pax_global_header00006660000000000000000000000064145043100430014504gustar00rootroot0000000000000052 comment=3be9b70ddc63ebcfdfc1d7afea48af3ee7ec03a4 syslog-ng-syslog-ng-4.4.0/000077500000000000000000000000001450431004300153535ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.astylerc000066400000000000000000000013261450431004300172040ustar00rootroot00000000000000# GNU style --style=gnu # convert tabs into spaces --convert-tabs # lines indented using 2 spaces --indent=spaces=2 # add spaces around commas --pad-comma # max line lenght is 120 chars --max-code-length=120 --max-instatement-indent=60 # pointer is aligned to the name of the variable --align-pointer=name # check files recursively in folder --recursive # do not create backups of formatted files --suffix=none # exclude folders && files # on Travis these submodules are not checked out when cheking the style --ignore-exclude-errors --exclude="lib/ivykis" --exclude="lib/compat/strcasestr.c" --exclude="dbld" # allow opening curly bracket in the same line as namespace e.g.: `namespace foobar {` --attach-namespaces syslog-ng-syslog-ng-4.4.0/.ctags000066400000000000000000000001421450431004300164520ustar00rootroot00000000000000--exclude=tags --exclude=.git --exclude=dbld/build --exclude=dbld/install --exclude=dbld/release syslog-ng-syslog-ng-4.4.0/.github/000077500000000000000000000000001450431004300167135ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001450431004300210765ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.github/ISSUE_TEMPLATE/10-bug-report.md000066400000000000000000000020051450431004300237210ustar00rootroot00000000000000--- name: Bug report about: Use this template for reporting a bug. title: '' labels: bug assignees: '' --- # syslog-ng ## Version of syslog-ng ## Platform ## Debug bundle # Issue ## Failure ## Steps to reproduce ## Configuration ## Input and output logs (if possible) syslog-ng-syslog-ng-4.4.0/.github/ISSUE_TEMPLATE/20-documentation-issue.md000066400000000000000000000010421450431004300256330ustar00rootroot00000000000000--- name: Documentation issue about: Use this template for reporting an issue in the documentation. title: '' labels: 'doc-bug' assignees: '' --- ## Documentation version ## Incorrect section ## Description of the problem ## Proposed solution syslog-ng-syslog-ng-4.4.0/.github/ISSUE_TEMPLATE/30-feature-request.md000066400000000000000000000010231450431004300247550ustar00rootroot00000000000000--- name: Feature request about: Use this template for raising a feature request. title: '' labels: 'enhancement' assignees: '' --- ## Description of the problem ## Proposed solution ## Alternatives ## Additional context syslog-ng-syslog-ng-4.4.0/.github/pull_request_template.md000066400000000000000000000011351450431004300236540ustar00rootroot00000000000000 syslog-ng-syslog-ng-4.4.0/.github/workflows/000077500000000000000000000000001450431004300207505ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.github/workflows/comment-on-version-bump-pr.yml000066400000000000000000000026501450431004300266150ustar00rootroot00000000000000########################################################################### # # If there are new commits on master, while we have a version bump PR open, # this job automatically comments on the PR, mentioning the new commits, # so we will not forget to follow-up the changes. # ########################################################################### name: Comment on version bump PR on: push: branches: - master jobs: comment-on-version-bump-pr: runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMIT_URL: https://github.com/${{ github.repository_owner }}/syslog-ng/commit/${{ github.sha }} steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Check if version bump PR is open run: | . .github/workflows/gh-tools.sh PR_NUMBER=$(hub pr list --state=open --format="%I %l%n" | grep "version-bump" | grep -Po "^[0-9]+") || true [ -z ${PR_NUMBER} ] && echo "No version bump PR is open. Skipping." gh_export PR_NUMBER - name: Comment if: env.PR_NUMBER != '' run: | COMMENT_ENDPOINT=repos/${{ github.repository_owner }}/syslog-ng/issues/${PR_NUMBER}/comments COMMENT="There are new commits (${COMMIT_URL}) on master. Please follow-up any necessary changes." hub api \ ${COMMENT_ENDPOINT} \ --field body="${COMMENT}" syslog-ng-syslog-ng-4.4.0/.github/workflows/create-packages.yml000066400000000000000000000045331450431004300245170ustar00rootroot00000000000000name: Create package from source tarball on: workflow_call: inputs: source-tarball-artifact-name: required: true type: string dbld-image-mode: required: true type: string # cache / build distros: required: false type: string default: '[ "debian-buster", "debian-testing", "debian-sid", "debian-bullseye", "debian-bookworm", "ubuntu-focal", "ubuntu-jammy", "ubuntu-lunar", "centos-7", "fedora-37" ]' jobs: create-packages: name: ${{ matrix.distro }} runs-on: ubuntu-latest strategy: matrix: distro: ${{ fromJson(inputs.distros) }} fail-fast: false steps: - name: Download source tarball artifact uses: actions/download-artifact@v3 with: name: ${{ inputs.source-tarball-artifact-name }} - name: Extract source tarball run: | mkdir syslog-ng tar --strip-components=1 -xvf syslog-ng*.tar.gz -C syslog-ng - name: Prepare docker image working-directory: syslog-ng run: | if [[ "${{ inputs.dbld-image-mode }}" = "build" ]] then ./dbld/rules image-${{ matrix.distro }} elif [[ "${{ inputs.dbld-image-mode }}" = "cache" ]] then ./dbld/rules cache-image-${{ matrix.distro }} else echo Unexpected input: dbld-image-mode=${{ inputs.dbld-image-mode }} false fi - name: Create package working-directory: syslog-ng run: | ./dbld/rules package-${{ matrix.distro }} - name: Prepare package for artifact # We want to keep the directory structure starting with ${{ matrix.distro }}, # but it can only be done, if we give its parent directory as `path` to upload-artifact. # There are other directories in dbld/build which we do not want to upload, # so let's make a temporary directory and move the ${{ matrix.distro }} directory there. run: | mkdir package cp -r syslog-ng/dbld/build/${{ matrix.distro }} package/ - name: Store package as artifact uses: actions/upload-artifact@v3 with: name: package-${{ matrix.distro }} path: package/* syslog-ng-syslog-ng-4.4.0/.github/workflows/dbld-images.yml000066400000000000000000000046131450431004300236470ustar00rootroot00000000000000name: Compile dbld-images on: pull_request: paths: - 'dbld/**' - 'packaging/rhel/**' - 'packaging/debian/**' - '.github/workflows/dbld-images.yml' push: paths: - 'dbld/**' - 'packaging/rhel/**' - 'packaging/debian/**' - '.github/workflows/dbld-images.yml' schedule: - cron: '00 22 * * *' workflow_dispatch: inputs: testing_image_upload: description: Should we upload the images into GitHub Packages? (true/false) required: false default: "false" jobs: build: runs-on: ubuntu-latest strategy: matrix: image: - centos-7 - fedora-37 - debian-bullseye - debian-bookworm - debian-buster - debian-sid - debian-testing - ubuntu-focal - ubuntu-jammy - ubuntu-lunar - devshell - kira - tarball fail-fast: false steps: - name: Checkout source code uses: actions/checkout@v3 - name: Set container registry run: | CONTAINER_REGISTRY="ghcr.io/${{ github.repository_owner }}" CONTAINER_REGISTRY="$(echo "$CONTAINER_REGISTRY" | tr '[:upper:]' '[:lower:]')" . .github/workflows/gh-tools.sh gh_export CONTAINER_REGISTRY - name: Build the images run: dbld/rules image-${{ matrix.image }} - name: Should we upload the images? run: | if [ "${{ github.event.inputs.testing_image_upload }}" = "true" ] || \ ( \ [ "${{ github.repository_owner }}" = "syslog-ng" ] && \ [ "${{ github.ref }}" = "refs/heads/master" ] && \ [[ "${{ github.event_name }}" =~ ^(push|workflow_dispatch|schedule)$ ]] \ ) then UPLOAD_IMAGES_INTERNAL="true" else UPLOAD_IMAGES_INTERNAL="false" fi . .github/workflows/gh-tools.sh gh_export UPLOAD_IMAGES_INTERNAL - name: Log in to the Container registry if: env.UPLOAD_IMAGES_INTERNAL == 'true' uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Push the images if: env.UPLOAD_IMAGES_INTERNAL == 'true' run: | dbld/rules push-image-${{ matrix.image }} syslog-ng-syslog-ng-4.4.0/.github/workflows/devshell.yml000066400000000000000000000210151450431004300233000ustar00rootroot00000000000000name: CI @ devshell on: pull_request: push: schedule: - cron: '00 21 * * *' jobs: general: runs-on: ubuntu-latest container: image: ghcr.io/syslog-ng/dbld-devshell:latest options: --privileged --ulimit core=-1 strategy: matrix: build-tool: [autotools, cmake] cc: [gcc, clang] fail-fast: false steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Setup Git safedir run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Setup environment run: | . .github/workflows/gh-tools.sh # Setup corefiles ulimit -c unlimited COREFILES_DIR=/tmp/corefiles mkdir ${COREFILES_DIR} echo "${COREFILES_DIR}/core.%h.%e.%t" > /proc/sys/kernel/core_pattern # Setup build time environment variables PYTHONUSERBASE="${HOME}/python_packages" CC="${{ matrix.cc }}" SYSLOG_NG_INSTALL_DIR=${HOME}/install/syslog-ng CONFIGURE_FLAGS=" --prefix=${SYSLOG_NG_INSTALL_DIR} --enable-debug --enable-all-modules --disable-java --disable-java-modules --enable-ebpf --with-python=3 `[ $CC = clang ] && echo '--enable-force-gnu99' || true` " CMAKE_FLAGS=" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS=-Werror -DCMAKE_INSTALL_PREFIX=${HOME}/install/syslog-ng -DPYTHON_VERSION=3 " gh_export COREFILES_DIR PYTHONUSERBASE CC SYSLOG_NG_INSTALL_DIR CONFIGURE_FLAGS CMAKE_FLAGS gh_path "${PYTHONUSERBASE}" - name: autogen.sh if: matrix.build-tool == 'autotools' run: ./autogen.sh - name: configure if: matrix.build-tool == 'autotools' run: | mkdir build cd build ../configure ${CONFIGURE_FLAGS} - name: cmake if: matrix.build-tool == 'cmake' run: | mkdir build cd build cmake ${CMAKE_FLAGS} .. - name: make working-directory: ./build run: make V=1 -j $(nproc) - name: make check id: make_check working-directory: ./build run: make V=1 check || (mkdir -p ${COREFILES_DIR} && find . -executable -a -type f | tar -cf ${COREFILES_DIR}/test-binaries.tar --files-from=- && cat test-suite.log && false) - name: make install working-directory: ./build run: make install - name: Python virtualenv for syslog-ng runtime run: ${SYSLOG_NG_INSTALL_DIR}/bin/syslog-ng-update-virtualenv -y - name: Light id: light working-directory: ./build run: | make light-self-check make light-check - name: make func-test working-directory: ./build run: make VERBOSE=1 func-test - name: "Artifact: test-suite.log" uses: actions/upload-artifact@v3 if: always() && steps.make_check.outcome == 'failure' with: name: test-suite-${{ matrix.build-tool }}-${{ matrix.cc }} path: ${{ github.workspace }}/build/test-suite.log - name: "Prepare artifact: light-reports" id: prepare-light-reports if: always() && steps.light.outcome == 'failure' run: | if [ ${{ matrix.build-tool }} = 'autotools' ] then REPORTS_DIR=build/reports elif [ ${{ matrix.build-tool }} = 'cmake' ] then REPORTS_DIR=build/tests/light/reports else echo Unrecognized build tool: ${{ matrix.build-tool }}. exit 1 fi cp -r ${REPORTS_DIR} /tmp/light-reports rm -f `find /tmp/light-reports -type p,s` - name: "Artifact: light-reports" uses: actions/upload-artifact@v3 if: always() && steps.prepare-light-reports.outcome == 'success' with: name: light-reports-${{ matrix.build-tool }}-${{ matrix.cc }} path: /tmp/light-reports - name: Dump corefile backtrace working-directory: ${{ env.COREFILES_DIR }} if: failure() run: | find -name "core.*syslog-ng*" -exec \ gdb --ex="thread apply all bt full" --ex="quit" ${SYSLOG_NG_INSTALL_DIR}/sbin/syslog-ng --core {} \; - name: "Artifact: corefiles" uses: actions/upload-artifact@v3 if: failure() with: name: corefiles-${{ matrix.build-tool }}-${{ matrix.cc }} path: ${{ env.COREFILES_DIR }} distcheck: runs-on: ubuntu-latest container: image: ghcr.io/syslog-ng/dbld-devshell:latest options: --security-opt seccomp=unconfined --ulimit core=-1 steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Setup Git safedir run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Set ENV variables run: | . .github/workflows/gh-tools.sh DISTCHECK_CONFIGURE_FLAGS=" CFLAGS=-Werror CXXFLAGS=-Werror --prefix=${HOME}/install/syslog-ng --with-ivykis=internal --with-jsonc=system --enable-tcp-wrapper --enable-linux-caps --enable-manpages --enable-all-modules --disable-java --disable-java-modules --with-python=3 " gh_export DISTCHECK_CONFIGURE_FLAGS - name: autogen.sh run: ./autogen.sh - name: configure run: ./configure --disable-all-modules --enable-manpages - name: distcheck run: | . tests/build-log-cflags-propagation.sh exec_prop_check "make distcheck -j 3 V=1" style-check: runs-on: ubuntu-latest container: image: ghcr.io/syslog-ng/dbld-devshell:latest steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Setup Git safedir run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Prepare run: | ./autogen.sh mkdir build && cd build ../configure - name: Style check (C) id: c-style-check run: | scripts/style-checker.sh format git diff --exit-code > c-style-problems.diff || \ (cat c-style-problems.diff && git reset --hard HEAD && exit 1) - name: Style check (pylib) if: always() working-directory: ./build run: | make pymodules-linters || (git reset --hard HEAD && exit 1) - name: Style check (Light) id: light-style-check if: always() working-directory: ./build shell: bash run: | make light-linters || \ (git diff > ../light-style-problems.diff ; git reset --hard HEAD && exit 1) - name: "Artifact: c-style-problems" uses: actions/upload-artifact@v3 if: always() && steps.c-style-check.outcome == 'failure' with: name: c-style-problems path: c-style-problems.diff - name: "Artifact: light-style-problems" uses: actions/upload-artifact@v3 if: always() && steps.light-style-check.outcome == 'failure' with: name: light-style-problems path: light-style-problems.diff copyright-check: runs-on: ubuntu-latest container: image: ghcr.io/syslog-ng/dbld-devshell:latest env: COPYRIGHTVERBOSITY: 1 steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Setup Git safedir run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Copyright check run: tests/copyright/check.sh . . - name: "Artifact: copyright-run.log" uses: actions/upload-artifact@v3 if: failure() with: name: copyright-run.log path: copyright-run.log commits-check: runs-on: ubuntu-latest container: image: ghcr.io/syslog-ng/dbld-devshell:latest steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 with: fetch-depth: 0 - name: Setup Git safedir run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" - name: Commits check (Pull request) if: github.event_name == 'pull_request' run: tests/commits/check.sh origin/${{ github.base_ref }}..HEAD - name: Commits check (Push) if: github.event_name == 'push' run: tests/commits/check.sh syslog-ng-syslog-ng-4.4.0/.github/workflows/draft-release.yml000066400000000000000000000105611450431004300242140ustar00rootroot00000000000000########################################################################################################### # # This workflow creates a draft release into GitHub's releases section. # # It is automatically started, when a "Version: x.y.z" PR is merged. # Its progress is commented at the "Version: x.y.z" PR. # # The workflow can also be started manually, if necessary. # # When the workflow is finished, one must visit https://github.com/syslog-ng/syslog-ng/releases, # double check the generated draft release, and manually release it. # ########################################################################################################### name: Draft release on: workflow_dispatch: pull_request: types: [closed] env: GITHUB_TOKEN: ${{ secrets.PAT_FOR_ACTIONS }} WORKFLOW_NAME: "**Draft release** workflow" CURRENT_WORKFLOW_RUN_URL: https://github.com/${{ github.repository_owner }}/syslog-ng/actions/runs/${{ github.run_id }} COMMENT_ENDPOINT: repos/${{ github.repository_owner }}/syslog-ng/issues/${{ github.event.number }}/comments RELEASES_URL: https://github.com/${{ github.repository_owner }}/syslog-ng/releases jobs: create-release-tarball: runs-on: ubuntu-latest if: (github.event_name == 'workflow_dispatch') || (github.event.pull_request.merged && contains(github.event.pull_request.labels.*.name, 'version-bump')) outputs: RELEASE_TAG: ${{ steps.setup-environment.outputs.RELEASE_TAG }} RELEASE_NAME: ${{ steps.setup-environment.outputs.RELEASE_NAME }} TARBALL_NAME: ${{ steps.setup-environment.outputs.TARBALL_NAME }} steps: - name: "Comment: job started" if: github.event_name == 'pull_request' run: | COMMENT="${WORKFLOW_NAME} started: ${CURRENT_WORKFLOW_RUN_URL}." hub api \ ${COMMENT_ENDPOINT} \ --field body="${COMMENT}" - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Setup environment id: setup-environment run: | . .github/workflows/gh-tools.sh VERSION=`cat VERSION` RELEASE_TAG=syslog-ng-$VERSION RELEASE_NAME=${RELEASE_TAG} TARBALL_NAME=${RELEASE_NAME}.tar.gz TARBALL_PATH=dbld/release/${VERSION}/${TARBALL_NAME} gh_export VERSION RELEASE_TAG TARBALL_PATH gh_output RELEASE_TAG RELEASE_NAME TARBALL_NAME - name: "DBLD: release" run: | ./dbld/rules release VERSION=${VERSION} - name: Store release tarball as artifact uses: actions/upload-artifact@v3 with: name: release-tarball path: ${{ env.TARBALL_PATH }} if-no-files-found: error create-packages: needs: create-release-tarball uses: ./.github/workflows/create-packages.yml with: source-tarball-artifact-name: release-tarball dbld-image-mode: build upload-packages: needs: create-packages uses: ./.github/workflows/upload-packages.yml with: pkg-type: stable secrets: azure-sas-token: ${{ secrets.AZURE_SAS_TOKEN }} create-draft-release: runs-on: ubuntu-latest needs: [create-release-tarball, upload-packages] steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Download release tarball artifact uses: actions/download-artifact@v3 with: name: release-tarball - name: Create draft release run: | sed "1 i${{ needs.create-release-tarball.outputs.RELEASE_NAME }}\n" NEWS.md > /tmp/message hub release create \ --draft \ --file /tmp/message \ --attach ${{ needs.create-release-tarball.outputs.TARBALL_NAME }} \ ${{ needs.create-release-tarball.outputs.RELEASE_TAG }} comment-workflow-result: runs-on: ubuntu-latest needs: create-draft-release if: always() && (github.event.pull_request.merged && contains(github.event.pull_request.labels.*.name, 'version-bump')) steps: - name: "Comment: job status" run: | if [[ "${{ needs.create-draft-release.result }}" = "success" ]] then COMMENT="${WORKFLOW_NAME} finished successfully. Please check the Releases page: ${RELEASES_URL}" else COMMENT="${WORKFLOW_NAME} failed." fi hub api \ ${COMMENT_ENDPOINT} \ --field body="${COMMENT}" syslog-ng-syslog-ng-4.4.0/.github/workflows/gh-tools.sh000066400000000000000000000005601450431004300230410ustar00rootroot00000000000000gh_export() { while [ "x$1" != "x" ]; do echo "$1<<__EOF__" >> $GITHUB_ENV eval echo \$$1 >> $GITHUB_ENV echo "__EOF__" >> $GITHUB_ENV shift; done } gh_path() { echo "$1" >> $GITHUB_PATH } gh_output() { while [ "x$1" != "x" ]; do echo "$1=$(eval echo \$$1)" >> $GITHUB_OUTPUT shift; done } syslog-ng-syslog-ng-4.4.0/.github/workflows/index-packages.yml000066400000000000000000000044401450431004300243600ustar00rootroot00000000000000name: Index packages in Azure/incoming on: workflow_call: inputs: pkg-type: required: true type: string # stable / nightly run-id: required: false type: string secrets: config-base64: required: true gpg-key-base64: required: true gpg-key-passphrase: required: true defaults: run: working-directory: packaging/package-indexer jobs: index-packages: name: ${{ inputs.pkg-type }} runs-on: ubuntu-latest env: DOCKER_IMAGE: package-indexer DOCKER_CONTAINER_NAME: package_indexer_container VERBOSE_LOG_PATH: index-packages-verbose.log GPG_KEY_PATH: syslog_ng_ose_signing_key.sub.priv.asc if: github.repository_owner == 'syslog-ng' steps: - name: Checkout source code uses: actions/checkout@v3 - name: Prepare environment run: | . "${GITHUB_WORKSPACE}/.github/workflows/gh-tools.sh" if [[ -n "${{ inputs.run-id }}" ]]; then RUN_ID="${{ inputs.run-id }}" else RUN_ID="${{ github.run_id }}" fi gh_export RUN_ID echo "${{ secrets.gpg-key-base64 }}" | base64 --decode > "${GPG_KEY_PATH}" - name: Build docker image run: | docker build -t "${DOCKER_IMAGE}" . - name: Start docker container run: | docker run -v "${PWD}:${PWD}" -w "${PWD}" --detach --name "${DOCKER_CONTAINER_NAME}" -t "${DOCKER_IMAGE}" - name: Index packages run: | echo "${{ secrets.gpg-key-passphrase }}" | \ docker exec \ --interactive \ ${DOCKER_CONTAINER_NAME} \ ./index-packages.py \ --suite "${{ inputs.pkg-type }}" \ --config-content "$(echo '${{ secrets.config-base64 }}' | base64 --decode)" \ --run-id "${RUN_ID}" \ --gpg-key-passphrase-from-stdin \ --log-file "${VERBOSE_LOG_PATH}" - name: Cleanup if: always() run: rm -f "${GPG_KEY_PATH}" - name: "Artifact: verbose run log" uses: actions/upload-artifact@v3 if: always() with: name: ${{ env.VERBOSE_LOG_PATH }} path: packaging/package-indexer/${{ env.VERBOSE_LOG_PATH }} syslog-ng-syslog-ng-4.4.0/.github/workflows/macos.yml000066400000000000000000000117661450431004300226100ustar00rootroot00000000000000name: macOS on: pull_request: push: schedule: - cron: '00 21 * * *' jobs: general: runs-on: macOS-latest strategy: matrix: build-tool: [autotools, cmake] cc: [gcc, clang] fail-fast: false steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Unlinking preinstalled Python (workaround) # The python@3 brew package has to be installed and linked system-wide (it's a dependency of glib and syslog-ng) # The macos-latest GitHub runner has Python preinstalled as a pkg, this prevents linking the python@3 # brew package, even when linking is forced. `brew "python@3", link: true, force: true` # also, brew cannot update the links even these cretated by itself for an earlier python version run : | find /usr/local/bin/ -lname "*Python.framework*" -delete - name: Install dependencies run: | brew update --preinstall brew bundle --file=contrib/Brewfile - name: Set ENV variables run: | . .github/workflows/gh-tools.sh HOMEBREW_PREFIX="$(brew --prefix)" PYTHONUSERBASE="${HOME}/python_packages" PKG_CONFIG_PATH="${HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig:${HOMEBREW_PREFIX}/opt/net-snmp/lib/pkgconfig:${PKG_CONFIG_PATH}" CFLAGS="-I${HOMEBREW_PREFIX}/include/" LDFLAGS="-L${HOMEBREW_PREFIX}/lib" CC="${{ matrix.cc }}" THREADS="$(sysctl -n hw.physicalcpu)" CONFIGURE_FLAGS=" `[ $CC = clang ] && echo '--enable-force-gnu99' || true` `[ $CC = gcc ] && echo '--enable-cpp' || true` --prefix=${SYSLOG_NG_INSTALL_DIR} --enable-all-modules --enable-tests --with-ivykis=system --with-python=3 --disable-smtp --disable-grpc --disable-java --disable-java-modules --disable-mqtt --disable-pacct " CMAKE_CONFIGURE_FLAGS=" `[ $CC = gcc ] && echo '-DENABLE_CPP=ON' || true` -DCMAKE_BUILD_TYPE=Debug -DSUMMARY_VERBOSE=ON -DBUILD_TESTING=ON -DIVYKIS_SOURCE=system -DPYTHON_VERSION=3 -DENABLE_AFSMTP=OFF -DENABLE_GRPC=OFF -DENABLE_JAVA=OFF -DENABLE_JAVA_MODULES=OFF -DENABLE_MQTT=OFF -DENABLE_PACCT=OFF " gh_export HOMEBREW_PREFIX PYTHONUSERBASE CC PKG_CONFIG_PATH THREADS CONFIGURE_FLAGS CFLAGS LDFLAGS CMAKE_CONFIGURE_FLAGS gh_path "${HOMEBREW_PREFIX}/bin:${HOMEBREW_PREFIX}/opt/bison/bin:${HOMEBREW_PREFIX}/opt/libnet/bin:${PYTHONUSERBASE}/bin:${HOMEBREW_PREFIX}/opt/net-snmp/bin:${PATH}" ln -s "${HOMEBREW_PREFIX}/bin/gcc-11" "${HOMEBREW_PREFIX}/bin/gcc" ln -s "${HOMEBREW_PREFIX}/bin/g++-11" "${HOMEBREW_PREFIX}/bin/g++" - name: autogen.sh if: matrix.build-tool == 'autotools' run: | ./autogen.sh - name: configure if: matrix.build-tool == 'autotools' run: | ./configure ${CONFIGURE_FLAGS} - name: cmake configure if: matrix.build-tool == 'cmake' run: | mkdir build # If you know the valid syntax to provide the quoted string for -DCMAKE_C_FLAGS inplace in CMAKE_CONFIGURE_FLAGS above (in Set ENV variables step) instead of this hack, please contribute! # # TODO: -Wall must be replaced here with -Werror but now multiple warnings could occure in several modules that needs to be corrected first # cmake --install-prefix "${HOME}/install/syslog-ng" -B build . -DCMAKE_C_FLAGS="-Wall ${CFLAGS}" ${CMAKE_CONFIGURE_FLAGS} - name: cmake install if: matrix.build-tool == 'cmake' run: | cmake --build ./build -j ${THREADS} --target install - name: cmake check if: matrix.build-tool == 'cmake' run: | # FIXME: Should fix these tests first, latest result is # 98% tests passed, 4 tests failed out of 194 # that is strange as in the autotools case 199 out of 199(!) is passed #cmake --build ./build -j ${THREADS} --target check true - name: make if: matrix.build-tool == 'autotools' run: | set -e make --keep-going -j ${THREADS} || \ { \ S=$?; \ make V=1; \ return $S; \ } - name: make check if: matrix.build-tool == 'autotools' run: | set -e make --keep-going check -j ${THREADS} || \ { \ S=$?; \ echo "Output of first test invocation:"; \ find . -name test-suite.log | xargs cat; \ make V=1 check; \ echo "Output of second test invocation:"; \ find . -name test-suite.log | xargs cat; \ return $S; \ } syslog-ng-syslog-ng-4.4.0/.github/workflows/nightly-release.yml000066400000000000000000000033161450431004300245720ustar00rootroot00000000000000name: Nightly release on: workflow_dispatch: schedule: - cron: '00 23 * * *' jobs: create-source-tarball: runs-on: ubuntu-latest steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 with: fetch-depth: 0 - name: Prepare docker image run: ./dbld/rules cache-image-tarball - name: Create source tarball run: ./dbld/rules pkg-tarball - name: Store source tarball as artifact uses: actions/upload-artifact@v3 with: name: source-tarball path: dbld/build/*.tar.gz create-packages: needs: create-source-tarball uses: ./.github/workflows/create-packages.yml with: source-tarball-artifact-name: source-tarball dbld-image-mode: cache upload-packages: needs: create-packages uses: ./.github/workflows/upload-packages.yml with: pkg-type: nightly secrets: azure-sas-token: ${{ secrets.AZURE_SAS_TOKEN }} index-packages: needs: upload-packages uses: ./.github/workflows/index-packages.yml with: pkg-type: nightly secrets: config-base64: ${{ secrets.PACKAGE_INDEXER_CONFIG_BASE64 }} gpg-key-base64: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_BASE64 }} gpg-key-passphrase: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_PASSPHRASE }} test-packages: needs: index-packages uses: ./.github/workflows/test-apt-packages.yml with: pkg-type: nightly publish-docker-image: needs: test-packages uses: ./.github/workflows/publish-docker-image.yml with: pkg-type: nightly secrets: dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }} dockerhub-password: ${{ secrets.DOCKERHUB_PASSWORD }} syslog-ng-syslog-ng-4.4.0/.github/workflows/package-indexer-checks.yml000066400000000000000000000022041450431004300257560ustar00rootroot00000000000000name: Package indexer checks on: pull_request: paths: - "packaging/package-indexer/**" - ".github/workflows/package-indexer-checks.yml" push: paths: - "packaging/package-indexer/**" - ".github/workflows/package-indexer-checks.yml" defaults: run: working-directory: packaging/package-indexer jobs: package-indexer-checks: runs-on: ubuntu-latest env: DOCKER_IMAGE: package-indexer DOCKER_CONTAINER_NAME: package_indexer_container steps: - name: Checkout source code uses: actions/checkout@v3 - name: Build docker image run: | docker build -t ${DOCKER_IMAGE} . - name: Start docker container run: | docker run -v $PWD:$PWD -w $PWD --detach --name ${DOCKER_CONTAINER_NAME} -t ${DOCKER_IMAGE} - name: style-check run: | docker exec ${DOCKER_CONTAINER_NAME} pip install black docker exec ${DOCKER_CONTAINER_NAME} black --check --diff . - name: linter run: | docker exec ${DOCKER_CONTAINER_NAME} pip install mypy docker exec ${DOCKER_CONTAINER_NAME} mypy . syslog-ng-syslog-ng-4.4.0/.github/workflows/packages.yml000066400000000000000000000016111450431004300232500ustar00rootroot00000000000000name: Packages (PR / push) on: pull_request: push: jobs: create-source-tarball: runs-on: ubuntu-latest steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 with: fetch-depth: 0 - name: Prepare docker image run: ./dbld/rules cache-image-tarball - name: Create source tarball run: ./dbld/rules pkg-tarball - name: Store source tarball as artifact uses: actions/upload-artifact@v3 with: name: source-tarball path: dbld/build/*.tar.gz create-packages: needs: create-source-tarball uses: ./.github/workflows/create-packages.yml with: source-tarball-artifact-name: source-tarball dbld-image-mode: cache distros: '[ "centos-7", "debian-bookworm", "debian-testing", "fedora-37", "ubuntu-jammy" ]' syslog-ng-syslog-ng-4.4.0/.github/workflows/publish-docker-image.yml000066400000000000000000000033501450431004300254670ustar00rootroot00000000000000name: Publish Docker image on: workflow_call: inputs: pkg-type: required: true type: string # stable / nightly secrets: dockerhub-username: required: true dockerhub-password: required: true env: DOCKER_IMAGE_NAME: balabit/syslog-ng jobs: publish-docker-image: name: Publish syslog-ng Docker image if: github.repository_owner == 'syslog-ng' runs-on: ubuntu-latest steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 - name: Log in to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.dockerhub-username }} password: ${{ secrets.dockerhub-password }} - name: Extract metadata (syslog-ng version) for Docker if: inputs.pkg-type == 'stable' id: stable-tags uses: docker/metadata-action@v3 with: images: ${{ env.DOCKER_IMAGE_NAME }} tags: type=match,pattern=syslog-ng-(.*),group=1 sep-tags: ',' - name: Compose Docker image tags id: tags run: | if [[ '${{ inputs.pkg-type }}' = 'stable' ]]; then TAGS='${{ steps.stable-tags.outputs.tags }}' elif [[ '${{ inputs.pkg-type }}' = 'nightly' ]]; then TAGS="${DOCKER_IMAGE_NAME}:nightly" else echo Unexpected input: pkg-type=${{ inputs.pkg-type }} false fi . .github/workflows/gh-tools.sh gh_output TAGS - name: Build and push Docker image uses: docker/build-push-action@v2 with: context: docker/ push: true tags: ${{ steps.tags.outputs.TAGS }} build-args: PKG_TYPE=${{ inputs.pkg-type }} syslog-ng-syslog-ng-4.4.0/.github/workflows/stable-release.yml000066400000000000000000000045721450431004300243730ustar00rootroot00000000000000# Please note that the syslog-ng git repository is not available in this workflow. # It means that certain convenience/helper functions are not available (e.g. gh_output). # This is intentional as syslog-ng will be acquired from the tarball. name: Stable release on: workflow_dispatch: push: tags: - 'syslog-ng-*' jobs: pre-check: runs-on: ubuntu-latest if: github.repository_owner == 'syslog-ng' steps: - name: Validate tag run: | if [[ "${{ github.ref }}" != refs/tags/syslog-ng-* ]]; then echo "Please start the workflow on a 'syslog-ng-*' tag" false fi find-draft-release-run: needs: pre-check runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} outputs: DRAFT_RELEASE_RUN_ID: ${{ steps.find-and-export-run-id.outputs.DRAFT_RELEASE_RUN_ID }} steps: - name: Find and export run-id id: find-and-export-run-id run: | DRAFT_RELEASE_RUN_ID=$(gh run list \ --repo "${{ github.repository_owner }}/syslog-ng" \ --workflow "Draft release" \ --json "status,conclusion,updatedAt,databaseId" \ --jq '[ .[] | select(.status=="completed") | select(.conclusion=="success") ] | max_by(.updatedAt) | .databaseId') if [[ -z "${DRAFT_RELEASE_RUN_ID}" ]]; then echo "Failed to find the run-id of the last successful 'Draft release' workflow run." false fi echo "DRAFT_RELEASE_RUN_ID=${DRAFT_RELEASE_RUN_ID}" >> $GITHUB_OUTPUT index-packages: needs: find-draft-release-run uses: ./.github/workflows/index-packages.yml with: pkg-type: stable run-id: ${{ needs.find-draft-release-run.outputs.DRAFT_RELEASE_RUN_ID }} secrets: config-base64: ${{ secrets.PACKAGE_INDEXER_CONFIG_BASE64 }} gpg-key-base64: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_BASE64 }} gpg-key-passphrase: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_PASSPHRASE }} test-packages: needs: index-packages uses: ./.github/workflows/test-apt-packages.yml with: pkg-type: stable publish-docker-image: needs: test-packages uses: ./.github/workflows/publish-docker-image.yml with: pkg-type: stable secrets: dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }} dockerhub-password: ${{ secrets.DOCKERHUB_PASSWORD }} syslog-ng-syslog-ng-4.4.0/.github/workflows/test-apt-packages.yml000066400000000000000000000072161450431004300250160ustar00rootroot00000000000000# Please note that the syslog-ng git repository is not available in this workflow. # It means that certain convenience/helper functions are not available (e.g. gh_output). # This is intentional as syslog-ng will be acquired from the APT repository. name: Run smoke tests on APT packages on: workflow_call: inputs: pkg-type: required: true type: string jobs: TestPackagesWith: strategy: matrix: distro: - "debian:buster" - "debian:bullseye" - "debian:bookworm" - "debian:testing" - "debian:sid" - "ubuntu:focal" - "ubuntu:jammy" - "ubuntu:lunar" upgrade-from: - "debian-official" - "syslog-ng-last" exclude: # The official syslog-ng got removed from debian:testing because of pcre: # https://tracker.debian.org/news/1445295/syslog-ng-removed-from-testing/ - distro: "debian:testing" upgrade-from: "debian-official" fail-fast: false runs-on: ubuntu-latest container: ${{ matrix.distro }} steps: - name: Install prerequisites for adding 3rd party repository run: | apt-get update -qq apt-get install --yes wget gnupg2 ca-certificates apt-transport-https - name: Install the Debian official syslog-ng OSE package if: matrix.upgrade-from == 'debian-official' run: | DEBIAN_FRONTEND=noninteractive apt-get install --yes syslog-ng - name: Add OSE repository run: | wget -qO - https://ose-repo.syslog-ng.com/apt/syslog-ng-ose-pub.asc | gpg --dearmor > /usr/share/keyrings/ose-repo-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/ose-repo-archive-keyring.gpg] https://ose-repo.syslog-ng.com/apt/ ${{ inputs.pkg-type }} $(echo ${{ matrix.distro }} | sed 's/:/-/g')" | tee --append /etc/apt/sources.list.d/syslog-ng-ose.list apt-get update -qq - name: Install the last but one syslog-ng OSE package if: matrix.upgrade-from == 'syslog-ng-last' run: | DEBIAN_FRONTEND=noninteractive apt-get install --yes syslog-ng=$(apt-cache madison syslog-ng | sed -n 2p | awk -F"|" '{print $2}' | sed 's/ //g') - name: Upgrade to the latest syslog-ng OSE package run: | DEBIAN_FRONTEND=noninteractive apt-get install --yes syslog-ng - name: Get syslog-ng revision run: | syslog-ng -V echo "REVISION=$(syslog-ng -V | grep Revision | cut -d" " -f2)" >> $GITHUB_OUTPUT id: syslog_ng_revision - name: Check revision run: | if [ "${{ inputs.pkg-type }}" = "nightly" ]; then echo "${{ steps.syslog_ng_revision.outputs.REVISION }}" | egrep "^[0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}(\.[0-9]{1,3}\.[a-z0-9]{8})?-snapshot\+[0-9]{8}T[0-9]{6}$" elif [ "${{ inputs.pkg-type }}" = "stable" ]; then echo "${{ steps.syslog_ng_revision.outputs.REVISION }}" | egrep "^[0-9]{1}\.[0-9]{1,2}\.[0-9]{1,2}-[0-9]{1,2}$" fi - name: Check if installed package version matches with install revision run: | echo "Installed revision value: ${{ steps.syslog_ng_revision.outputs.REVISION }}" dpkg-query --show syslog-ng\* dpkg-query -f='${db:Status-Status}\t${package}\t${version}\t\n' --show syslog-ng\* | grep ^installed | while read installed_syslog_ng_package ; do echo $installed_syslog_ng_package | grep ${{ steps.syslog_ng_revision.outputs.REVISION }} ; done - name: Check if syslog-ng can start with default config run: | nohup syslog-ng -Fe & sleep 5 syslog-ng-ctl stop syslog-ng-syslog-ng-4.4.0/.github/workflows/trigger-index-packages.yml000066400000000000000000000011631450431004300260200ustar00rootroot00000000000000name: Trigger index-packages on: workflow_dispatch: inputs: pkg-type: required: true type: choice options: - nightly - stable run-id: required: true jobs: index-packages: uses: ./.github/workflows/index-packages.yml with: pkg-type: ${{ github.event.inputs.pkg-type }} run-id: ${{ github.event.inputs.run-id }} secrets: config-base64: ${{ secrets.PACKAGE_INDEXER_CONFIG_BASE64 }} gpg-key-base64: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_BASE64 }} gpg-key-passphrase: ${{ secrets.PACKAGE_INDEXER_GPG_KEY_PASSPHRASE }} syslog-ng-syslog-ng-4.4.0/.github/workflows/trigger-publish-docker-image.yml000066400000000000000000000010621450431004300271260ustar00rootroot00000000000000name: Trigger Publish Docker image on: workflow_call: jobs: pre-check: runs-on: ubuntu-latest steps: - name: Validate tag run: | if [[ "${{ github.ref }}" != refs/tags/syslog-ng-* ]]; then echo "Please start the workflow on a 'syslog-ng-*' tag" false fi publish-docker-image: needs: pre-check uses: ./.github/workflows/publish-docker-image.yml secrets: dockerhub-username: ${{ secrets.DOCKERHUB_USERNAME }} dockerhub-password: ${{ secrets.DOCKERHUB_PASSWORD }} syslog-ng-syslog-ng-4.4.0/.github/workflows/trigger-tests-on-packages.yml000066400000000000000000000005131450431004300264630ustar00rootroot00000000000000name: Trigger tests for APT packages on: workflow_dispatch: inputs: pkg-type: required: true type: choice options: - nightly - stable jobs: test-packages: uses: ./.github/workflows/test-apt-packages.yml with: pkg-type: ${{ github.event.inputs.pkg-type }} syslog-ng-syslog-ng-4.4.0/.github/workflows/upload-packages.yml000066400000000000000000000031521450431004300245340ustar00rootroot00000000000000name: Upload package to Azure/incoming on: workflow_call: inputs: pkg-type: required: true type: string # stable / nightly distros: required: false type: string default: '[ "debian-buster", "debian-testing", "debian-sid", "debian-bullseye", "debian-bookworm", "ubuntu-focal", "ubuntu-jammy", "ubuntu-lunar" ]' secrets: azure-sas-token: required: true jobs: upload-packages: name: ${{ matrix.distro }} runs-on: ubuntu-latest if: github.repository_owner == 'syslog-ng' strategy: matrix: distro: ${{ fromJson(inputs.distros) }} fail-fast: false steps: - name: Download package artifact uses: actions/download-artifact@v3 with: name: package-${{ matrix.distro }} path: package - name: Calculate Azure path run: | if [[ ! "${{ inputs.pkg-type }}" =~ ^(stable|nightly)$ ]]; then echo Unexpected input: pkg-type=${{ inputs.pkg-type }} false fi AZURE_PATH="incoming/${{ inputs.pkg-type }}/${{ github.run_id }}" echo "AZURE_PATH=${AZURE_PATH}" >> ${GITHUB_ENV} - name: Upload packages to Azure incoming uses: azure/CLI@v1 with: inlineScript: | az storage blob upload-batch \ --sas-token '${{ secrets.azure-sas-token }}' \ --account-name 'syslogngose' \ --source 'package' \ --destination '${{ env.AZURE_PATH }}' syslog-ng-syslog-ng-4.4.0/.github/workflows/version-bump.yml000066400000000000000000000066161450431004300241320ustar00rootroot00000000000000########################################################################################################### # # This job creates a version bump branch based on master, and opens a PR from it. # # The branch will have the version bumped in all necessary parts of the code, # and it will generate the NEWS.md content from the NEWS snippets. # # Organization members have the chance to add or modify the commits on the branch, if necessary. # # The job will also generate a tarball, and reference it in the PR's description. # # The job cannot be started, if there is an open PR with the version given. # # Manual steps: # 1. Navigate to https://github.com/syslog-ng/syslog-ng/actions. # 2. Choose the "Version bump" job. # 3. Click "Run workflow". # 4. Fill the new release version, and click "Run workflow". # 5. When the PR is opened, double check the changes, if necessary, add commits. # 6. When the PR is merged, the "Draft release" job will automatically start. # ########################################################################################################### name: Version bump on: workflow_dispatch: inputs: release_version: description: 'VERSION (..)' required: true jobs: version-bump: runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{ secrets.PAT_FOR_ACTIONS }} RELEASE_VERSION: ${{ github.event.inputs.release_version }} VERSION_BUMP_BRANCH: version/${{ github.event.inputs.release_version }} CURRENT_RUN_URL: https://github.com/${{ github.repository_owner }}/syslog-ng/actions/runs/${{ github.run_id }} steps: - name: Checkout syslog-ng source uses: actions/checkout@v3 with: fetch-depth: 0 - name: Check existing PR run: | EXISTS=$(hub pr list --state=open --head=${VERSION_BUMP_BRANCH} | wc -l) if [ ${EXISTS} -ne 0 ] then echo "There is a PR already open for this version. Please close it before running this job." exit 1 fi - name: Configure git user run: | git config user.name "github-actions" git config user.email "41898282+github-actions@users.noreply.github.com" - name: Create git branch run: | git switch -c ${VERSION_BUMP_BRANCH} - name: "DBLD: prepare-release" run: | ./dbld/rules prepare-release VERSION=${RELEASE_VERSION} git commit -a -s -m "version: bumped to ${RELEASE_VERSION}" - name: Generate NEWS.md run: | ./news/create-newsfile.py git diff-index --quiet HEAD NEWS.md || git commit -a -s -m "NEWS: generate for ${RELEASE_VERSION}" - name: "DBLD: release" run: | ./dbld/rules release VERSION=${RELEASE_VERSION} - name: Upload tarball uses: actions/upload-artifact@v3 with: name: syslog-ng-${{ env.RELEASE_VERSION }} path: dbld/release/${{ env.RELEASE_VERSION }}/syslog-ng-${{ env.RELEASE_VERSION }}.tar.gz - name: Open Pull Request run: | TITLE="Version: ${RELEASE_VERSION}" DESCRIPTION="Tarball is available at: ${CURRENT_RUN_URL}" echo -e "${TITLE}\n\n${DESCRIPTION}" > /tmp/message git push --force origin ${VERSION_BUMP_BRANCH} hub pull-request \ --base ${GITHUB_REF} \ --file /tmp/message \ --labels "version-bump" syslog-ng-syslog-ng-4.4.0/.gitignore000066400000000000000000000012031450431004300173370ustar00rootroot00000000000000{arch} .arch-ids .arch-inventory .gitcommit.txt autom4te.cache *~ Makefile.in aclocal.m4 config.h.in configure configure.gnu depcomp install-sh missing mkinstalldirs cscope.out ._* config.guess config.sub config.cache stamp-h.in stamp-h ylwrap .*.swp *.pyc ltmain.sh .project .cproject .settings Debug m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/pkg.m4 m4/ax*.m4 /compile .deps /lib/cfg-grammar.h /test-driver dbld/rules.conf dbld/extra-files/ debian/build-tree/ debian/*.log debian/autoreconf.* build/ tests/light/reports tags TAGS GPATH GRTAGS GTAGS modules/python-modules/syslogng.egg-info aclocal.m4-e syslog-ng-syslog-ng-4.4.0/.gitmodules000066400000000000000000000005001450431004300175230ustar00rootroot00000000000000[submodule "lib/ivykis"] path = lib/ivykis url = https://github.com/bazsi/ivykis.git ignore = dirty branch = iv-work-pool-support-for-slave-work-items [submodule "modules/grpc/otel/opentelemetry-proto"] path = modules/grpc/protos/opentelemetry-proto url = https://github.com/open-telemetry/opentelemetry-proto.git syslog-ng-syslog-ng-4.4.0/.lgtm.yml000066400000000000000000000013561450431004300171240ustar00rootroot00000000000000# Disable LGTM's built-in query to detect unsafe uses of gmtime; there's a # custom query to check for that queries: - exclude: cpp/potentially-dangerous-function extraction: cpp: prepare: packages: - autoconf-archive - openjdk-8-jdk-headless after_prepare: - export PATH=/usr/lib/jvm/java-8-openjdk-amd64/bin/:$PATH - export LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server:$LD_LIBRARY_PATH - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 - cd /tmp && wget https://ftp.gnu.org/gnu/bison/bison-3.7.6.tar.gz && tar -xzf bison-3.7.6.tar.gz - cd /tmp/bison-3.7.6 && ./configure --prefix=/tmp/bison && make all install - export PATH=/tmp/bison/bin/:$PATH syslog-ng-syslog-ng-4.4.0/.lgtm/000077500000000000000000000000001450431004300163745ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.lgtm/cpp-queries/000077500000000000000000000000001450431004300206315ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/.lgtm/cpp-queries/call-to-gmtime-without-lock.ql000066400000000000000000000016371450431004300264400ustar00rootroot00000000000000/** * @name Use of gmtime without proper lock * @description In the absence of the safer gmtime_r function, any call to * gmtime should be protected by a lock * Based on LGTM's built-in query 'cpp/potentially-dangerous-function' * (https://lgtm.com/rules/2154840805) after discussion here: * https://discuss.lgtm.com/t/suppressions-in-c-code/1525 * * @kind problem * @problem.severity error * @precision high * @id cpp/call-to-gmtime-without-lock * @tags reliability * security * external/cwe/cwe-676 */ import cpp import semmle.code.cpp.controlflow.Dominance predicate isLockedUseOfFunction(FunctionCall call){ exists (FunctionCall lockCall | lockCall.getTarget().getQualifiedName() = "g_mutex_lock" and dominates(lockCall, call) ) } from FunctionCall call where call.getTarget().getName() = "gmtime" and isLockedUseOfFunction(call) select call, "Call to gmtime is not protected by a lock" syslog-ng-syslog-ng-4.4.0/.mailmap000066400000000000000000000105111450431004300167720ustar00rootroot00000000000000Balazs Scheidler Laszlo Budai Laszlo Budai Laszlo Budai Laszlo Budai Laszlo Budai Andras Mitzki Andras Mitzki Andras Mitzki Attila Szakacs Attila Szakacs Attila Szakacs Attila Szakacs <45236571+alltilla@users.noreply.github.com> Attila Szakacs Attila Szakacs Balint Kovacs Balint Kovacs Fabien Wernli Fabien Wernli Fabien Wernli Gergely Nagy Gergely Nagy Gergely Nagy Gergely Nagy Gabor Nagy Viktor Juhasz Viktor Juhasz Viktor Juhasz Peter Kokai Peter Kokai Laszlo Meszaros Laszlo Meszaros Laszlo Szemere Laszlo Szemere Lorand Muzamel Lorand Muzamel László Várady <3130044+MrAnno@users.noreply.github.com> László Várady László Várady László Várady Marton ILLES Marton ILLES Adam Istvan MOZES Adam Istvan MOZES Adam Istvan MOZES Mate Farkas Mate Farkas Noemi Vanyi Noemi Vanyi Peter Czanik (CzP) Peter Czanik (CzP) Peter Czanik (CzP) Peter Gyorko Peter Gyorko Zoltan Pallagi Zoltan Pallagi Zoltan Pallagi Zoltan Pallagi Zoltan Pallagi Antal Nemes Antal Nemes Norbert Takacs Viktor Tusa Viktor Tusa Viktor Tusa syslog-ng-syslog-ng-4.4.0/AUTHORS000066400000000000000000000022021450431004300164170ustar00rootroot00000000000000 syslog-ng was written by Balázs Scheidler Contributions under the contrib/ directory were contributed by a number of different people. Code contributions: ------------------- Anthony Lineham - bugfixes Chris Packham - suppressing duplicate messages Jung Christian - BSDTAG macro Roger J. Meier - initgroups bugfix Corinna Vinschen - cygwin packaging files and portability fixes Charles G. Waldman - file source driver fixes Philip Bellino - IPv6 bugfixes Vijay Ramasubramanian - extending time related macros The Regents of the University of California & Chris Torek - strcasestr() Suggestions, good bugreports, helping newbies on the mailing list: ------------------------------------------------------------------ Evan Rempel Roberto Nibali Nate Campi Sandor Geller Valdis Kletnieks Alexander Clouter Hari Sekhon Dave Johnson Brian A. Seklecki John Morrissey Joe Fegan Joe Shaw and probably a lot more. Please note that this list is only updated from time to time, and my memories may not serve me the best, so it is probably inaccurate. If you miss your name from this list, just let me know :) Balazs Scheidler 2008-11-06 syslog-ng-syslog-ng-4.4.0/CMakeLists.txt000066400000000000000000000410351450431004300201160ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.14) # use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") set(CMAKE_MACOSX_RPATH 1) # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) project(syslog-ng C) if (APPLE) option(ENABLE_CPP "Enable C++" OFF) else() option(ENABLE_CPP "Enable C++" ON) endif() if (ENABLE_CPP) enable_language(CXX) set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard") set(SYSLOG_NG_ENABLE_CPP ${ENABLE_CPP}) endif() set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules ${PROJECT_SOURCE_DIR}/cmake/) set(CMAKE_POSITION_INDEPENDENT_CODE 1) set(BISON_FLAGS "-Wno-other -Werror=conflicts-sr -Werror=conflicts-rr -Wcounterexamples") set(BISON_BUILT_SOURCE_CFLAGS "-Wno-unused-but-set-variable") include(CheckIncludeFiles) include(ExternalProject) include(external_or_find_package) include(add_module) include(module_switch) find_package(Git QUIET) if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") option(GIT_SUBMODULE "Checkout submodules during build" ON) if(GIT_SUBMODULE) message(STATUS "Submodule update") execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_SUBMOD_RESULT) if(NOT GIT_SUBMOD_RESULT EQUAL "0") message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") endif() endif() endif() set(MEMORYCHECK_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/tests/valgrind/unit-test-leak.supp") set(MEMORYCHECK_COMMAND_OPTIONS "--num-callers=30 --sim-hints=no-nptl-pthread-stackcache --gen-suppressions=all --leak-check=full --trace-children=yes --freelist-vol=200000000 --freelist-big-blocks=10000000 --malloc-fill=55 --free-fill=AA") execute_process(COMMAND ${PROJECT_SOURCE_DIR}/scripts/version.sh SET OUTPUT_VARIABLE SYSLOG_NG_VERSION) set(SYSLOG_NG_COMBINED_VERSION ${SYSLOG_NG_VERSION}) set(SYSLOG_NG_SOURCE_REVISION ${SYSLOG_NG_VERSION}) set(SYSLOG_NG_PATH_PREFIX ${CMAKE_INSTALL_PREFIX}) set(SYSLOG_NG_PATH_SYSCONFDIR "\${prefix}/etc") set(SYSLOG_NG_PATH_DATADIR "\${datarootdir}") set(SYSLOG_NG_PATH_PKGDATADIR "\${datarootdir}/syslog-ng") set(SYSLOG_NG_PATH_PIDFILEDIR "\${localstatedir}") set(SYSLOG_NG_PATH_LOCALSTATEDIR "\${prefix}/var") set(SYSLOG_NG_MODULE_PATH "\${exec_prefix}/lib/syslog-ng") set(SYSLOG_NG_PATH_EXECPREFIX "\${prefix}") set(SYSLOG_NG_PATH_CONFIG_INCLUDEDIR "\${datadir}/syslog-ng/include") set(SYSLOG_NG_PATH_SCLDIR "\${datadir}/syslog-ng/include/scl") set(SYSLOG_NG_PATH_LIBEXECDIR "\${exec_prefix}/libexec") set(SYSLOG_NG_PATH_DATAROOTDIR "\${prefix}/share") set(SYSLOG_NG_ENABLE_TCP_WRAPPER 0) set(SYSLOG_NG_ENABLE_GPROF 0) set(SYSLOG_NG_ENABLE_MEMTRACE 0) set(SYSLOG_NG_ENABLE_SYSTEMD 0) set(SYSLOG_NG_PATH_MODULEDIR "\${exec_prefix}/lib/syslog-ng") set(SYSLOG_NG_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") set(SYSLOG_NG_PATH_XSDDIR "\${datadir}/syslog-ng/xsd") set(SYSLOG_NG_JAVA_MODULE_PATH "\${exec_prefix}/lib/syslog-ng/java-modules") set(SYSLOG_NG_PYTHON_MODULE_DIR "\${exec_prefix}/lib/syslog-ng/python") set(SYSLOG_NG_PYTHON_SYSCONF_MODULE_DIR "\${prefix}/etc/python") set(SYSLOG_NG_PYTHON_VENV_DIR "\${localstatedir}/python-venv") set(SYSLOG_NG_PATH_TOPSRC_DIR "${PROJECT_SOURCE_DIR}") set(LIBDIR "\${exec_prefix}/lib") set(INCLUDEDIR "\${prefix}/include") set(TOOLSDIR "\${datadir}/syslog-ng/tools") set(SYSLOG_NG_ENABLE_FORCED_SERVER_MODE 1) set (LOGGEN_PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/syslog-ng/loggen") IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) set(SYSLOG_NG_ENABLE_DEBUG 1) add_definitions(-DYYDEBUG=1) ELSE() set(SYSLOG_NG_ENABLE_DEBUG 0) ENDIF() include(CheckTypeSize) include(CheckStructMember) include(CheckSymbolExists) include(GenerateYFromYm) include(CheckStructHasMember) include(CheckCSourceCompiles) add_definitions(-D_GNU_SOURCE=1) add_definitions(-D_LARGEFILE64_SOURCE=1) add_definitions(-D__APPLE_USE_RFC_3542) include(CheckSockaddrStorage) if (HAVE_STRUCT_SOCKADDR_STORAGE) set(SYSLOG_NG_HAVE_STRUCT_SOCKADDR_STORAGE 1) else() set(SYSLOG_NG_HAVE_STRUCT_SOCKADDR_STORAGE 0) endif() include(CheckCreds) set(SYSLOG_NG_HAVE_STRUCT_UCRED (HAVE_STRUCT_UCRED OR HAVE_STRUCT_CMSGCRED)) check_struct_member ("struct msghdr" "msg_control" "sys/types.h;sys/socket.h" SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR) include(CheckIPv6) module_switch(ENABLE_IPV6 "Enable IPv6") if (ENABLE_IPV6) set(SYSLOG_NG_ENABLE_IPV6 ${HAVE_IPV6}) endif() check_symbol_exists(TCP_KEEPIDLE "sys/socket.h;netinet/in.h;netinet/tcp.h" HAVE_TCP_KEEPIDLE) check_symbol_exists(TCP_KEEPINTVL "sys/socket.h;netinet/in.h;netinet/tcp.h" HAVE_TCP_KEEPINTVL) check_symbol_exists(TCP_KEEPCNT "sys/socket.h;netinet/in.h;netinet/tcp.h" HAVE_TCP_KEEPCNT) if (HAVE_TCP_KEEPIDLE AND HAVE_TCP_KEEPINTVL AND HAVE_TCP_KEEPCNT) set(SYSLOG_NG_HAVE_TCP_KEEPALIVE_TIMERS 1) endif() if (NOT APPLE) set(SYSLOG_NG_HAVE_ENVIRON 1) endif() option(ENV_LD_LIBRARY_PATH "Set LD_LIBRARY_PATH during runtime to the value given" "") if (ENV_LD_LIBRARY_PATH) set(SYSLOG_NG_ENABLE_ENV_WRAPPER 1) endif() option(WITH_COMPILE_DATE "Include compile date in binary" "ON") if (WITH_COMPILE_DATE) set(SYSLOG_NG_WITH_COMPILE_DATE 1) endif() set(CMAKE_REQUIRED_DEFINITIONS "-D_LARGEFILE64_SOURCE=1") set(CMAKE_EXTRA_INCLUDE_FILES "fcntl.h") check_type_size(O_LARGEFILE O_LARGEFILE) if (HAVE_O_LARGEFILE) set(SYSLOG_NG_HAVE_O_LARGEFILE 1) endif() check_c_source_compiles(" #include __thread int a; int main() { a=0; }" SYSLOG_NG_HAVE_THREAD_KEYWORD) check_symbol_exists(strtoll stdlib.h SYSLOG_NG_HAVE_STRTOLL) check_symbol_exists(strnlen string.h SYSLOG_NG_HAVE_STRNLEN) check_symbol_exists(getline "stdio.h" SYSLOG_NG_HAVE_GETLINE) check_symbol_exists(strtok_r string.h SYSLOG_NG_HAVE_STRTOK_R) check_symbol_exists(strtoimax inttypes.h SYSLOG_NG_HAVE_STRTOIMAX) check_symbol_exists(inet_aton "sys/socket.h;netinet/in.h;arpa/inet.h" SYSLOG_NG_HAVE_INET_ATON) check_symbol_exists(inet_ntoa "sys/socket.h;netinet/in.h;arpa/inet.h" SYSLOG_NG_HAVE_INET_NTOA) check_symbol_exists(getutent utmp.h SYSLOG_NG_HAVE_GETUTENT) check_symbol_exists(getutxent utmpx.h SYSLOG_NG_HAVE_GETUTXENT) check_symbol_exists(getaddrinfo "netdb.h;sys/socket.h;sys/types.h" SYSLOG_NG_HAVE_GETADDRINFO) check_symbol_exists(getnameinfo "netdb.h;sys/socket.h" SYSLOG_NG_HAVE_GETNAMEINFO) check_symbol_exists(getprotobynumber_r "netdb.h" SYSLOG_NG_HAVE_GETPROTOBYNUMBER_R) check_symbol_exists(clock_gettime "time.h" SYSLOG_NG_HAVE_CLOCK_GETTIME) check_symbol_exists(gmtime_r "time.h" SYSLOG_NG_HAVE_GMTIME_R) check_symbol_exists(localtime_r "time.h" SYSLOG_NG_HAVE_LOCALTIME_R) check_symbol_exists("getrandom" "sys/random.h" SYSLOG_NG_HAVE_GETRANDOM) check_symbol_exists(fmemopen "stdio.h" SYSLOG_NG_HAVE_FMEMOPEN) set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE=1") check_symbol_exists(memrchr "string.h" SYSLOG_NG_HAVE_MEMRCHR) check_symbol_exists(strcasestr "string.h" SYSLOG_NG_HAVE_STRCASESTR) check_symbol_exists(pread "unistd.h" SYSLOG_NG_HAVE_PREAD) check_symbol_exists(pwrite "unistd.h" SYSLOG_NG_HAVE_PWRITE) check_symbol_exists(posix_fallocate "fcntl.h" SYSLOG_NG_HAVE_POSIX_FALLOCATE) check_symbol_exists(timezone time.h SYSLOG_NG_HAVE_TIMEZONE) check_include_files(utmp.h SYSLOG_NG_HAVE_UTMP_H) check_include_files(utmpx.h SYSLOG_NG_HAVE_UTMPX_H) check_include_files(dlfcn.h SYSLOG_NG_HAVE_DLFCN_H) check_include_files(getopt.h SYSLOG_NG_HAVE_GETOPT_H) check_struct_has_member("struct utmpx" "ut_type" "utmpx.h" UTMPX_HAS_UT_TYPE LANGUAGE C) check_struct_has_member("struct utmp" "ut_type" "utmp.h" UTMP_HAS_UT_TYPE LANGUAGE C) check_struct_has_member("struct utmpx" "ut_user" "utmpx.h" UTMPX_HAS_UT_USER LANGUAGE C) check_struct_has_member("struct utmp" "ut_user" "utmp.h" UTMP_HAS_UT_USER LANGUAGE C) check_struct_has_member("struct tm" "tm_gmtoff" "sys/time.h;time.h" SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF) if ((UTMPX_HAS_UT_TYPE AND UTMPX_HAS_UT_USER) OR (UTMPX_HAS_UT_TYPE AND UTMP_HAS_UT_USER)) set(SYSLOG_NG_HAVE_MODERN_UTMP 1) endif() check_symbol_exists(SO_MEMINFO "sys/socket.h" SYSLOG_NG_HAVE_SO_MEMINFO) check_include_file("linux/sock_diag.h" SYSLOG_NG_HAVE_LINUX_SOCK_DIAG_H) if (SYSLOG_NG_HAVE_SO_MEMINFO) set(SYSLOG_NG_ENABLE_AFSOCKET_MEMINFO_METRICS 1) endif() set(WITH_GETTEXT "" CACHE STRING "Set the prefix where gettext is installed (e.g. /usr)") set(CMAKE_C_STANDARD 99) find_package(BISON 3.7.6 REQUIRED) string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\..*$" _dummy "${BISON_VERSION}") set(GLIB_COMPILE_DEFINITIONS GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32 ) find_package(GLIB 2.32.0 REQUIRED COMPONENTS gmodule gthread) set(CMAKE_REQUIRED_INCLUDES ${GLIB_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${GLIB_LIBRARIES}) check_symbol_exists(g_list_copy_deep "glib.h" SYSLOG_NG_HAVE_G_LIST_COPY_DEEP) check_symbol_exists(g_ptr_array_find_with_equal_func "glib.h" SYSLOG_NG_HAVE_G_PTR_ARRAY_FIND_WITH_EQUAL_FUNC) check_symbol_exists(g_canonicalize_filename "glib.h" SYSLOG_NG_HAVE_G_CANONICALIZE_FILENAME) find_package(RabbitMQ) if (RabbitMQ_FOUND) set(CMAKE_REQUIRED_INCLUDES ${RabbitMQ_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${RabbitMQ_LIBRARY}) check_symbol_exists(amqp_ssl_socket_set_verify_peer "amqp.h;amqp_ssl_socket.h" SYSLOG_NG_HAVE_AMQP_SSL_SOCKET_SET_VERIFY_PEER) endif() set (SYSLOG_NG_USE_CONST_IVYKIS_MOCK 1) external_or_find_package(IVYKIS REQUIRED) if ((NOT IVYKIS_INTERNAL) AND (IVYKIS_PKGCONF_VERSION VERSION_LESS "0.39")) set (SYSLOG_NG_USE_CONST_IVYKIS_MOCK 0) endif() find_package(OpenSSL REQUIRED) find_package(FLEX REQUIRED) find_package(LIBNET REQUIRED) find_package(Resolv REQUIRED) find_package(WRAP) find_package(criterion) find_package(Inotify) find_package(LIBCAP) find_package(systemd) pkg_search_module(SYSTEMD_WITH_NAMESPACE libsystemd>=245) message(STATUS "Found lib${SYSTEMD_WITH_NAMESPACE_LIBRARIES} version ${SYSTEMD_WITH_NAMESPACE_VERSION}") module_switch(ENABLE_JOURNALD "Enable systemd-journal" Libsystemd_FOUND) set(WITH_SYSTEMD_JOURNAL "system" CACHE STRING "Link against the system supplied or the wrapper library") set_property(CACHE WITH_SYSTEMD_JOURNAL PROPERTY STRINGS system wrapper) if (ENABLE_JOURNALD) if (WITH_SYSTEMD_JOURNAL STREQUAL "system" AND NOT Libsystemd_FOUND) message(FATAL_ERROR "systemd library not found") endif() set(SYSLOG_NG_ENABLE_SYSTEMD 1) if (WITH_SYSTEMD_JOURNAL STREQUAL "system") if (SYSTEMD_WITH_NAMESPACE_LIBRARIES STREQUAL "systemd") set(SYSLOG_NG_HAVE_JOURNAL_NAMESPACES 1) message(STATUS "Have journal namespaces") else() set(SYSLOG_NG_HAVE_JOURNAL_NAMESPACES 0) endif() set(SYSLOG_NG_SYSTEMD_JOURNAL_MODE SYSLOG_NG_JOURNALD_SYSTEM) elseif (WITH_SYSTEMD_JOURNAL STREQUAL "wrapper") set(SYSLOG_NG_SYSTEMD_JOURNAL_MODE SYSLOG_NG_JOURNALD_OPTIONAL) endif() else() set(SYSLOG_NG_ENABLE_SYSTEMD 0) set(SYSLOG_NG_SYSTEMD_JOURNAL_MODE SYSLOG_NG_JOURNALD_OFF) endif() set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) set(SYSLOG_NG_HAVE_INOTIFY "${Inotify_FOUND}") set (PYTHON_VERSION "AUTO" CACHE STRING "Version of the installed development library" ) if ("${PYTHON_VERSION}" STREQUAL "AUTO") find_package(PythonInterp EXACT 3) find_package(PythonLibs EXACT 3) else () find_package(PythonInterp EXACT "${PYTHON_VERSION}" REQUIRED) find_package(PythonLibs EXACT "${PYTHON_VERSION}" REQUIRED) endif () MESSAGE(STATUS "Detected pythonlib version: ${PYTHONLIBS_VERSION_STRING}") include(python_build_venv) include(openssl_functions) openssl_set_defines() pkg_check_modules(LIBPCRE REQUIRED libpcre2-8) if (WRAP_FOUND) set(SYSLOG_NG_ENABLE_TCP_WRAPPER 1) endif() if (LIBNET_FOUND) set(SYSLOG_NG_ENABLE_SPOOF_SOURCE 1) endif() set(SYSLOG_NG_ENABLE_LINUX_CAPS ${PC_LIBCAP_FOUND}) if (WITH_GETTEXT) set(CMAKE_PREFIX_PATH ${WITH_GETTEXT}) find_package(Gettext REQUIRED QUIET) set(CMAKE_PREFIX_PATH "") else() find_package(Gettext REQUIRED QUIET) endif() set(Eventlog_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib/eventlog/src") add_custom_target(style-check COMMAND ${PROJECT_SOURCE_DIR}/scripts/style-checker.sh check ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}) add_custom_target(style-format COMMAND ${PROJECT_SOURCE_DIR}/scripts/style-checker.sh format ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR}) add_custom_target(check-commits COMMAND ${PROJECT_SOURCE_DIR}/tests/commits/check.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(check-copyright COMMAND ${PROJECT_SOURCE_DIR}/tests/copyright/check.sh . ${PROJECT_BINARY_DIR} policy WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) set_target_properties(check-copyright PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "copyright-run.log;copyright-err.log") if (CRITERION_FOUND) option(BUILD_TESTING "Enable unit tests" ON) else() option(BUILD_TESTING "Enable unit tests" OFF) endif() include(add_tests) # The inclusion of CTest triggers enable_testing() # CMake will generate tests only if the enable_testing() command has been invoked. # The CTest module invokes the command automatically when the BUILD_TESTING option is ON. if (BUILD_TESTING) if (NOT CRITERION_FOUND) message(FATAL_ERROR "BUILD_TESTING enabled without criterion detected!") else() set(CTEST_ENVIRONMENT "G_SLICE=always-malloc,debug-blocks" "G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly") include(CTest) add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -j $$(nproc) --output-on-failure) endif() endif() set(IMPORTANT_WARNINGS -Wshadow) set(ACCEPTABLE_WARNINGS -Wno-stack-protector -Wno-unused-parameter -Wno-variadic-macros) option(ENABLE_EXTRA_WARNINGS "Enable extra warnings" ON) if (ENABLE_EXTRA_WARNINGS) set(EXTRA_WARNINGS $<$:-Wimplicit-function-declaration> $<$:-Wnested-externs> $<$:-Wstrict-prototypes> -Wswitch-default $<$:-Wimplicit-int> -Wall -Wuninitialized -Wdeprecated -Wdeprecated-declarations -Woverflow -Wdouble-promotion -Wfloat-equal -Wpointer-arith $<$:-Wpointer-sign> -Wmissing-format-attribute $<$:-Wold-style-definition> -Wundef -Wignored-qualifiers -Wfloat-conversion $<$:-Wbad-function-cast>) if ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") set(EXTRA_WARNINGS ${EXTRA_WARNINGS} ) else() set(EXTRA_WARNINGS $<$:-Wold-style-declaration> -Wunused-but-set-parameter $<$:-Woverride-init> ${EXTRA_WARNINGS} ) endif() endif() add_compile_options(${IMPORTANT_WARNINGS} ${ACCEPTABLE_WARNINGS} ${EXTRA_WARNINGS}) # Sanatizer configuration set(SANITIZER "OFF" CACHE STRING "Enable clang sanitizer") set_property(CACHE SANITIZER PROPERTY STRINGS OFF address undefined) if (SANITIZER) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -fsanitize=${SANITIZER} -fno-omit-frame-pointer") endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_subdirectory(Mk) add_subdirectory(scl) add_subdirectory(lib) add_subdirectory(modules) add_subdirectory(scripts) add_subdirectory(syslog-ng) add_subdirectory(syslog-ng-ctl) add_subdirectory(persist-tool) add_subdirectory(tests) add_subdirectory(libtest) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/syslog-ng-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/syslog-ng-config.h) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syslog-ng-config.h DESTINATION include/syslog-ng) install(DIRECTORY DESTINATION var) # Package Information for pkg-config set(PKG_CONFIG_EXEC_PREFIX ${SYSLOG_NG_PATH_EXECPREFIX}) set(PKG_CONFIG_DATAROOTDIR ${SYSLOG_NG_PATH_DATAROOTDIR}) set(PKG_CONFIG_DATADIR ${SYSLOG_NG_PATH_DATAROOTDIR}) set(PKG_CONFIG_LIBDIR ${LIBDIR}) set(PKG_CONFIG_INCLUDEDIR ${INCLUDEDIR}) set(PKG_CONFIG_TOOLSDIR ${TOOLSDIR}) set(PKG_CONFIG_MODULEDIR ${SYSLOG_NG_PATH_MODULEDIR}) set(PKG_CONFIG_CONFIG_INCLUDEDIR ${SYSLOG_NG_PATH_CONFIG_INCLUDEDIR}) set(PKG_CONFIG_SCLDIR ${SYSLOG_NG_PATH_SCLDIR}) set(PKG_CONFIG_IVYKIS ${IVYKIS_INCLUDE_DIRS}) set(PKG_CONFIG_PACKAGE_VERSION ${SYSLOG_NG_VERSION}) set(PKG_CONFIG_INTERNAL_IVYKIS_CFLAGS ${IVYKIS_INCLUDE_DIRS}) set(libdir "\${libdir}") set(includedir "\${includedir}") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/syslog-ng.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/syslog-ng.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syslog-ng.pc DESTINATION lib/pkgconfig) include(print_config_summary) print_config_summary() syslog-ng-syslog-ng-4.4.0/CONTRIBUTING.md000066400000000000000000000201711450431004300176050ustar00rootroot00000000000000# Contributing to syslog-ng syslog-ng is developed as a community project, and relies on volunteers to produce syslog-ng. Reporting bugs, testing changes, writing code, or simply providing feedback are all important contributions. This guide provides guidelines to make contributing easier. ## Table of contents 1. [Issues](#issues) 1. [Reporting bugs](#reporting-bugs) 2. [Feature requests](#feature-requests) 3. [Testing](#testing) 2. [Pull requests](#pull-requests) 3. [Additional resources](#additional-resources) ## Issues One of the easiest ways to contribute to the development of syslog-ng is to participate in the discussions about features, bugs and design. Some of these discussions started on the [mailing list][ar:mailing-list], some in the [issue tracker][ar:issue-tracker]. Bugs tagged [`good first issue`][ar:issues:good-first-issue] are generally good targets to contribute your feedback - but pretty much any open issue can be a good start! ### Reporting bugs When you report a bug, it is important to share as much relevant information as you can, including: * version number of syslog-ng used; * the platform (operating system and its version, architecture, etc); * a backtrace from the core file if the issue is a crash (this can be invaluable); * if possible, a configuration that triggers the problem; * a detailed description of the issue. To make it easy to read reports, if you send a configuration snippet, or a backtrace, use [fenced code blocks](https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks) around them. ### Feature requests We use the same [issue tracker][ar:issue-tracker] to handle features requests (they're all tagged with the [`enhancement`](https://github.com/syslog-ng/syslog-ng/labels/enhancement) label. You are welcome to share your ideas on existing requests, or to submit your own. ### Testing An incredibly useful way to contribute is to test patches and pull requests - there's only so much [automated testing][ar:github-actions] can do. For example, you can help testing on platforms the developers do not have access to, or try configurations not thought of before. ## Pull requests If you plan to open a pull request, please follow the guideline below. ### Branch You need to fork syslog-ng in github, and create a working branch from master in your fork. After writing the code, just before opening the pull request, make sure your working branch is rebased against master. ### PR description In the description, please explain (if applicable): - The problem your pull request intends to solve. - A general overview about the implementation, or any information that can help reviewers to understand your code. - Please explain how one can try out your code: configuration snippets, or deployment information. - You can mention if you were considering alternative solutions or explain problems you ran into. - If you submit a pull request that fixes an existing issue, please mention the issue somewhere in the pull request, so we can close the original issue as well. The documentation is created from the description. Please provide a description that can be a good input for the admin guide as well. ### Commits #### Commit messages ``` The commit messages be formatted according to this: module: short description Long description, that may be formatted in markdown. Signed-off-by: your name ``` This format is checked by the CI. If you do not want to share your email address due to privacy reasons, you can use `some-id+yourgithubusername@users.noreply.github.com`, which is automatically generated and tracked by github. You can check the exact address in your github settings->email->primary email address, if you enabled email privacy. `module` refers to the part of syslog-ng that the patch intends to change. For example python, redis, persist, scratch-buffers, etc. #### Patches We are using a coding style very similar to [GNU Coding Standards](https://www.gnu.org/prep/standards/standards.html#Writing-C) for syslog-ng. You can use `make style-check` or `make style-format` to check or format automatically your code. These commands are executed by our CI as well. If possible, please organize your code into a set of small and self contained patches, with clear descriptions each, that can help to understand the patch. This greatly helps the review process. Please follow clean code guidelines whenever possible. Functions should be small and responsible for one thing. Try to avoid code duplication. Add descriptive names for functions and variables. Etc... #### News file We are automatically generating the news file before each release. So that to work, please add a news entry for your change under the news directory. The file name should be news/type-PR_ID.md (for example: news/bugfix-1234.md). For now the following types are supported: feature, bugfix, packaging, developer-note, other. If you think there is no need for a news file (for example it is a small fix for an earlier pull request of the same release), you can leave a note about it in the pull request description. The generated news file will contain a link to the pull request, where the interested users can find detailed information in the description. This means your news entry does not need to be too descriptive. The news file format should look like this: ``` `module`: short description long description ``` See news/README.md for more information. ### Testing If possible please add tests for your change. You can add unit tests in c (tests directory in most of syslog-ng modules), or there is an initiative so that contributors write tests in python (for now the feature set is limited). You can check `tests/light/functional_tests/source_drivers/generator_source/` as an example. ### CI After opening the pull requests, one of the maintainers will enable the tests to run for your pull requests. So that the pull request could be merged, all tests must pass, and the PR needs two approvals from the maintainers. You do not need to find reviewers. The maintainers continuously monitor the project, and will assign themselves. We try to add feedback as soon as possible. If you get stuck with a regression test, feel free to ask for help. Sometimes it is difficult to understand the test logs. ## Licensing Please ensure that your contribution is clean in respect to licensing and copyright. If your contribution is eligible for copyright, you should also extend the list of copyright holders at the top of the relevant files which carry your modifications. The absolute minimum to specify is the identity of the author entity, which is usually one or more of an e-mail address and your full name or the name of the legal entity who holds the intellectual rights if it is not you. Please make it clear which is the case, because this may depend on your contract if you are employed or are a subcontractor. Note that from time to time, we may rephrase the exact text surrounding attributions, however the specified identities and the license binding a given contribution will not be changed in a legally incompatibly manner. Every new file must carry a standard copyright notice and be compatible with our licensing scheme described in COPYING. You should observe some of the existing files for reference. ## Additional resources For additional information, have a look at the [syslog-ng.org](http://www.syslog-ng.org/) website, which is a recommended starting point for finding out more about syslog-ng. To contact us, visit the [mailing list][ar:mailing-list] where you can ask questions, and discuss your feature requests with a wider audience. We also have a [Gitter channel][ar:gitter], where developers hang out. We use [GitHub issues][ar:issue-tracker] to track issues, feature requests and patches. We are also using [GitHub Actions][ar:github-actions] for automatic testing. [ar:gitter]: https://gitter.im/syslog-ng/syslog-ng [ar:mailing-list]: http://lists.balabit.com/mailman/listinfo/syslog-ng [ar:issue-tracker]: https://github.com/syslog-ng/syslog-ng/issues [ar:issues:good-first-issue]: https://github.com/syslog-ng/syslog-ng/labels/good%20first%20issue [ar:github-actions]: https://github.com/syslog-ng/syslog-ng/actions syslog-ng-syslog-ng-4.4.0/COPYING000066400000000000000000000115401450431004300164070ustar00rootroot00000000000000Copyright (c) 2002-2015 Balabit Copyright (c) 1996-2015 Balázs Scheidler syslog-ng is licensed under the combination of the GPL and LGPL licenses. Our intention with the choice of our licenses is to: 1) license reusable/extendable code under the LGPL, 2) license code implementing a specific function, not intended to be extended, under the GPL Although the location of a file wthin the source tree is closely related to how it is licensed (lib/ is LGPL by default, for instance), there are exceptions. One example is: some of the tests are GPLed while they are related to LGPLed library code. With that in mind, before assuming the licensing of a specific file based solely on its location, please check its licensing in its copyright header, i.e. the very first comment block of the source code file. Alternatively, you can also use the contents of the `tests/copyright/policy` file, this is an input to our automated test suite that checks licenses against our intents. The syslog-ng core contained in the following subdirectories is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version (please refer to the file LGPL.txt for more details): lib/ libtest/ syslog-ng/ syslog-ng-ctl/ persist-tool/ tests/loggen/ docker/ The syslog-ng modules (modules/ and scl/ subdirectories, except the ones that declare LGPL-2.1-or-later in their license notices) is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation, or (at your option) any later version (please refer to the file GPL.txt for more details). FAQ: ==== The questions and answers below try to summarize the intentions behind this licensing scheme. Q: Is it possible to create derived works of syslog-ng under the GPL/LGPL licenses? A: Yes, that's exactly the point of open source. Works derived from the plugins will have to use the GPL license, but you can choose to use LGPL for them as well. Q: Do I need to sign a Contributory License Agreement in order for my contribution to be accepted? A: No, starting with syslog-ng 3.2, you don't need to sign a CLA in order to have your contributions accepted. Q: Is it possible to create non-free plugins for syslog-ng? A: Yes. It is our understanding that plugins are derived works of the syslog-ng core but not derived works of other plugins. Thus, non-free plugins are possible, provided they do not link to any of the GPLd plugins explicitly and the only connection between two plugins is via the syslog-ng core. Q: Who is permitted to create non-free plugins for syslog-ng? Is it just BalaBit (the current copyright holder as of the initial 3.2 release)? A: No, everyone including BalaBit. PORTIONS WERE CONTRIBUTED UNDER THE FOLLOWING LICENSES: ====================================================== lib/compat: /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ syslog-ng-syslog-ng-4.4.0/GPL.txt000066400000000000000000000354311450431004300165440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS syslog-ng-syslog-ng-4.4.0/LGPL.txt000066400000000000000000000636421450431004300166650ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! syslog-ng-syslog-ng-4.4.0/Makefile.am000066400000000000000000000175541450431004300174230ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# SUBDIRS = DIST_SUBDIRS = AM_MAKEFLAGS = --no-print-directory AM_YFLAGS = -Wno-yacc -Wno-other -Werror=conflicts-sr -Werror=conflicts-rr -Wcounterexamples AM_TESTS_ENVIRONMENT = top_srcdir="$(top_srcdir)" CRITERION_TEST_PATTERN='!(*/*performance*)' ASAN_OPTIONS="detect_odr_violation=0" if ENABLE_SANITIZER LOG_COMPILER = $(top_srcdir)/scripts/test-grep.sh endif ACLOCAL_AMFLAGS = -I m4 --install EXTRA_DIST = $(filter-out ${NODIST_BUILT_SOURCES},${BUILT_SOURCES}) VERSION NEWS.md autogen.sh \ dist.conf dist.conf.in syslog-ng.pc.in \ syslog-ng-config.h.in \ CONTRIBUTING.md \ sub-configure.sh \ syslog-ng.pc.cmake \ syslog-ng-native-connector.pc.cmake \ syslog-ng-ctl/CMakeLists.txt \ requirements.txt \ dev-requirements.txt \ README.md \ .astylerc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = syslog-ng.pc AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/modules -I$(top_builddir)/lib -I$(top_builddir)/modules # configure script gives us -g and/or -O2, but all warning related settings # should be here # Important warnings AM_CFLAGS = \ -Wshadow AM_CXXFLAGS = \ -Wshadow # Acceptable warnings AM_CFLAGS += \ -Wno-stack-protector \ -Wno-unused-parameter \ -Wno-variadic-macros AM_CXXFLAGS += \ -Wno-stack-protector \ -Wno-unused-parameter \ -Wno-variadic-macros if ENABLE_EXTRA_WARNINGS AM_CFLAGS += \ -Wimplicit-function-declaration \ -Wnested-externs \ -Wold-style-declaration \ -Wstrict-prototypes \ -Wswitch-default \ -Wimplicit-int \ -Wall \ -Wuninitialized \ -Wunused-but-set-parameter \ -Wdeprecated \ -Wdeprecated-declarations \ -Woverflow \ -Wdouble-promotion \ -Wfloat-equal \ -Wpointer-arith \ -Wpointer-sign \ -Wmissing-format-attribute \ -Wold-style-definition \ -Wundef \ -Wignored-qualifiers \ -Woverride-init \ -Wfloat-conversion \ -Wbad-function-cast AM_CXXFLAGS += \ -Wswitch-default \ -Wall \ -Wuninitialized \ -Wdeprecated \ -Wdeprecated-declarations \ -Woverflow \ -Wdouble-promotion \ -Wfloat-equal \ -Wpointer-arith \ -Wmissing-format-attribute \ -Wundef \ -Wignored-qualifiers \ -Wfloat-conversion \ -Wunused-but-set-parameter endif if ENABLE_DEBUG AM_CFLAGS += -DYYDEBUG=1 endif TEST_CFLAGS = -DTOP_SRCDIR=\"$(abs_top_srcdir)\" $(AM_CFLAGS) $(CRITERION_CFLAGS) TEST_CXXFLAGS = -DTOP_SRCDIR=\"$(abs_top_srcdir)\" $(AM_CXXFLAGS) $(CRITERION_CFLAGS) -lstdc++ TEST_LDADD = $(LIBTEST_LIBS) $(CRITERION_LIBS) \ $(top_builddir)/lib/libsyslog-ng.la \ $(TOOL_DEPS_LIBS) test_ldflags = -no-install $(NO_PIE_LDFLAG) PREOPEN_SYSLOGFORMAT = -dlpreopen ${top_builddir}/modules/syslogformat/libsyslogformat.la PREOPEN_BASICFUNCS = -dlpreopen ${top_builddir}/modules/basicfuncs/libbasicfuncs.la PREOPEN_CORE = $(PREOPEN_SYSLOGFORMAT) $(PREOPEN_BASICFUNCS) syslog_ng_tools = ${top_srcdir}/lib export top_srcdir export MAKE CLEAN_SUBDIRS = clean-local: ${CLEAN_HOOKS} ${AM_v_at}for dir in ${CLEAN_SUBDIRS}; do \ [ -f $${dir}/Makefile ] && ${MAKE} -C $${dir} clean || true; \ done distclean-local: distclean-ax-prefix-config-h distclean-ax-prefix-config-h: rm -f _configs.sed syslog-ng-config.h if ENABLE_TESTING local-check: subdir_tests=$(foreach ts,${${check_subdir}_test_subdirs},${${ts}_tests_TESTS}) local-check: current_tests=$(foreach subdir,${check_subdir} ${check_subdir}_tests,${${subdir}_TESTS}) local-check: ${AM_v_at}${MAKE} check check_PROGRAMS="${current_tests} ${subdir_tests}" \ TESTS="${current_tests} ${subdir_tests}" endif check: check_target_guard check_target_guard: if !ENABLE_TESTING $(error "Unit tests disabled") endif ${check_PROGRAMS}: LDFLAGS+=${test_ldflags} noinst_PROGRAMS = noinst_LIBRARIES = noinst_DATA = noinst_LTLIBRARIES = lib_LTLIBRARIES = pkginclude_HEADERS = syslog-ng-config.h module_LTLIBRARIES = loggenplugin_LTLIBRARIES = BUILT_SOURCES = NODIST_BUILT_SOURCES = CLEANFILES = $(BUILT_SOURCES) check_PROGRAMS = check_SCRIPTS = TESTS = $(check_PROGRAMS) $(check_SCRIPTS) bin_SCRIPTS = dist_sbin_SCRIPTS = bin_PROGRAMS = sbin_PROGRAMS = libexec_PROGRAMS = man_MANS = INSTALL_EXEC_HOOKS = UNINSTALL_HOOKS = CLEAN_HOOKS = AUTOMAKE_OPTIONS = subdir-objects parallel-tests ${top_srcdir}/ChangeLog: (cd $(top_srcdir); git log) > $@ install-exec-hook: ${INSTALL_EXEC_HOOKS} uninstall-hook: ${UNINSTALL_HOOKS} populate-makefiles: $(top_srcdir)/Mk/populate-makefiles.sh style-check: $(top_srcdir)/scripts/style-checker.sh check $(top_srcdir) style-format: $(top_srcdir)/scripts/style-checker.sh format $(top_srcdir) help: @echo "Welcome to the syslog-ng build system!" @echo @echo "All of the standard targets are available:" @echo " all, check, install, dist, distcheck, and clean" @echo @echo "Apart from these, the build system supports various other," @echo "special targets:" @echo @echo " modules Builds all syslog-ng modules." @echo " syslog-ng Build syslog-ng itself, only." @echo " populate-makefiles populate build directory with stub Makefiles" @echo " check-commits check commits format" @echo " check-copyright check copyright/license statements in files" @echo " style-check check formatting of source files (astyle)" @echo " style-format reformat source files (astyle)" @echo @echo "One can also build individual modules (and their dependencies)," @echo "using any of the following shortcuts:" @echo @echo "" ${SYSLOG_NG_MODULES} | sed -e 's#\(.\{,72\}\) #\1\n #g' .PHONY: help populate-makefiles install_moduleLTLIBRARIES = install-moduleLTLIBRARIES $(install_moduleLTLIBRARIES): install-libLTLIBRARIES install_loggenpluginLTLIBRARIES = install-loggenpluginLTLIBRARIES $(install_loggenpluginLTLIBRARIES): install-libLTLIBRARIES include Mk/lex-rules.am include Mk/python-venv.am include Mk/Makefile.am if ENABLE_TESTING include libtest/Makefile.am endif include lib/Makefile.am include modules/Makefile.am include syslog-ng/Makefile.am include syslog-ng-ctl/Makefile.am include scripts/Makefile.am include tests/Makefile.am include doc/Makefile.am include contrib/Makefile.am include scl/Makefile.am include packaging/Makefile.am include dbld/Makefile.am include cmake/Makefile.am include dev-utils/plugin_skeleton_creator/Makefile.am include persist-tool/Makefile.am TEST_EXTENSIONS = .sh @VALGRIND_CHECK_RULES@ VALGRIND_SUPPRESSIONS_FILES = $(top_srcdir)/tests/valgrind/unit-test-leak.supp EXTRA_DIST += syslog-ng.supp \ .github/ISSUE_TEMPLATE/10-bug-report.md \ .github/ISSUE_TEMPLATE/20-documentation-issue.md \ .github/ISSUE_TEMPLATE/30-feature-request.md \ GPL.txt \ LGPL.txt \ CMakeLists.txt VALGRIND_FLAGS = \ --num-callers=30 \ --sim-hints=no-nptl-pthread-stackcache \ --gen-suppressions=all VALGRIND_memcheck_FLAGS = \ --leak-check=full \ --trace-children=yes \ --freelist-vol=200''000''000 \ --freelist-big-blocks=10''000''000 \ --malloc-fill=55 \ --free-fill=AA syslog-ng-syslog-ng-4.4.0/Mk/000077500000000000000000000000001450431004300157225ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/Mk/CMakeLists.txt000066400000000000000000000000761450431004300204650ustar00rootroot00000000000000install(FILES lex-rules.am DESTINATION share/syslog-ng/tools) syslog-ng-syslog-ng-4.4.0/Mk/Makefile.am000066400000000000000000000003401450431004300177530ustar00rootroot00000000000000EXTRA_DIST += Mk/lex-rules.am \ Mk/find-top-builddir.sh \ Mk/populate-makefiles.sh \ Mk/subdir.mk \ Mk/CMakeLists.txt tools_DATA = \ Mk/lex-rules.am \ lib/cfg-grammar.y tools_SCRIPTS = \ lib/merge-grammar.py syslog-ng-syslog-ng-4.4.0/Mk/find-top-builddir.sh000077500000000000000000000001351450431004300215740ustar00rootroot00000000000000#! /bin/sh while ! test -f config.status || test "$(pwd)" = "/"; do cd .. done pwd syslog-ng-syslog-ng-4.4.0/Mk/lex-rules.am000066400000000000000000000017001450431004300201570ustar00rootroot00000000000000%.y: %.ym $(syslog_ng_tools)/merge-grammar.py $(syslog_ng_tools)/cfg-grammar.y if HAVE_PYTHON_INTERPRETER $(AM_V_at) $(mkinstalldirs) $(dir $@) $(AM_V_GEN) $(PYTHON) $(syslog_ng_tools)/merge-grammar.py $< > $@ else $(error "Python interpreter is required to generate grammar files, but it was not detected during configure") endif .l.c: $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $*.c $(LEX_OUTPUT_ROOT).h $*.h -- $(LEXCOMPILE) | ($(EGREP) -v "(^updating|unchanged)" || true) $(AM_V_at) touch $@ .l.h: $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $*.c $(LEX_OUTPUT_ROOT).h $*.h -- $(LEXCOMPILE) | ($(EGREP) -v "(^updating|unchanged)" || true) $(AM_V_at) touch $@ .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) .y.h: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) syslog-ng-syslog-ng-4.4.0/Mk/populate-makefiles.sh000077500000000000000000000011671450431004300220550ustar00rootroot00000000000000#! /bin/sh root=$(cd $(dirname $0) && cd .. && pwd) populate() { mfam="$1" dir="$(dirname ${mfam})" if [ "${dir}" != "." ] && [ "${dir}" != "${root}" ] && [ -d "${dir}" ]; then echo "${root}/Mk/subdir.mk" "=>" "${dir}/Makefile" ln -sf "${root}/Mk/subdir.mk" "${dir}/Makefile" fi if [ -e "${root}/${dir}/Makefile.am" ]; then incs=$(grep "^include" "${root}/${dir}/Makefile.am" | sed -e "s,^include ,,") for inc in ${incs}; do populate "${inc}" done fi } populate ./Makefile.am syslog-ng-syslog-ng-4.4.0/Mk/python-venv.am000066400000000000000000000006541450431004300205430ustar00rootroot00000000000000 PYTHON_VENV_TOUCHFILE=$(abs_builddir)/.python-venv-built $(PYTHON_VENV_TOUCHFILE): dev-requirements.txt if [ "$(with_python_packages)" = "venv" ]; then \ $(top_srcdir)/scripts/build-python-venv.sh "$(PYTHON)" "$(PYTHON_VENV_DIR)" "$(top_srcdir)"; \ fi touch $@ python-venv: $(PYTHON_VENV_TOUCHFILE) python-venv-clean: rm -rf "$(PYTHON_VENV_DIR)" rm -rf "$(PYTHON_VENV_TOUCHFILE)" CLEAN_HOOKS += python-venv-clean syslog-ng-syslog-ng-4.4.0/Mk/subdir.mk000066400000000000000000000034701450431004300175470ustar00rootroot00000000000000top_srcdir = $(dir $(shell readlink ${MAKEFILE_LIST}))../ top_builddir = $(shell ${top_srcdir}/Mk/find-top-builddir.sh) self = $(subst ${top_builddir}/,,${CURDIR}) self_sub = $(subst -,_,$(subst /,_,${self})) basedir = $(firstword $(subst /, ,${self})) levelup = ifeq (${self_sub},lib_filter) levelup = 1 else ifeq (${self_sub},lib_logproto) levelup = 1 else ifeq (${self_sub},lib_parser) levelup = 1 else ifeq (${self_sub},lib_rewrite) levelup = 1 endif ifeq (${levelup},1) self = $(subst /,,$(dir $(subst ${top_builddir}/,,${CURDIR}))) endif all: ${AM_v_at}${MAKE} -C ${top_builddir} ${self}/ check: ${AM_v_at}${MAKE} -C ${top_builddir} local-check check_subdir=${self_sub} INSTALL_ARGS = bin_SCRIPTS= \ bin_PROGRAMS= \ sbin_PROGRAMS= \ libexec_PROGRAMS= \ man_MANS= \ tools_DATA= \ xsd_DATA= \ INSTALL_EXEC_HOOKS= ifeq (${basedir},lib) INSTALL_ARGS += module_LTLIBRARIES= else ifeq (${basedir},modules) INSTALL_ARGS += lib_LTLIBRARIES= pkginclude_HEADERS= pkgconfig_DATA= ifneq (${self_sub},modules) ifeq (${self_sub},modules_afsocket) INSTALL_ARGS += module_LTLIBRARIES="modules/afsocket/libafsocket.la" INSTALL_ARGS += INSTALL_EXEC_HOOKS=afsocket-install-exec-hook else ifeq (${self_sub},modules_json) INSTALL_ARGS += module_LTLIBRARIES="modules/json/libjson-plugin.la" else ifeq (${self_sub},modules_python) INSTALL_ARGS += module_LTLIBRARIES="modules/python/libmod-python.la" else INSTALL_ARGS += module_LTLIBRARIES=${self}/lib$(word 2,$(subst /, ,${self})).la endif endif else INSTALL_ARGS = endif endif install: ifeq (${INSTALL_ARGS},) @echo "Installing from this directory is not supported." else ${AM_v_at}${MAKE} -C ${top_builddir} install ${INSTALL_ARGS} endif clean dist distcheck: ${AM_v_at}${MAKE} -C ${top_builddir} $@ %: ${AM_v_at}${MAKE} -C ${top_builddir} ${self}/$@ syslog-ng-syslog-ng-4.4.0/NEWS.md000066400000000000000000000267521450431004300164650ustar00rootroot000000000000004.4.0 ===== Read Axoflow's [blog post](https://axoflow.com/axosyslog-release-4-4/) for more details. You can read more about the new features in the AxoSyslog [documentation](https://axoflow.com/docs/axosyslog-core/). ## Highlights ### Sending messages between syslog-ng instances via OTLP/gRPC The `syslog-ng-otlp()` source and destination helps to transfer the internal representation of a log message between syslog-ng instances. In contrary to the `syslog-ng()` (`ewmm()`) drivers, `syslog-ng-otlp()` does not transfer the messages on simple TCP connections, but uses the OpenTelemetry protocol to do so. It is easily scalable (`workers()` option), uses built-in application layer acknowledgement, out of the box supports google service authentication (ADC or ALTS), and gives the possibility of better load balancing. The performance is currently similar to `ewmm()` (OTLP is ~30% quicker) but there is a source side limitation, which will be optimized. We measured 200-300% performance improvement with a PoC optimized code using multiple threads, so stay tuned. Note: The `syslog-ng-otlp()` source is only an alias to the `opentelemetry()` source. This is useful for not needing to open different ports for the syslog-ng messages and other OpenTelemetry messages. The syslog-ng messages are marked with a `@syslog-ng` scope name and the current syslog-ng version as the scope version. Both sources will handle the incoming syslog-ng messages as syslog-ng messages, and all other messages as simple OpenTelemetry messages. ([#4564](https://github.com/syslog-ng/syslog-ng/pull/4564)) ### Grafana Loki destination The `loki()` destination sends messages to Grafana Loki using gRPC. The message format conforms to the documented HTTP endpoint: https://grafana.com/docs/loki/latest/reference/api/#push-log-entries-to-loki Example config: ``` loki( url("localhost:9096") labels( "app" => "$PROGRAM", "host" => "$HOST", ) workers(16) batch-timeout(10000) batch-lines(1000) ); ``` Loki requires monotonic timestamps within the same label-set, which makes it difficult to use the original message timestamp without the possibility of message loss. In case the monotonic property is violated, Loki discards the problematic messages with an error. The source of the timestamps can be configured with the `timestamp()` option (`current`, `received`, `msg`). ([#4631](https://github.com/syslog-ng/syslog-ng/pull/4631)) ### S3 destination The `s3()` destination stores log messages in S3 objects. Minimal config: ``` s3( url("http://localhost:9000") bucket("syslog-ng") access-key("my-access-key") secret-key("my-secret-key") object-key("${HOST}/my-logs") template("${MESSAGE}\n") ); ``` #### Compression Setting `compression(yes)` enables gzip compression, and implicitly adds a `.gz` suffix to the created object's key. Use the `compresslevel()` options to set the level of compression (0-9). #### Rotation based on object size The `max-object-size()` option configures syslog-ng to finish an object if it reaches a certain size. syslog-ng will append an index (`"-1"`, `"-2"`, ...) to the end of the object key when starting a new object after rotation. #### Rotation based on timestamp The `object-key-timestamp()` option can be used to set a datetime related template, which gets appended to the end of the object (e.g. `"${R_MONTH_ABBREV}${R_DAY}"` => `"-Sep25"`). When a log message arrives with a newer timestamp template resolution, the previous timestamped object gets finised and a new one is started with the new timestamp. Backfill messages do not reopen and append the old object, but starts a new object with the key having an index appended to the old object. #### Rotation based on timeout The `flush-grace-period()` option sets the number of minutes to wait for new messages to arrive to objects, if the timeout expires the object is finished, and a new message will start a new with an index appended. #### Upload options The objects are uploaded with the multipart upload API. Chunks are composed locally. When a chunk reaches a certain size (by default 5 MiB), the chunk is uploaded. When an object is finished, the multipart upload gets completed and the chunks are merged by S3. Upload parameters can be configured with the `chunk-size()`, `upload-threads()` and `max-pending-uploads()` options. #### Additional options Additional options include `region()`, `storage-class()` and `canned-acl()`. ([#4624](https://github.com/syslog-ng/syslog-ng/pull/4624)) ## Features * `http()`: Added compression ability for use with metered egress/ingress The new features can be accessed with the following options: * `accept-encoding()` for requesting the compression of HTTP responses form the server. (These are currently not used by syslog-ng, but they still contribute to network traffic.) The available options are `identity` (for no compression), `gzip` or `deflate`. If you want the driver to accept multiple compression types, you can list them separated by commas inside the quotation mark, or write `all`, if you want to enable all available compression types. * `content-compression()` for compressing messages sent by syslog-ng. The available options are `identity` for no compression, `gzip`, or `deflate`. Below you can see a configuration example: ``` destination d_http_compressed{ http(url("127.0.0.1:80"), content-compression("deflate"), accept-encoding("all")); }; ``` ([#4137](https://github.com/syslog-ng/syslog-ng/pull/4137)) * `opensearch`: Added a new destination. It is similar to `elasticsearch-http()`, with the difference that it does not have the `type()` option, which is deprecated and advised not to use. ([#4560](https://github.com/syslog-ng/syslog-ng/pull/4560)) * Added metrics for message delays: a new metric is introduced that measures the delay the messages accumulate while waiting to be delivered by syslog-ng. The measurement is sampled, e.g. syslog-ng would take the very first message in every second and expose its delay as a value of the new metric. There are two new metrics: * syslogng_output_event_delay_sample_seconds -- contains the latency of outgoing messages * syslogng_output_event_delay_sample_age_seconds -- contains the age of the last measurement, relative to the current time. ([#4565](https://github.com/syslog-ng/syslog-ng/pull/4565)) * `metrics-probe`: Added dynamic labelling support via name-value pairs You can use all value-pairs options, like `key()`, `rekey()`, `pair()` or `scope()`, etc... Example: ``` metrics-probe( key("foo") labels( "static-label" => "bar" key(".my_prefix.*" rekey(shift-levels(1))) ) ); ``` ``` syslogng_foo{static_label="bar",my_prefix_baz="almafa",my_prefix_foo="bar",my_prefix_nested_axo="flow"} 4 ``` ([#4610](https://github.com/syslog-ng/syslog-ng/pull/4610)) * `systemd-journal()`: Added support for enabling multiple systemd-journal() sources Using multiple systemd-journal() sources are now possible as long as each source uses a unique systemd namespace. The namespace can be configured with the `namespace()`` option, which has a default value of `"*"`. ([#4553](https://github.com/syslog-ng/syslog-ng/pull/4553)) * `stdout()`: added a new destination that allows you to write messages easily to syslog-ng's stdout. ([#4620](https://github.com/syslog-ng/syslog-ng/pull/4620)) * `network()`: Added `ignore-hostname-mismatch` as a new flag to `ssl-options()`. By specifying `ignore-hostname-mismatch`, you can ignore the subject name of a certificate during the validation process. This means that syslog-ng will only check if the certificate itself is trusted by the current set of trust anchors (e.g. trusted CAs) ignoring the mismatch between the targeted hostname and the certificate subject. ([#4628](https://github.com/syslog-ng/syslog-ng/pull/4628)) ## Bugfixes * `syslog-ng`: fix runtime `undefined symbol: random_choice_generator_parser'` when executing `syslog-ng -V` or using an example plugin ([#4615](https://github.com/syslog-ng/syslog-ng/pull/4615)) * Fix threaded destination crash during a configuration revert Threaded destinations that do not support the `workers()` option crashed while syslog-ng was trying to revert to an old configuration. ([#4588](https://github.com/syslog-ng/syslog-ng/pull/4588)) * `redis()`: fix incrementing seq_num ([#4588](https://github.com/syslog-ng/syslog-ng/pull/4588)) * `python()`: fix crash when using `Persist` or `LogTemplate` without global `python{}` code block in configuration ([#4572](https://github.com/syslog-ng/syslog-ng/pull/4572)) * `mqtt()` destination: fix template option initialization ([#4605](https://github.com/syslog-ng/syslog-ng/pull/4605)) * `opentelemetry`: Fixed error handling in case of insert failure. ([#4583](https://github.com/syslog-ng/syslog-ng/pull/4583)) * pdbtool: add validation for types of `` tags In patterndb, you can add extra name-value pairs following a match with the tags. But the actual value of these name-value pairs were never validated against their types, meaning that an incorrect value could be set using this construct. ([#4621](https://github.com/syslog-ng/syslog-ng/pull/4621)) * `grouping-by()`, `group-lines()`: Fixed a persist name generating error. ([#4478](https://github.com/syslog-ng/syslog-ng/pull/4478)) ## Packaging * debian: Added tzdata-legacy to BuildDeps for recent debian versions. In the recent debian packaging some of the timezone info files moved to a new tzdata-legacy package from the standard tzdata package. ([#4643](https://github.com/syslog-ng/syslog-ng/pull/4643)) * rhel: `contrib/vim` has been removed from the source. ([#4607](https://github.com/syslog-ng/syslog-ng/pull/4607)) ## Other changes * APT packages: Dropped support for Ubuntu Bionic. ([#4648](https://github.com/syslog-ng/syslog-ng/pull/4648)) * `vim`: Syntax highlight file is no longer packaged. vim syntax files where previously installed by the RedHat packages of syslog-ng (but not the Debian ones). These files where sometime lagging behind, so in order to provide a more up-to-date experience on all platforms, regardless of the installation of the syslog-ng package, the vim syntax files have been moved to a dedicated repository [syslog-ng/vim-syslog-ng](https://github.com/syslog-ng/vim-syslog-ng) that can be used using a plugin manager such as [vim-plug](https://github.com/junegunn/vim-plug), [vim-pathogen](https://github.com/tpope/vim-pathogen) or [vundle](https://github.com/VundleVim/Vundle.vim). ([#4607](https://github.com/syslog-ng/syslog-ng/pull/4607)) ## syslog-ng Discord For a bit more interactive discussion, join our Discord server: [![Axoflow Discord Server](https://discordapp.com/api/guilds/1082023686028148877/widget.png?style=banner2)](https://discord.gg/E65kP9aZGm) ## Credits syslog-ng is developed as a community project, and as such it relies on volunteers, to do the work necessarily to produce syslog-ng. Reporting bugs, testing changes, writing code or simply providing feedback are all important contributions, so please if you are a user of syslog-ng, contribute. We would like to thank the following people for their contribution: Alex Becker, Attila Szakacs, Balazs Scheidler, Bálint Horváth, Hofi, László Várady, Romain Tartière, Szilard Parrag syslog-ng-syslog-ng-4.4.0/README.md000066400000000000000000000237541450431004300166450ustar00rootroot00000000000000[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/syslog-ng/syslog-ng?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://github.com/syslog-ng/syslog-ng/actions/workflows/devshell.yml/badge.svg)](https://github.com/syslog-ng/syslog-ng/actions/workflows/devshell.yml) [![Nightly](https://github.com/syslog-ng/syslog-ng/actions/workflows/nightly-release.yml/badge.svg)](https://github.com/syslog-ng/syslog-ng/actions/workflows/nightly-release.yml) [![Binary packages](https://github.com/syslog-ng/syslog-ng/actions/workflows/packages.yml/badge.svg)](https://github.com/syslog-ng/syslog-ng/actions/workflows/packages.yml) [![Compile dbld-images](https://github.com/syslog-ng/syslog-ng/actions/workflows/dbld-images.yml/badge.svg)](https://github.com/syslog-ng/syslog-ng/actions/workflows/dbld-images.yml) syslog-ng ========= syslog-ng is an enhanced log daemon, supporting a wide range of input and output methods: syslog, unstructured text, message queues, databases (SQL and NoSQL alike), and more. ## Quickstart The simplest configuration accepts system logs from /dev/log (from applications or forwarded by systemd) and writes everything to a single file: ``` @version: 4.4 @include "scl.conf" log { source { system(); }; destination { file("/var/log/syslog"); }; }; ``` This one additionally processes logs from the network (TCP/514 by default): ``` @version: 4.4 @include "scl.conf" log { source { system(); network(); }; destination { file("/var/log/syslog"); }; }; ``` This config is designed for structured/application logging, using local submission via JSON, and outputting in key=value format: ``` @version: 4.4 @include "scl.conf" log { source { system(); }; destination { file("/var/log/app.log" template("$(format-welf --subkeys .cim.)\n")); }; }; ``` To submit a structured log using `logger`, you might run: ``` $ logger '@cim: {"name1":"value1", "name2":"value2"}' ``` In which case the resulting message will be: ``` name1=value1 name2=value2 ``` For a brief introduction to configuring the syslog-ng application, see the [quickstart guide](https://support.oneidentity.com/technical-documents/syslog-ng-open-source-edition/administration-guide/the-syslog-ng-ose-quick-start-guide). ## Features * Receive and send [RFC3164](https://tools.ietf.org/html/rfc3164) and [RFC5424](https://tools.ietf.org/html/rfc5424) style syslog messages * Receive and send [JSON](http://json.org/) formatted messages * Work with any kind of unstructured data * Classify and structure logs using built-in parsers (csv-parser(), db-parser(), kv-parser(), etc.) * Normalize, crunch, and process logs as they flow through the system * Hand over logs for further processing using files, message queues (like [AMQP](http://www.amqp.org/)), or databases (like [PostgreSQL](http://www.postgresql.org/) or [MongoDB](http://www.mongodb.org/)) * Forward logs to big data tools (like [Elasticsearch](https://www.elastic.co/), [Apache Kafka](http://kafka.apache.org/), or [Apache Hadoop](http://hadoop.apache.org/)) ### Performance * syslog-ng provides performance levels comparable to a large cluster when running on a single node * In the simplest use case, it scales up to 600-800k messages per second * But classification, parsing, and filtering still produce several tens of thousands of messages per second ### Community * syslog-ng is developed by a community of volunteers, the best way to contact us is via our [github project page](http://github.com/syslog-ng/syslog-ng) project, our [gitter channel](https://gitter.im/syslog-ng/syslog-ng) or our [mailing list](https://lists.balabit.hu/mailman/listinfo/syslog-ng). * syslog-ng is integrated into almost all Linux distributions and BSDs, it is also incorporated into a number of products, see our [powered by syslog-ng](https://syslog-ng.com/powered-by-syslog-ng) page for more details. ### Sponsors [Balabit](http://www.balabit.com/) is the original creator and largest current sponsor of the syslog-ng project. They offer support, professional services, and addons you may be interested in ## Feedback We are really interested to see who uses our software, so if you do use it and you like what you see, please tell us about it. A star on github or an email saying thanks means a lot already, but telling us about your use case, your experience, and things to improve would be much appreciated. Just send an email to feedback (at) syslog-ng.org. *Feedback Powers Open Source.* ## Installation from source Releases and precompiled tarballs are available on [GitHub][github-repo]. [github-repo]: https://github.com/syslog-ng/syslog-ng/releases To compile from source, the easiest is to use `dbld`, a docker based, self-hosted compile/build/release infrastructure within the source tree. See `dbld/README.md` for more information. For the brave souls who want to compile syslog-ng from scratch, the usual drill applies: $ ./configure && make && make install The extra effort in contrast with the dbld based build is the need to fetch and install all build dependencies of syslog-ng (of which there are a few). If you don't have a configure script (because of cloning from git, for example), run `./autogen.sh` to generate it. Some of the functionality of syslog-ng is compiled only if the required development libraries are present. The configure script displays a summary of enabled features at the end of its run. For details, see the [syslog-ng compiling instructions](https://support.oneidentity.com/technical-documents/syslog-ng-open-source-edition/administration-guide/installing-syslog-ng). ## Installation from binaries Binaries are available in various Linux distributions and contributors maintain packages of the latest and greatest syslog-ng version for various OSes. ### Debian/Ubuntu Simply invoke the following command as root: # apt install syslog-ng The latest versions of syslog-ng are available for a wide range of Debian and Ubuntu releases from our APT repository. The packages and the APT repository are provided "as is" without warranty of any kind, on a best-effort level. #### Supported distributions syslog-ng packages are released for the following distribution versions (x86-64): | Distro version | sources.list component name | |---|---| | Ubuntu 23.04 | ubuntu-lunar | | Ubuntu 22.04 | ubuntu-jammy | | Ubuntu 20.04 | ubuntu-focal | | Debian 12 | debian-bookworm | | Debian 11 | debian-bullseye | | Debian 10 | debian-buster | | Debian Unstable | debian-sid | | Debian Testing | debian-testing | #### Adding the APT repository 1. Download and install the release signing key: ``` wget -qO - https://ose-repo.syslog-ng.com/apt/syslog-ng-ose-pub.asc | sudo apt-key add - ``` 2. Add the repository containing the latest build of syslog-ng to the APT sources. For example, stable releases on Ubuntu 22.04: ``` echo "deb https://ose-repo.syslog-ng.com/apt/ stable ubuntu-jammy" | sudo tee -a /etc/apt/sources.list.d/syslog-ng-ose.list ``` 3. Run `apt update` #### Nightly builds Nightly packages are built and released from the git `master` branch everyday. Use `nightly` instead of `stable` in step 2 to use the nightly APT repository. E.g.: ``` echo "deb https://ose-repo.syslog-ng.com/apt/ nightly ubuntu-jammy" | sudo tee -a /etc/apt/sources.list.d/syslog-ng-ose.list ``` Nightly builds can be used for testing purposes (obtaining new features and bugfixes) at the risk of breakage. ### Arch Linux ``` # pacman -S syslog-ng ``` ### Fedora syslog-ng is available as a Fedora package that you can install using dnf: # dnf install syslog-ng You can download packages for the latest versions from [here](https://copr.fedoraproject.org/coprs/czanik/). For instructions on how to install syslog-ng on RPM distributions, see the blog post [Installing latest syslog-ng on RHEL and other RPM distributions](https://syslog-ng.com/blog/installing-latest-syslog-ng-on-rhel-and-other-rpm-distributions/). If you wish to install the latest RPM package that comes from a recent commit in Git for testing purposes, read the blog post, [RPM packages from syslog-ng Git HEAD](https://syslog-ng.com/blog/rpm-packages-from-syslog-ng-git-head/). ### macOS ``` # brew install syslog-ng ``` ### Others Binaries for other platforms are listed on the official [third party page][3rd-party]. [3rd-party]: https://syslog-ng.com/3rd-party-binaries ## Installation from Docker image Binaries are also available as a Docker image. To find out more, check out the blog post, [Your central log server in Docker](https://syslog-ng.com/blog/central-log-server-docker/). There are alternatives to the upstream provided, bare syslog-ng image, such as the [AxoSyslog image](https://github.com/axoflow/axosyslog-docker/pkgs/container/axosyslog) for running syslog-ng in Kubernetes. * [AxoSyslog, a cloud native distribution for syslog-ng announcement](https://axoflow.com/cloud-ready-syslog-ng-images/) * [AxoSyslog log collection for Kubernetes](https://axoflow.com/axosyslog-log-collection-for-kubernetes/) * [AxoSyslog Documentation](https://axoflow.com/docs/axosyslog/) * [GitHub](https://github.com/axoflow/axosyslog-docker) ## Documentation The official documentation of the latest released version of syslog-ng Open Source Edition provided by One Identity is available [here](https://www.syslog-ng.com/technical-documents/doc/syslog-ng-open-source-edition/3.26/administration-guide). For earlier versions, see the syslog-ng [Documentation Page](https://www.syslog-ng.com/technical-documents). An alternative, markdown based, improved, community maintained version of the documentation is available [as AxoSyslog Core documentation](https://axoflow.com/docs/axosyslog-core/). [source code](https://github.com/axoflow/axosyslog-core-docs/) ## Contributing If you would like to contribute to syslog-ng, to fix a bug or create a new module, the [syslog-ng gitbook](https://syslog-ng.gitbooks.io/getting-started/content/) helps you take the first steps to working with the code base. syslog-ng-syslog-ng-4.4.0/VERSION000066400000000000000000000000061450431004300164170ustar00rootroot000000000000004.4.0 syslog-ng-syslog-ng-4.4.0/autogen.sh000077500000000000000000000062331450431004300173600ustar00rootroot00000000000000#!/bin/sh ############################################################################# # Copyright (c) 2007-2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # # This script is needed to setup build environment from checked out # source tree. # SUBMODULES="lib/ivykis" GIT=`which git` # bootstrap syslog-ng itself case `uname -s` in "SunOS") SED="gsed" ;; *) SED="sed" ;; esac include_automake_from_dir_if_exists() { dir=$1 if [ -f "$1/Makefile.am" ]; then grep "include $dir/Makefile.am" Makefile.am if [ "$?" -eq "1" ]; then last_include=$(grep ^include Makefile.am|grep Makefile.am|tail -n 1) $SED -i s@"$last_include"@"$last_include\ninclude $dir/Makefile.am"@g Makefile.am fi fi } autogen_submodules() { origdir=`pwd` submod_initialized=1 for submod in $SUBMODULES; do if [ ! -f $submod/configure.gnu ]; then submod_initialized=0 fi done if [ -n "$GIT" ] && [ -f .gitmodules ] && [ -d .git ] && [ $submod_initialized = 0 ]; then # only clone submodules if none of them present git submodule update --init --recursive fi for submod in $SUBMODULES; do echo "Running autogen in '$submod'..." cd "$submod" if [ -x autogen.sh ]; then ./autogen.sh elif [ -f configure.in ] || [ -f configure.ac ]; then autoreconf -i else echo "Don't know how to bootstrap submodule '$submod'" >&2 exit 1 fi CONFIGURE_OPTS="--disable-shared --enable-static --with-pic" $SED -e "s/@__CONFIGURE_OPTS__@/${CONFIGURE_OPTS}/g" ${origdir}/sub-configure.sh >configure.gnu cd "$origdir" done } if [ -z "$skip_submodules" ]; then autogen_submodules fi # bootstrap syslog-ng itself case `uname -s` in "Darwin") LIBTOOLIZE="glibtoolize" ;; *) LIBTOOLIZE="libtoolize" ;; esac $LIBTOOLIZE --force --copy aclocal -I m4 --install $SED -i -e 's/PKG_PROG_PKG_CONFIG(\[0\.16\])/PKG_PROG_PKG_CONFIG([0.14])/g' aclocal.m4 include_automake_from_dir_if_exists debian include_automake_from_dir_if_exists tgz2build autoheader automake --foreign --add-missing --copy autoconf if grep AX_PREFIX_CONFIG_H configure > /dev/null; then cat < # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. INCLUDE(CheckCSourceCompiles) MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT) SET(_INCLUDE_FILES) FOREACH (it ${_HEADER}) SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") ENDFOREACH (it) SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE " ${_INCLUDE_FILES} int main() { static ${_STRUCT} tmp; if (sizeof(tmp.${_MEMBER})) return 0; return 0; } ") CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) ENDMACRO (CHECK_STRUCT_MEMBER) syslog-ng-syslog-ng-4.4.0/cmake/Modules/ExternalIVYKIS.cmake000066400000000000000000000044721450431004300235750ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # Copyright (c) 2017 Kokan # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# set(LIB_NAME "IVYKIS") if (EXISTS ${PROJECT_SOURCE_DIR}/lib/ivykis/src/include/iv.h.in) ExternalProject_Add( ${LIB_NAME} PREFIX ${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/ INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/ SOURCE_DIR ${PROJECT_SOURCE_DIR}/lib/ivykis/ DOWNLOAD_COMMAND echo BUILD_COMMAND make INSTALL_COMMAND make install CONFIGURE_COMMAND autoreconf -i ${PROJECT_SOURCE_DIR}/lib/ivykis && ${PROJECT_SOURCE_DIR}/lib/ivykis/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/ ) set(${LIB_NAME}_INTERNAL TRUE) set(${LIB_NAME}_INTERNAL_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/include" CACHE STRING "${LIB_NAME} include path") set(${LIB_NAME}_INTERNAL_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/lib/libivykis${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE STRING "${LIB_NAME} library path") set(SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION 1 PARENT_SCOPE) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ivykis-install/lib/ DESTINATION lib USE_SOURCE_PERMISSIONS FILES_MATCHING PATTERN "libivykis${CMAKE_SHARED_LIBRARY_SUFFIX}*") else() set(${LIB_NAME}_INTERNAL FALSE) endif() syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindCurl.cmake000066400000000000000000000025551450431004300225620ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # Copyright (c) 2016 Todd C. Miller # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) libfind_pkg_check_modules(Curl_PKGCONF libcurl) libfind_pkg_detect(Curl libcurl FIND_PATH curl.h PATH_SUFFIXES curl FIND_LIBRARY curl) set(Curl_PROCESS_INCLUDES Curl_INCLUDE_DIR) set(Curl_PROCESS_LIBS Curl_LIBRARY) libfind_process(Curl QUIET) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindESMTP.cmake000066400000000000000000000047151450431004300225450ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Origin: https://raw.githubusercontent.com/ckruse/cforum_cpp/master/cmake/modules/FindESMTP.cmake # - Try to find the libesmtp library # Once done this will define # # ESMTP_FOUND - system has the libesmtp library # ESMTP_CONFIG # ESMTP_INCLUDE_DIR - the libesmtp include directory # ESMTP_LIBRARIES - The libraries needed to use libesmtp # # Based on FindPCRE.cmake # Distributed under the BSD license. if (ESMTP_INCLUDE_DIR AND ESMTP_LIBRARIES) # Already in cache, be silent set(ESMTP_FIND_QUIETLY TRUE) endif (ESMTP_INCLUDE_DIR AND ESMTP_LIBRARIES) find_package(PkgConfig) pkg_check_modules(PC_ESMTP QUIET libesmtp-1.0) if (PC_ESMTP_FOUND) find_path(ESMTP_INCLUDE_DIR NAMES libesmtp.h HINTS ${PC_ESMTP_INCLUDE_DIRS} PATH_SUFFIXES libesmtp) find_library(ESMTP_LIBRARIES NAMES esmtp HINTS ${PC_ESMTP_LIBRARY_DIRS}) else () find_program(ESMTP_CONFIG libesmtp-config) if (ESMTP_CONFIG) find_path(ESMTP_INCLUDE_DIR libesmtp.h ) exec_program(${ESMTP_CONFIG} ARGS --libs OUTPUT_VARIABLE _ESMTP_LIBRARIES) string(REGEX REPLACE "[\r\n]" " " _ESMTP_LIBRARIES "${_ESMTP_LIBRARIES}") set (ESMTP_LIBRARIES ${_ESMTP_LIBRARIES} CACHE STRING "The libraries needed for ESMTP") endif (ESMTP_CONFIG) endif (PC_ESMTP_FOUND) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ESMTP DEFAULT_MSG ESMTP_LIBRARIES ESMTP_INCLUDE_DIR) mark_as_advanced(ESMTP_LIBRARIES ESMTP_INCLUDE_DIR) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindFLEX.cmake000066400000000000000000000166351450431004300224170ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # - Find flex executable and provides a macro to generate custom build rules # # The module defines the following variables: # FLEX_FOUND - true is flex executable is found # FLEX_EXECUTABLE - the path to the flex executable # FLEX_VERSION - the version of flex # FLEX_LIBRARIES - The flex libraries # FLEX_INCLUDE_DIRS - The path to the flex headers # # The minimum required version of flex can be specified using the # standard syntax, e.g. find_package(FLEX 2.5.13) # # # If flex is found on the system, the module provides the macro: # FLEX_TARGET(Name FlexInput FlexOutput [COMPILE_FLAGS ]) # which creates a custom command to generate the file from # the file. If COMPILE_FLAGS option is specified, the next # parameter is added to the flex command line. Name is an alias used to # get details of this custom command. Indeed the macro defines the # following variables: # FLEX_${Name}_DEFINED - true is the macro ran successfully # FLEX_${Name}_OUTPUTS - the source file generated by the custom rule, an # alias for FlexOutput # FLEX_${Name}_INPUT - the flex source file, an alias for ${FlexInput} # # Flex scanners oftenly use tokens defined by Bison: the code generated # by Flex depends of the header generated by Bison. This module also # defines a macro: # ADD_FLEX_BISON_DEPENDENCY(FlexTarget BisonTarget) # which adds the required dependency between a scanner and a parser # where and are the first parameters of # respectively FLEX_TARGET and BISON_TARGET macros. # # ==================================================================== # Example: # # find_package(BISON) # find_package(FLEX) # # BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp) # FLEX_TARGET(MyScanner lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) # ADD_FLEX_BISON_DEPENDENCY(MyScanner MyParser) # # include_directories(${CMAKE_CURRENT_BINARY_DIR}) # add_executable(Foo # Foo.cc # ${BISON_MyParser_OUTPUTS} # ${FLEX_MyScanner_OUTPUTS} # ) # ==================================================================== #============================================================================= # Copyright 2009 Kitware, Inc. # Copyright 2006 Tristan Carel # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_program(FLEX_EXECUTABLE NAMES flex win_flex DOC "path to the flex executable") mark_as_advanced(FLEX_EXECUTABLE) find_library(FL_LIBRARY NAMES fl DOC "Path to the fl library") find_path(FLEX_INCLUDE_DIR FlexLexer.h DOC "Path to the flex headers") mark_as_advanced(FL_LIBRARY FLEX_INCLUDE_DIR) set(FLEX_INCLUDE_DIRS ${FLEX_INCLUDE_DIR}) set(FLEX_LIBRARIES ${FL_LIBRARY}) if(FLEX_EXECUTABLE) execute_process(COMMAND ${FLEX_EXECUTABLE} --version OUTPUT_VARIABLE FLEX_version_output ERROR_VARIABLE FLEX_version_error RESULT_VARIABLE FLEX_version_result OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT ${FLEX_version_result} EQUAL 0) if(FLEX_FIND_REQUIRED) message(SEND_ERROR "Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}") else() message("Command \"${FLEX_EXECUTABLE} --version\" failed with output:\n${FLEX_version_output}\n${FLEX_version_error}\nFLEX_VERSION will not be available") endif() else() # older versions of flex printed "/full/path/to/executable version X.Y" # newer versions use "basename(executable) X.Y" get_filename_component(FLEX_EXE_NAME_WE "${FLEX_EXECUTABLE}" NAME_WE) get_filename_component(FLEX_EXE_EXT "${FLEX_EXECUTABLE}" EXT) string(REGEX REPLACE "^.*${FLEX_EXE_NAME_WE}(${FLEX_EXE_EXT})?\"? (version )?([0-9]+[^ ]*)( .*)?$" "\\3" FLEX_VERSION "${FLEX_version_output}") unset(FLEX_EXE_EXT) unset(FLEX_EXE_NAME_WE) endif() #============================================================ # FLEX_TARGET (public macro) #============================================================ # macro(FLEX_TARGET Name Input Output OutputHeader) set(FLEX_TARGET_usage "FLEX_TARGET( [COMPILE_FLAGS ]") if(${ARGC} GREATER 3) if(${ARGC} EQUAL 6) if("${ARGV4}" STREQUAL "COMPILE_FLAGS") set(FLEX_EXECUTABLE_opts "${ARGV5}") separate_arguments(FLEX_EXECUTABLE_opts) else() message(SEND_ERROR ${FLEX_TARGET_usage}) endif() endif() endif() add_custom_command( OUTPUT ${Output} ${OutputHeader} COMMAND ${FLEX_EXECUTABLE} ARGS ${FLEX_EXECUTABLE_opts} -o${Output} --header-file=${OutputHeader} ${Input} COMMAND mv lex.yy.c ${Output} COMMAND mv lex.yy.h ${OutputHeader} DEPENDS ${Input} COMMENT "[FLEX][${Name}] Building scanner with flex ${FLEX_VERSION}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set(FLEX_${Name}_DEFINED TRUE) set(FLEX_${Name}_OUTPUTS ${Output}) set(FLEX_${Name}_INPUT ${Input}) set(FLEX_${Name}_COMPILE_FLAGS ${FLEX_EXECUTABLE_opts}) endmacro() #============================================================ #============================================================ # ADD_FLEX_BISON_DEPENDENCY (public macro) #============================================================ # macro(ADD_FLEX_BISON_DEPENDENCY FlexTarget BisonTarget) if(NOT FLEX_${FlexTarget}_OUTPUTS) message(SEND_ERROR "Flex target `${FlexTarget}' does not exists.") endif() if(NOT BISON_${BisonTarget}_OUTPUT_HEADER) message(SEND_ERROR "Bison target `${BisonTarget}' does not exists.") endif() set_source_files_properties(${FLEX_${FlexTarget}_OUTPUTS} PROPERTIES OBJECT_DEPENDS ${BISON_${BisonTarget}_OUTPUT_HEADER}) endmacro() #============================================================ endif() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(FLEX REQUIRED_VARS FLEX_EXECUTABLE VERSION_VAR FLEX_VERSION) # FindFLEX.cmake ends here syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindGLIB.cmake000066400000000000000000000163521450431004300223720ustar00rootroot00000000000000# - Try to find Glib and its components (gio, gobject etc) # Once done, this will define # # GLIB_FOUND - system has Glib # GLIB_INCLUDE_DIRS - the Glib include directories # GLIB_LIBRARIES - link these to use Glib # # Optionally, the COMPONENTS keyword can be passed to find_package() # and Glib components can be looked for. Currently, the following # components can be used, and they define the following variables if # found: # # gio: GLIB_GIO_LIBRARIES # gobject: GLIB_GOBJECT_LIBRARIES # gmodule: GLIB_GMODULE_LIBRARIES # gthread: GLIB_GTHREAD_LIBRARIES # # Note that the respective _INCLUDE_DIR variables are not set, since # all headers are in the same directory as GLIB_INCLUDE_DIRS. # # Copyright (C) 2012 Raphael Kubo da Costa # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS # IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Source https://raw.githubusercontent.com/WebKit/webkit/master/Source/cmake/FindGLIB.cmake find_package(PkgConfig) pkg_check_modules(PC_GLIB QUIET glib-2.0) find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS} ) # Files in glib's main include path may include glibconfig.h, which, # for some odd reason, is normally in $LIBDIR/glib-2.0/include. get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/include ) find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0 ) set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) # Version detection if (EXISTS "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h") file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS) string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}") string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}") set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}") endif () # Additional Glib components. We only look for libraries, as not all of them # have corresponding headers and all headers are installed alongside the main # glib ones. foreach (_component ${GLIB_FIND_COMPONENTS}) if (${_component} STREQUAL "gio") find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES) elseif (${_component} STREQUAL "gobject") find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES) elseif (${_component} STREQUAL "gmodule") find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES) elseif (${_component} STREQUAL "gthread") find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR}) set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES) elseif (${_component} STREQUAL "gio-unix") # gio-unix is compiled as part of the gio library, but the include paths # are separate from the shared glib ones. Since this is currently only used # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config. pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0) endif () endforeach () include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS} VERSION_VAR GLIB_VERSION) mark_as_advanced( GLIBCONFIG_INCLUDE_DIR GLIB_GIO_LIBRARIES GLIB_GIO_UNIX_LIBRARIES GLIB_GMODULE_LIBRARIES GLIB_GOBJECT_LIBRARIES GLIB_GTHREAD_LIBRARIES GLIB_INCLUDE_DIR GLIB_INCLUDE_DIRS GLIB_LIBRARIES ) if (GLIB_FOUND AND NOT TARGET GLib::GLib) add_library(GLib::GLib UNKNOWN IMPORTED) set_target_properties(GLib::GLib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLIB_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${GLIB_LIBRARIES}" INTERFACE_COMPILE_DEFINITIONS "${GLIB_COMPILE_DEFINITIONS}" IMPORTED_LOCATION "${GLIB_LIBRARIES}" ) endif () if (EXISTS "${GLIB_GIO_LIBRARIES}" AND NOT TARGET GLib::GIO) add_library(GLib::GIO UNKNOWN IMPORTED) set_target_properties(GLib::GIO PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLIB_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${GLIB_GIO_LIBRARIES}" IMPORTED_LOCATION "${GLIB_GIO_LIBRARIES}" ) endif () if (EXISTS "${GLIB_GOBJECT_LIBRARIES}" AND NOT TARGET GLib::GObject) add_library(GLib::GObject UNKNOWN IMPORTED) set_target_properties(GLib::GObject PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLIB_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${GLIB_GOBJECT_LIBRARIES}" IMPORTED_LOCATION "${GLIB_GOBJECT_LIBRARIES}" ) endif () if (EXISTS "${GLIB_GMODULE_LIBRARIES}" AND NOT TARGET GLib::GModule) add_library(GLib::GModule UNKNOWN IMPORTED) set_target_properties(GLib::GModule PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLIB_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${GLIB_GMODULE_LIBRARIES}" IMPORTED_LOCATION "${GLIB_GMODULE_LIBRARIES}" ) endif () if (EXISTS "${GLIB_GTHREAD_LIBRARIES}" AND NOT TARGET GLib::GThread) add_library(GLib::GThread UNKNOWN IMPORTED) set_target_properties(GLib::GThread PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLIB_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${GLIB_GTHREAD_LIBRARIES}" IMPORTED_LOCATION "${GLIB_GTHREAD_LIBRARIES}" ) endif () syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindGettext.cmake000066400000000000000000000046021450431004300232740ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Origin: https://fossies.org/linux/darktable/cmake/modules/FindGettext.cmake # - Try to find Gettext # Once done, this will define # # Gettext_FOUND - system has Gettext # Gettext_INCLUDE_DIRS - the Gettext include directories # Gettext_LIBRARIES - link these to use Gettext # # See documentation on how to write CMake scripts at # http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries include(LibFindMacros) # On Linux there is no pkgconfig script, but with this we force # Gettext_PKGCONF_INCLUDE_DIRS to "". The situation is the same on # FreeBSD and OS X: Gettext comes without a pkgconfig file. if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD|Darwin)$") set(Gettext_PKGCONF_INCLUDE_DIRS "") else(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD|Darwin)$") libfind_pkg_check_modules(Gettext_PKGCONF Gettext) endif(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD|Darwin)$") if(WIN32 OR APPLE) set(Gettext_LIBRARY_SEARCH_DIRS /opt/local/lib /sw/local/lib ) find_library(Gettext_LIBRARY NAMES intl PATHS ${Gettext_LIBRARY_SEARCH_DIRS} HINTS ${Gettext_PKGCONF_LIBRARY_DIRS} ) set(Gettext_PROCESS_LIBS Gettext_LIBRARY) endif() find_path(Gettext_INCLUDE_DIR NAMES libintl.h HINTS ${Gettext_PKGCONF_INCLUDE_DIRS} PATHS /opt/local/include ) set(Gettext_PROCESS_INCLUDES Gettext_INCLUDE_DIR) libfind_process(Gettext) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindGradle.cmake000066400000000000000000000032651450431004300230520ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(FindPackageHandleStandardArgs) find_program(GRADLE_EXECUTABLE NAMES gradle PATHS $ENV{GRADLE_HOME}/bin NO_CMAKE_FIND_ROOT_PATH) if (GRADLE_EXECUTABLE) execute_process(COMMAND gradle --version COMMAND grep Gradle COMMAND head -1 COMMAND sed "s/.*\\ \\(.*\\)/\\1/" OUTPUT_VARIABLE GRADLE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() find_package_handle_standard_args(Gradle FOUND_VAR GRADLE_FOUND REQUIRED_VARS GRADLE_EXECUTABLE VERSION_VAR GRADLE_VERSION) mark_as_advanced(GRADLE_EXECUTABLE) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindHiredis.cmake000066400000000000000000000040261450431004300232370ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # FindHiredis.cmake - Try to find the Hiredis library # Once done this will define # # HIREDIS_FOUND - System has Hiredis # HIREDIS_INCLUDE_DIR - The Hiredis include directory # HIREDIS_LIBRARIES - The libraries needed to use Hiredis # HIREDIS_DEFINITIONS - Compiler switches required for using Hiredis # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_RARY() calls FIND_PACKAGE(PkgConfig) PKG_SEARCH_MODULE(PC_HIREDIS hiredis) SET(HIREDIS_DEFINITIONS ${PC_HIREDIS_CFLAGS_OTHER}) FIND_PATH(HIREDIS_INCLUDE_DIR NAMES hiredis/hiredis.h HINTS ${PC_HIREDIS_INCLUDEDIR} ${PC_HIREDIS_INCLUDE_DIRS} PATH_SUFFIXES hiredis ) FIND_LIBRARY(HIREDIS_LIBRARIES NAMES hiredis HINTS ${PC_HIREDIS_DIR} ${PC_HIREDIS_LIBRARY_DIRS} ) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Hiredis DEFAULT_MSG HIREDIS_LIBRARIES HIREDIS_INCLUDE_DIR) MARK_AS_ADVANCED(HIREDIS_INCLUDE_DIR HIREDIS_LIBRARIES) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindIVYKIS.cmake000066400000000000000000000030451450431004300226660ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) libfind_pkg_check_modules(IVYKIS_PKGCONF ivykis) libfind_pkg_detect(IVYKIS ivykis FIND_PATH iv.h FIND_LIBRARY ivykis) set(IVYKIS_PROCESS_INCLUDES IVYKIS_INCLUDE_DIR) set(IVYKIS_PROCESS_LIBS IVYKIS_LIBRARY) libfind_process(IVYKIS) check_symbol_exists(iv_work_pool_submit_continuation "iv_work.h" SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION) set(SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION "${SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION}" PARENT_SCOPE) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindInotify.cmake000066400000000000000000000062111450431004300232670ustar00rootroot00000000000000#.rest: # FindInotify # -------------- # # Try to find inotify on this system. This finds: # - libinotiy on Unix like systems, or # - the kernel's inotify on Linux systems. # # This will define the following variables: # # ``Inotify_FOUND`` # True if inotify is available # ``Inotify_LIBRARIES`` # This has to be passed to target_link_libraries() # ``Inotify_INCLUDE_DIRS`` # This has to be passed to target_include_directories() # # On Linux, the libraries and include directories are empty, # even though Inotify_FOUND may be set to TRUE. This is because # no special includes or libraries are needed. On other systems # these may be needed to use inotify. #============================================================================= # Copyright 2016 Tobias C. Berner # Copyright 2017 Adriaan de Groot # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= find_path(Inotify_INCLUDE_DIRS sys/inotify.h) if(Inotify_INCLUDE_DIRS) # On Linux there is no library to link against, on the BSDs there is. # On the BSD's, inotify is implemented through a library, libinotify. if( CMAKE_SYSTEM_NAME MATCHES "Linux") set(Inotify_FOUND TRUE) set(Inotify_INCLUDE_DIRS "") else() find_library(Inotify_LIBRARIES NAMES inotify) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Inotify FOUND_VAR Inotify_FOUND REQUIRED_VARS Inotify_LIBRARIES Inotify_INCLUDE_DIRS ) mark_as_advanced(Inotify_LIBRARIES Inotify_INCLUDE_DIRS) include(FeatureSummary) set_package_properties(Inotify PROPERTIES URL "https://github.com/libinotify-kqueue/" DESCRIPTION "inotify API on the *BSD family of operating systems." ) endif() else() set(Inotify_FOUND FALSE) endif() mark_as_advanced(Inotify_LIBRARIES Inotify_INCLUDE_DIRS) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindJSONC.cmake000066400000000000000000000034271450431004300225300ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Origin: https://github.com/SirCmpwn/sway/blob/master/CMake/FindJsonC.cmake # - Find json-c # Find the json-c libraries # # This module defines the following variables: # JSONC_FOUND - True if JSONC is found # JSONC_LIBRARY - JSONC libraries # JSONC_INCLUDE_DIR - JSONC include directories # find_package(PkgConfig) pkg_check_modules(PC_JSONC QUIET JSONC) find_path(JSONC_INCLUDE_DIR NAMES json.h HINTS ${PC_JSONC_INCLUDE_DIRS} PATH_SUFFIXES json-c json) find_library(JSONC_LIBRARY NAMES json-c HINTS ${PC_JSONC_LIBRARY_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(JSONC DEFAULT_MSG JSONC_LIBRARY JSONC_INCLUDE_DIR) mark_as_advanced(JSONC_LIBRARY JSONC_INCLUDE_DIR) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindLIBBPF.cmake000066400000000000000000000032061450431004300226050ustar00rootroot00000000000000############################################################################# # Copyright (c) 2023 Attila Szakacs # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# find_package(PkgConfig) pkg_check_modules(LIBBPF QUIET libbpf>=1.0.1) if (LIBBPF_FOUND) find_program(BPF_CC clang) find_program(BPFTOOL bpftool) if ((NOT BPF_CC) OR (NOT BPFTOOL)) set(LIBBPF_FOUND FALSE) else () execute_process(COMMAND ${BPF_CC} -print-file-name=include OUTPUT_VARIABLE CLANG_INCLUDES OUTPUT_STRIP_TRAILING_WHITESPACE) pkg_get_variable(LIBBPF_INCLUDE_DIRS_RAW libbpf includedir) set(BPF_CFLAGS -nostdinc -isystem ${CLANG_INCLUDES} -target bpf -I${CMAKE_CURRENT_BINARY_DIR} -I${LIBBPF_INCLUDE_DIRS_RAW} -fPIC -O2 -g) endif () endif () syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindLIBCAP.cmake000066400000000000000000000030621450431004300226010ustar00rootroot00000000000000############################################################################# # Copyright (c) 2018 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) include(FindPackageHandleStandardArgs) find_package(PkgConfig) pkg_check_modules(PC_LIBCAP libcap QUIET) find_path(LIBCAP_INCLUDE_DIR NAMES sys/capability.h HINTS ${PC_LIBCAP_INCLUDE_DIRS}) find_library(LIBCAP_LIBRARY NAMES cap HINTS ${PC_LIBCAP_LIBRARY_DIRS}) add_library(libcap INTERFACE) if (NOT PC_LIBCAP_FOUND) return() endif() target_include_directories(libcap INTERFACE ${LIBCAP_INCLUDE_DIR}) target_link_libraries(libcap INTERFACE ${LIBCAP_LIBRARY}) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindLIBDBI.cmake000066400000000000000000000042001450431004300225670ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Origin: https://github.com/hhetter/smbtatools/blob/master/FindLibDBI.cmake # Try to find libdbi # Once done this will define: # LIBDBI_FOUND - System has Libdbi # LIBDBI_INCLUDE_DIRS - libdbi include directories # LIBDBI_LIBRARIES - libraries need to use libdbi # LIBDBI_DEFINITIONS - compiler switches for libdbi # 2011 by Holger Hetterich # find_package(PkgConfig) pkg_check_modules(PC_LIBDBI QUIET libdbi) set(LIBDBI_DEFINITIONS ${PC_LIBDBI_CFLAGS_OTHER}) find_path(LIBDBI_INCLUDE_DIR dbi.h HINTS ${PC_LIBDBI_INCLUDE_DIR} ${PC_LIBDBI_INCLUDE_DIRS} PATH_SUFFIXES dbi ) find_library(LIBDBI_LIBRARY NAMES dbi libdbi HINTS ${PC_LIBDBI_LIBDIR} ${PC_LIBDBI_LIBRARY_DIRS}) set(LIBDBI_LIBRARIES ${LIBDBI_LIBRARY} ) set(LIBDBI_INCLUDE_DIRS ${LIBDBI_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRES arguments and set LIBDBI_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(LIBDBI DEFAULT_MSG LIBDBI_LIBRARY LIBDBI_INCLUDE_DIR) mark_as_advanced(LIBDBI_INCLUDE_DIR LIBDBI_LIBRARY) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindLIBMAXMINDDB.cmake000066400000000000000000000026271450431004300235070ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# find_path(LIBMAXMINDDB_INCLUDE_DIR NAMES maxminddb.h) find_library(LIBMAXMINDDB_LIBRARY NAMES maxminddb maxminddb.a) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBMAXMINDDB DEFAULT_MSG LIBMAXMINDDB_LIBRARY LIBMAXMINDDB_INCLUDE_DIR ) mark_as_advanced( LIBMAXMINDDB_LIBRARY LIBMAXMINDDB_INCLUDE_DIR ) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindLIBNET.cmake000066400000000000000000000052401450431004300226240ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # - Try to find the libnet library # Once done this will define # # LIBNET_FOUND - system has the libnet library # LIBNET_CONFIG # LIBNET_LIBRARIES - The libraries needed to use libnet # # Based on FindESMTP.cmake # Distributed under the BSD license. if (LIBNET_LIBRARIES) # Already in cache, be silent set(LIBNET_FIND_QUIETLY TRUE) endif (LIBNET_LIBRARIES) FIND_PROGRAM(LIBNET_CONFIG libnet-config) add_library(libnet INTERFACE) IF (LIBNET_CONFIG) EXEC_PROGRAM(${LIBNET_CONFIG} ARGS --libs OUTPUT_VARIABLE _LIBNET_LIBRARIES) EXEC_PROGRAM(${LIBNET_CONFIG} ARGS --cflags OUTPUT_VARIABLE _LIBNET_CFLAGS) string(REGEX REPLACE "[\r\n]" " " _LIBNET_LIBRARIES "${_LIBNET_LIBRARIES}") string(REGEX REPLACE "[\r\n]" " " _LIBNET_CFLAGS "${_LIBNET_CFLAGS}") set (LIBNET_LIBRARIES ${_LIBNET_LIBRARIES} CACHE STRING "The libraries needed for LIBNET") set (LIBNET_CFLAGS ${_LIBNET_CFLAGS} CACHE STRING "The compiler switches needed for LIBNET") set (LIBNET_FOUND TRUE CACHE BOOL "LibNet is found") # this is due to libnet-config provides old fashined defines, which triggers warning on newer systems # for details see: https://github.com/libnet/libnet/pull/71 set (LIBNET_CFLAGS "${LIBNET_CFLAGS} -D_DEFAULT_SOURCE") target_include_directories(libnet INTERFACE ${LIBNET_CFLAGS}) target_link_libraries(libnet INTERFACE ${LIBNET_LIBRARIES}) ELSE(LIBNET_CONFIG) set (LIBNET_FOUND FALSE CACHE BOOL "LibNet is found") ENDIF() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBNET DEFAULT_MSG LIBNET_LIBRARIES LIBNET_CFLAGS LIBNET_FOUND) MARK_AS_ADVANCED(LIBNET_LIBRARIES LIBNET_CFLAGS) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindNETSNMP.cmake000066400000000000000000000043051450431004300227740ustar00rootroot00000000000000############################################################################# # Copyright (c) 2019 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # - Try to find the net-snmp library # Once done this will define # # NETSNMP_FOUND - system has the net-snmp library # NETSNMP_CFLAGS - # NETSNMP_LIBS - the libraries needed to use net-snmp # if (NETSNMP_LIBS) # Already in cache, be silent set(NETSNMP_FIND_QUIETLY TRUE) endif (NETSNMP_LIBS) FIND_PROGRAM(NETSNMP_CONFIG_BIN net-snmp-config) IF (NETSNMP_CONFIG_BIN) EXEC_PROGRAM(${NETSNMP_CONFIG_BIN} ARGS --cflags OUTPUT_VARIABLE _NETSNMP_CFLAGS) EXEC_PROGRAM(${NETSNMP_CONFIG_BIN} ARGS --libs OUTPUT_VARIABLE _NETSNMP_LIBS) string(REGEX REPLACE "[\"\r\n]" " " _NETSNMP_CFLAGS "${_NETSNMP_CFLAGS}") string(REGEX REPLACE "[\"\r\n]" " " _NETSNMP_LIBS "${_NETSNMP_LIBS}") set (NETSNMP_CFLAGS ${_NETSNMP_CFLAGS} CACHE STRING "CFLAGS for net-snmp lib") set (NETSNMP_LIBS ${_NETSNMP_LIBS} CACHE STRING "linker options for net-snmp lib") set (NETSNMP_FOUND TRUE CACHE BOOL "net-snmp is found") ELSE() set (NETSNMP_FOUND FALSE CACHE BOOL "net-snmp is not found") ENDIF() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(NETSNMP DEFAULT_MSG NETSNMP_LIBS NETSNMP_CFLAGS NETSNMP_FOUND) MARK_AS_ADVANCED(NETSNMP_LIBS) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindPackageMessage.cmake000066400000000000000000000057471450431004300245230ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # FIND_PACKAGE_MESSAGE( "message for user" "find result details") # # This macro is intended to be used in FindXXX.cmake modules files. # It will print a message once for each unique find result. # This is useful for telling the user where a package was found. # The first argument specifies the name (XXX) of the package. # The second argument specifies the message to display. # The third argument lists details about the find result so that # if they change the message will be displayed again. # The macro also obeys the QUIET argument to the find_package command. # # Example: # # if(X11_FOUND) # FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" # "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") # else() # ... # endif() #============================================================================= # Copyright 2008-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) function(FIND_PACKAGE_MESSAGE pkg msg details) # Avoid printing a message repeatedly for the same find result. if(NOT ${pkg}_FIND_QUIETLY) string(REGEX REPLACE "[\n]" "" details "${details}") set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") # The message has not yet been printed. message(STATUS "${msg}") # Save the find details in the cache to avoid printing the same # message again. set("${DETAILS_VAR}" "${details}" CACHE INTERNAL "Details about finding ${pkg}") endif() endif() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindRabbitMQ.cmake000066400000000000000000000023701450431004300233110ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # Copyright (c) 2017 Kokan # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) # Find the include directories libfind_pkg_detect(RabbitMQ librabbitmq FIND_PATH amqp.h FIND_LIBRARY rabbitmq) libfind_process(RabbitMQ) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindResolv.cmake000066400000000000000000000023541450431004300231240ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# find_library (RESOLV_LIBRARIES resolv) add_library(resolv INTERFACE) if (NOT RESOLV_LIBRARIES) return() endif() target_link_libraries(resolv INTERFACE ${RESOLV_LIBRARIES}) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindRiemannClient.cmake000066400000000000000000000036371450431004300244070ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) libfind_pkg_detect(Riemann riemann-client FIND_PATH riemann/event.h FIND_LIBRARY riemann-client) if (NOT Riemann_LIBRARY) libfind_pkg_detect(Riemann riemann-client FIND_PATH riemann/event.h FIND_LIBRARY riemann-client-openssl) endif() if (NOT Riemann_LIBRARY) libfind_pkg_detect(Riemann riemann-client FIND_PATH riemann/event.h FIND_LIBRARY riemann-client-no-tls) endif() if (Riemann_LIBRARY) message(STATUS "Found Riemann client: ${Riemann_LIBRARY}") endif() set(Riemann_PROCESS_INCLUDES Riemann_INCLUDE_DIR) set(Riemann_PROCESS_LIBS Riemann_LIBRARY) # silence warnings libfind_process(Riemann QUIET) set(CMAKE_EXTRA_INCLUDE_FILES "event.h") set(CMAKE_REQUIRED_INCLUDES "${Riemann_INCLUDE_DIR}/riemann/") set(CMAKE_REQUIRED_LIBRARIES "${Riemann_LIBRARIES}") check_type_size(RIEMANN_EVENT_FIELD_TIME_MICROS RIEMANN_MICROSECONDS) syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindWRAP.cmake000066400000000000000000000035771450431004300224330ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Find wrap library # # Released under BSD license # # WRAP_INCLUDE_DIRS - where to find tcpd.h, etc # WRAP_LIBRARIES - Lists of libraries when using libwrap # WRAP_FOUND - True if wrap found INCLUDE(FindPackageHandleStandardArgs) # Look for the header file FIND_PATH(WRAP_INCLUDE_DIR NAMES tcpd.h) MARK_AS_ADVANCED(WRAP_INCLUDE_DIR) # Look for the library SET(WRAP_LIBS wrap) FIND_LIBRARY(WRAP_LIBRARY NAMES ${WRAP_LIBS}) MARK_AS_ADVANCED(WRAP_LIBRARY) FIND_PACKAGE_HANDLE_STANDARD_ARGS(WRAP REQUIRED_VARS WRAP_LIBRARY WRAP_INCLUDE_DIR) # Copy the result to output variables IF(WRAP_FOUND) SET(WRAP_LIBRARIES ${WRAP_LIBRARY}) SET(WRAP_INCLUDE_DIRS ${WRAP_INCLUDE_DIR}) ELSE(WRAP_FOUND) SET(WRAP_LIBS) SET(WRAP_LIBRARY) SET(WRAP_LIBRARIES) SET(WRAP_INCLUDE_DIR) SET(WRAP_INCLUDE_DIRS) ENDIF(WRAP_FOUND) syslog-ng-syslog-ng-4.4.0/cmake/Modules/Findcriterion.cmake000066400000000000000000000027351450431004300236530ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) libfind_pkg_check_modules(CRITERION_PKGCONF criterion) libfind_pkg_detect(CRITERION criterion FIND_PATH criterion/criterion.h FIND_LIBRARY criterion) set(CRITERION_PROCESS_INCLUDES CRITERION_INCLUDE_DIR) set(CRITERION_PROCESS_LIBS CRITERION_LIBRARY) libfind_process(CRITERION) if (NOT CRITERION_FOUND) MESSAGE(WARNING "Criterion not found: some unit tests will not be compiled") endif() syslog-ng-syslog-ng-4.4.0/cmake/Modules/FindgRPC.cmake000066400000000000000000000246661450431004300224570ustar00rootroot00000000000000# ~~~ # Copyright 2019 Google LLC # # 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 # # https://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. # ~~~ #[=======================================================================[.rst: FindgRPC -------- Locate and configure the ``gRPC`` library. The following variables can be set and are optional: ``gRPC_DEBUG`` Show debug messages. ``gRPC_USE_STATIC_LIBS`` Set to ON to force the use of the static libraries. Default is OFF. Defines the following variables: ``gRPC_FOUND`` Found the gRPC library ``gRPC_VERSION`` Version of package found. The following ``IMPORTED`` targets are also defined: ``gRPC::grpc++`` The gRPC C++ library. ``gRPC::grpc`` The gRPC C core library. ``gRPC::cpp_plugin`` The C++ plugin for the Protobuf protoc compiler. The following cache variables are also available to set or use: Example: .. code-block:: cmake find_package(gRPC REQUIRED) add_executable(bar bar.cc) target_link_libraries(bar PRIVATE gRPC::grpc++) #]=======================================================================] if (gRPC_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "gRPC_USE_STATIC_LIBS = ${gRPC_USE_STATIC_LIBS}" " gRPC_FOUND = ${gRPC_FOUND}") endif () # gRPC always requires Thread support. find_package(Threads REQUIRED) # Load the module to find protobuf with proper targets. Do not use # `find_package()` because we (have to) install this module in non-standard # locations. list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") find_package(Protobuf CONFIG QUIET) if (NOT Protobuf_FOUND) find_package(Protobuf) endif () # The gRPC::grpc_cpp_plugin target is sometimes defined, but without a # IMPORTED_LOCATION function (_grpc_fix_grpc_cpp_plugin_target) # The target may already exist, do not create it again if it does. if (NOT TARGET gRPC::grpc_cpp_plugin) add_executable(gRPC::grpc_cpp_plugin IMPORTED) endif () get_target_property(_gRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin IMPORTED_LOCATION) if (gRPC_DEBUG) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "LOCATION=${_gRPC_CPP_PLUGIN_EXECUTABLE}") endif () # Even if the target exists, gRPC CMake support files do not define the # executable for the imported target (at least they do not in v1.19.1), so # we need to define it ourselves. if (NOT _gRPC_CPP_PLUGIN_EXECUTABLE) find_program(_gRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin DOC "The gRPC C++ plugin for protoc") mark_as_advanced(_gRPC_CPP_PLUGIN_EXECUTABLE) if (_gRPC_CPP_PLUGIN_EXECUTABLE) set_property( TARGET gRPC::grpc_cpp_plugin PROPERTY IMPORTED_LOCATION ${_gRPC_CPP_PLUGIN_EXECUTABLE}) else () set(gRPC_FOUND "grpc_cpp_plugin-NOTFOUND") endif () endif () endfunction () # First try to use the `gRPCConfig.cmake` or `grpc-config.cmake` file if it was # installed. This is common on systems (or package managers) where gRPC was # compiled and installed with `CMake`. find_package(gRPC NO_MODULE QUIET) if (gRPC_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "NO_MODULE result gRPC_FOUND = ${gRPC_FOUND}") endif () if (gRPC_FOUND) _grpc_fix_grpc_cpp_plugin_target() return() endif () include(SelectLibraryConfigurations) # Internal function: search for normal library as well as a debug one if the # debug one is specified also include debug/optimized keywords in *_LIBRARIES # variable function (_gRPC_find_library name filename) if (${name}_LIBRARY) # Use result recorded by a previous call. return() else () find_library(${name}_LIBRARY_RELEASE NAMES ${filename}) mark_as_advanced(${name}_LIBRARY_RELEASE) find_library(${name}_LIBRARY_DEBUG NAMES ${filename}d ${filename}) mark_as_advanced(${name}_LIBRARY_DEBUG) select_library_configurations(${name}) if (gRPC_DEBUG) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "${name} ${filename} RELEASE=${${name}_LIBRARY}" " DEBUG=${${name}_LIBRARY_DEBUG} DEFAULT=${${name}_LIBRARY}" ) endif () set(${name}_LIBRARY "${${name}_LIBRARY}" PARENT_SCOPE) endif () endfunction () # # Main # # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES if (_gRPC_USE_STATIC_LIBS) set(_gRPC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if (WIN32) set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) else () set(CMAKE_FIND_LIBRARY_SUFFIXES .a) endif () endif () _grpc_find_library(_gRPC_grpc grpc) _grpc_find_library(_gRPC_grpc++ grpc++) if (NOT _gRPC_INCLUDE_DIR) find_path(_gRPC_INCLUDE_DIR grpcpp/grpcpp.h) mark_as_advanced(_gRPC_INCLUDE_DIR) endif () if (gRPC_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _gRPC_grpc_LIBRARY = ${_gRPC_grpc_LIBRARY}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _gRPC_grpc++_LIBRARY = ${_gRPC_grpc++_LIBRARY}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _gRPC_INCLUDE_DIR = ${_gRPC_INCLUDE_DIR}") endif () if (_gRPC_grpc_LIBRARY) if (NOT TARGET gRPC::grpc) add_library(gRPC::grpc UNKNOWN IMPORTED) set_target_properties( gRPC::grpc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_gRPC_INCLUDE_DIR}") if (EXISTS "${_gRPC_grpc_LIBRARY}") set_target_properties(gRPC::grpc PROPERTIES IMPORTED_LOCATION "${_gRPC_grpc_LIBRARY}") endif () if (EXISTS "${_gRPC_grpc_LIBRARY_RELEASE}") set_property( TARGET gRPC::grpc APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties( gRPC::grpc PROPERTIES IMPORTED_LOCATION_RELEASE "${_gRPC_grpc_LIBRARY_RELEASE}") endif () if (EXISTS "${_gRPC_grpc_LIBRARY_DEBUG}") set_property( TARGET gRPC::grpc APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties( gRPC::grpc PROPERTIES IMPORTED_LOCATION_DEBUG "${_gRPC_grpc_LIBRARY_DEBUG}") endif () set_property( TARGET gRPC::grpc APPEND PROPERTY INTERFACE_LINK_LIBRARIES protobuf::libprotobuf Threads::Threads) endif () endif () if (_gRPC_grpc++_LIBRARY) if (NOT TARGET gRPC::grpc++) add_library(gRPC::grpc++ UNKNOWN IMPORTED) set_target_properties( gRPC::grpc++ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_gRPC++_INCLUDE_DIR}") if (EXISTS "${_gRPC_grpc++_LIBRARY}") set_target_properties( gRPC::grpc++ PROPERTIES IMPORTED_LOCATION "${_gRPC_grpc++_LIBRARY}") endif () if (EXISTS "${_gRPC_grpc++_LIBRARY_RELEASE}") set_property( TARGET gRPC::grpc++ APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties( gRPC::grpc++ PROPERTIES IMPORTED_LOCATION_RELEASE "${_gRPC_grpc++_LIBRARY_RELEASE}") endif () if (EXISTS "${_gRPC_grpc++_LIBRARY_DEBUG}") set_property( TARGET gRPC::grpc++ APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) set_target_properties( gRPC::grpc++ PROPERTIES IMPORTED_LOCATION_DEBUG "${_gRPC_grpc++_LIBRARY_DEBUG}") endif () set_property( TARGET gRPC::grpc++ APPEND PROPERTY INTERFACE_LINK_LIBRARIES gRPC::grpc protobuf::libprotobuf Threads::Threads) # gRPC++ requires C++14. It does not yet define the compile features, so # we define the feature ourselves. set_property( TARGET gRPC::grpc++ APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14) endif () endif () # Restore original find library prefixes if (_gRPC_USE_STATIC_LIBS) set(CMAKE_FIND_LIBRARY_PREFIXES "${_gRPC_ORIG_FIND_LIBRARY_PREFIXES}") endif () file( WRITE "${CMAKE_BINARY_DIR}/get_gRPC_version.cc" [====[ #include #include int main() { std::cout << grpc::Version(); // no newline to simplify CMake module return 0; } ]====]) try_run( _gRPC_GET_VERSION_STATUS _gRPC_GET_VERSION_COMPILE_STATUS "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/get_gRPC_version.cc" LINK_LIBRARIES gRPC::grpc++ gRPC::grpc COMPILE_OUTPUT_VARIABLE _gRPC_GET_VERSION_COMPILE_OUTPUT RUN_OUTPUT_VARIABLE gRPC_VERSION) file(REMOVE "${CMAKE_BINARY_DIR}/get_gRPC_version.cc") _grpc_fix_grpc_cpp_plugin_target() if (gRPC_DEBUG) foreach ( _var _gRPC_CPP_PLUGIN_EXECUTABLE _gRPC_VERSION_RAW _gRPC_GET_VERSION_STATUS _gRPC_GET_VERSION_COMPILE_STATUS _gRPC_GET_VERSION_COMPILE_OUTPUT _gRPC_grpc_LIBRARY _gRPC_grpc++_LIBRARY _gRPC_INCLUDE_DIR) message( STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "${_var} = ${${_var}}") endforeach () unset(_var) endif () include(FindPackageHandleStandardArgs) find_package_handle_standard_args( gRPC REQUIRED_VARS _gRPC_grpc_LIBRARY _gRPC_INCLUDE_DIR VERSION_VAR gRPC_VERSION)syslog-ng-syslog-ng-4.4.0/cmake/Modules/Findrdkafka.cmake000066400000000000000000000032601450431004300232520ustar00rootroot00000000000000############################################################################# # Copyright (c) 2018 Balabit # Copyright (c) 2018 Kokan # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) pkg_search_module(RDKAFKA_PKGCONF rdkafka) libfind_pkg_detect(RDKAFKA rdkafka FIND_PATH librdkafka/rdkafka.h FIND_LIBRARY rdkafka) set(RDKAFKA_PROCESS_INCLUDES RDKAFKA_INCLUDE_DIR) set(RDKAFKA_PROCESS_LIBS RDKAFKA_LIBRARY) libfind_process(RDKAFKA) add_library(rdkafka INTERFACE) if (NOT RDKAFKA_FOUND) return() endif() if (${rdkafka_FIND_VERSION} VERSION_GREATER ${RDKAFKA_PKGCONF_VERSION}) set(RDKAFKA_FOUND FALSE) return() endif() target_include_directories(rdkafka INTERFACE ${RDKAFKA_PROCESS_INCLUDES}) target_link_libraries(rdkafka INTERFACE ${RDKAFKA_LIBRARY}) syslog-ng-syslog-ng-4.4.0/cmake/Modules/Findsystemd.cmake000066400000000000000000000026271450431004300233450ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(LibFindMacros) libfind_pkg_check_modules(Libsystemd_PKGCONF libsystemd) libfind_pkg_detect(Libsystemd libsystemd FIND_PATH sd-daemon.h PATH_SUFFIXES systemd FIND_LIBRARY systemd) set(Libsystemd_PROCESS_INCLUDES Libsystemd_INCLUDE_DIR) set(Libsystemd_PROCESS_LIBS Libsystemd_LIBRARY) # silence warnings libfind_process(Libsystemd QUIET) syslog-ng-syslog-ng-4.4.0/cmake/Modules/GenerateYFromYm.cmake000066400000000000000000000047431450431004300240720ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # This function is syslog-ng specific function(generate_y_from_ym FileWoExt) if (${ARGC} EQUAL 1) add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/${FileWoExt}.y COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/lib/merge-grammar.py ${PROJECT_SOURCE_DIR}/${FileWoExt}.ym > ${PROJECT_BINARY_DIR}/${FileWoExt}.y DEPENDS ${PROJECT_SOURCE_DIR}/lib/cfg-grammar.y ${PROJECT_SOURCE_DIR}/${FileWoExt}.ym) elseif(${ARGC} EQUAL 2) add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/${ARGV1}.y COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/lib/merge-grammar.py ${PROJECT_SOURCE_DIR}/${FileWoExt}.ym > ${PROJECT_BINARY_DIR}/${ARGV1}.y DEPENDS ${PROJECT_SOURCE_DIR}/lib/cfg-grammar.y ${PROJECT_SOURCE_DIR}/${FileWoExt}.ym) else() message(SEND_ERROR "Wrong usage of generate_y_from_ym() function") endif() endfunction() # This function is used by add_module function(module_generate_y_from_ym FileWoExtSrc FileWoExtDst) if (${ARGC} EQUAL 2) add_custom_command (OUTPUT ${FileWoExtDst}.y COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/lib/merge-grammar.py ${FileWoExtSrc}.ym > ${FileWoExtDst}.y DEPENDS ${PROJECT_SOURCE_DIR}/lib/cfg-grammar.y ${FileWoExtSrc}.ym) else() message(SEND_ERROR "Wrong usage of module_generate_y_from_ym() function") endif() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/Modules/LibFindMacros.cmake000066400000000000000000000274321450431004300235310ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # Origin: https://raw.githubusercontent.com/Tronic/cmake-modules/master/LibFindMacros.cmake # Version 2.2 # Public Domain, originally written by Lasse Kärkkäinen # Maintained at https://github.com/Tronic/cmake-modules # Please send your improvements as pull requests on Github. # Find another package and make it a dependency of the current package. # This also automatically forwards the "REQUIRED" argument. # Usage: libfind_package( [extra args to find_package]) # Modified by https://github.com/Tronic/cmake-modules/pull/1 macro (libfind_package PREFIX PKG) set(${PREFIX}_args ${PKG} ${ARGN}) if (${PREFIX}_FIND_REQUIRED) set(${PREFIX}_args ${${PREFIX}_args} REQUIRED) endif() find_package(${${PREFIX}_args}) set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG}) unset(${PREFIX}_args) endmacro() # A simple wrapper to make pkg-config searches a bit easier. # Works the same as CMake's internal pkg_check_modules but is always quiet. macro (libfind_pkg_check_modules) find_package(PkgConfig QUIET) if (PKG_CONFIG_FOUND) pkg_check_modules(${ARGN} QUIET) endif() endmacro() # Avoid useless copy&pasta by doing what most simple libraries do anyway: # pkg-config, find headers, find library. # Usage: libfind_pkg_detect( FIND_PATH [other args] FIND_LIBRARY [other args]) # E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2) function (libfind_pkg_detect PREFIX) # Parse arguments set(argname pkgargs) foreach (i ${ARGN}) if ("${i}" STREQUAL "FIND_PATH") set(argname pathargs) elseif ("${i}" STREQUAL "FIND_LIBRARY") set(argname libraryargs) else() set(${argname} ${${argname}} ${i}) endif() endforeach() if (NOT pkgargs) message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.") endif() # Find library libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs}) if (pathargs) find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS}) endif() if (libraryargs) find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}) endif() endfunction() # Extracts a version #define from a version.h file, output stored to _VERSION. # Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR) # Fourth argument "QUIET" may be used for silently testing different define names. # This function does nothing if the version variable is already defined. function (libfind_version_header PREFIX VERSION_H DEFINE_NAME) # Skip processing if we already have a version or if the include dir was not found if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR) return() endif() set(quiet ${${PREFIX}_FIND_QUIETLY}) # Process optional arguments foreach(arg ${ARGN}) if (arg STREQUAL "QUIET") set(quiet TRUE) else() message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.") endif() endforeach() # Read the header and parse for version number set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") if (NOT EXISTS ${filename}) if (NOT quiet) message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") endif() return() endif() file(READ "${filename}" header) string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}") # No regex match? if (match STREQUAL header) if (NOT quiet) message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") endif() return() endif() # Export the version string set(${PREFIX}_VERSION "${match}" PARENT_SCOPE) endfunction() # Do the final processing once the paths have been detected. # If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain # all the variables, each of which contain one include directory. # Ditto for ${PREFIX}_PROCESS_LIBS and library files. # Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. # Also handles errors in case library detection was required, etc. function (libfind_process PREFIX) # Skip processing if already processed during this configuration run if (${PREFIX}_FOUND) return() endif() set(found TRUE) # Start with the assumption that the package was found # Did we find any files? Did we miss includes? These are for formatting better error messages. set(some_files FALSE) set(missing_headers FALSE) # Shorthands for some variables that we need often set(quiet ${${PREFIX}_FIND_QUIETLY}) set(required ${${PREFIX}_FIND_REQUIRED}) set(exactver ${${PREFIX}_FIND_VERSION_EXACT}) set(findver "${${PREFIX}_FIND_VERSION}") set(version "${${PREFIX}_VERSION}") # Lists of config option names (all, includes, libs) unset(configopts) set(includeopts ${${PREFIX}_PROCESS_INCLUDES}) set(libraryopts ${${PREFIX}_PROCESS_LIBS}) # Process optional arguments foreach(arg ${ARGN}) if (arg STREQUAL "QUIET") set(quiet TRUE) endif() endforeach() # Process deps to add to foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES}) if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS) # The package seems to export option lists that we can use, woohoo! list(APPEND includeopts ${${i}_INCLUDE_OPTS}) list(APPEND libraryopts ${${i}_LIBRARY_OPTS}) else() # If plural forms don't exist or they equal singular forms if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES)) # Singular forms can be used if (DEFINED ${i}_INCLUDE_DIR) list(APPEND includeopts ${i}_INCLUDE_DIR) endif() if (DEFINED ${i}_LIBRARY) list(APPEND libraryopts ${i}_LIBRARY) endif() else() # Oh no, we don't know the option names message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!") endif() endif() endforeach() if (includeopts) list(REMOVE_DUPLICATES includeopts) endif() if (libraryopts) list(REMOVE_DUPLICATES libraryopts) endif() string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}") if (NOT tmp STREQUAL "${includeopts} ${libraryopts}") message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).") endif() # Include/library names separated by spaces (notice: not CMake lists) unset(includes) unset(libs) # Process all includes and set found false if any are missing foreach (i ${includeopts}) list(APPEND configopts ${i}) if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") list(APPEND includes "${${i}}") else() set(found FALSE) set(missing_headers TRUE) endif() endforeach() # Process all libraries and set found false if any are missing foreach (i ${libraryopts}) list(APPEND configopts ${i}) if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") list(APPEND libs "${${i}}") else() set (found FALSE) endif() endforeach() # Version checks if (found AND findver) if (NOT version) message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.") elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver)) set(found FALSE) set(version_unsuitable TRUE) endif() endif() # If all-OK, hide all config options, export variables, print status and exit if (found) foreach (i ${configopts}) mark_as_advanced(${i}) endforeach() if (NOT quiet) message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") if (LIBFIND_DEBUG) message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}") message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}") message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}") message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}") message(STATUS " ${PREFIX}_LIBRARIES=${libs}") endif() endif() set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE) set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE) set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE) set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE) set (${PREFIX}_FOUND TRUE PARENT_SCOPE) return() endif() # Format messages for debug info and the type of error set(vars "Relevant CMake configuration variables:\n") foreach (i ${configopts}) mark_as_advanced(CLEAR ${i}) set(val ${${i}}) if ("${val}" STREQUAL "${i}-NOTFOUND") set (val "") elseif (val AND NOT EXISTS ${val}) set (val "${val} (does not exist)") else() set(some_files TRUE) endif() set(vars "${vars} ${i}=${val}\n") endforeach() set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n") if (version_unsuitable) set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but") if (exactver) set(msg "${msg} only version ${findver} is acceptable.") else() set(msg "${msg} version ${findver} is the minimum requirement.") endif() else() if (missing_headers) set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?") elseif (some_files) set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?") if(findver) set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).") endif() else() set(msg "We were unable to find package ${PREFIX}.") endif() endif() # Fatal error out if REQUIRED if (required) set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.") message(FATAL_ERROR "${msg}\n${vars}") endif() # Otherwise just print a nasty warning if (NOT quiet) message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}") endif() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/Modules/ProtobufGenerateCpp.cmake000066400000000000000000000104041450431004300247620ustar00rootroot00000000000000############################################################################# # Copyright (c) 2023 Attila Szakacs # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(CMakeParseArguments) get_property(_protoc_path TARGET protobuf::protoc PROPERTY IMPORTED_LOCATION) execute_process(COMMAND ${_protoc_path} --version OUTPUT_VARIABLE _protoc_version) if("${_protoc_version}" MATCHES "libprotoc ([0-9.]+)") set(_protoc_version "${CMAKE_MATCH_1}") endif() if("${_protoc_version}" VERSION_LESS "3.15.0") set_property(GLOBAL PROPERTY PROTOC_EXTRA_FLAGS "--experimental_allow_proto3_optional") endif() function(_protobuf_generate_cpp_internal) cmake_parse_arguments(_protobuf_generate_cpp_internal "" "PROTO_PATH;CPP_OUT;OUT_SRCS" "PROTOS;EXTRA_EXT;EXTRA_PROTOC_FLAGS;EXTRA_DEPENDS" "${ARGN}") get_property(_protoc_extra_flags GLOBAL PROPERTY PROTOC_EXTRA_FLAGS) file(MAKE_DIRECTORY ${_protobuf_generate_cpp_internal_CPP_OUT}) set(_generated_srcs_all) foreach(_proto ${_protobuf_generate_cpp_internal_PROTOS}) get_filename_component(_abs_file ${_proto} ABSOLUTE) get_filename_component(_abs_dir ${_abs_file} DIRECTORY) get_filename_component(_basename ${_proto} NAME_WLE) file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir}) set(_generated_srcs) foreach(_ext .pb.h .pb.cc ${_protobuf_generate_cpp_internal_EXTRA_EXT}) list(APPEND _generated_srcs "${_protobuf_generate_cpp_internal_CPP_OUT}/${_rel_dir}/${_basename}${_ext}") endforeach() add_custom_command( OUTPUT ${_generated_srcs} COMMAND protobuf::protoc ARGS ${_protobuf_generate_cpp_internal_EXTRA_PROTOC_FLAGS} --proto_path=${_protobuf_generate_cpp_internal_PROTO_PATH} --cpp_out=${_protobuf_generate_cpp_internal_CPP_OUT} ${_protoc_extra_flags} ${_proto} DEPENDS protobuf::protoc ${_protobuf_generate_cpp_internal_EXTRA_DEPENDS} COMMENT "Running C++ protocol buffer compiler on ${_proto}" VERBATIM) set_source_files_properties(${_generated_srcs} PROPERTIES GENERATED TRUE) list(APPEND _generated_srcs_all ${_generated_srcs}) endforeach() set(${_protobuf_generate_cpp_internal_OUT_SRCS} ${_generated_srcs_all} PARENT_SCOPE) endfunction() function(protobuf_generate_cpp) cmake_parse_arguments(protobuf_generate_cpp "" "PROTO_PATH;CPP_OUT;OUT_SRCS" "PROTOS" "${ARGN}") _protobuf_generate_cpp_internal( PROTO_PATH ${protobuf_generate_cpp_PROTO_PATH} CPP_OUT ${protobuf_generate_cpp_CPP_OUT} OUT_SRCS _out_srcs PROTOS ${protobuf_generate_cpp_PROTOS}) set(${protobuf_generate_cpp_OUT_SRCS} ${_out_srcs} PARENT_SCOPE) endfunction() function(protobuf_generate_cpp_grpc) cmake_parse_arguments(protobuf_generate_cpp_grpc "" "PROTO_PATH;CPP_OUT;OUT_SRCS" "PROTOS" "${ARGN}") get_property(_grpc_cpp_plugin_path TARGET gRPC::grpc_cpp_plugin PROPERTY IMPORTED_LOCATION) _protobuf_generate_cpp_internal( PROTO_PATH ${protobuf_generate_cpp_grpc_PROTO_PATH} CPP_OUT ${protobuf_generate_cpp_grpc_CPP_OUT} OUT_SRCS _out_srcs PROTOS ${protobuf_generate_cpp_grpc_PROTOS} EXTRA_EXT .grpc.pb.cc .grpc.pb.h EXTRA_PROTOC_FLAGS --plugin=protoc-gen-grpc-cpp=${_grpc_cpp_plugin_path} --grpc-cpp_out=${protobuf_generate_cpp_grpc_CPP_OUT} EXTRA_DEPENDS gRPC::grpc_cpp_plugin) set(${protobuf_generate_cpp_grpc_OUT_SRCS} ${_out_srcs} PARENT_SCOPE) endfunction() syslog-ng-syslog-ng-4.4.0/cmake/add_module.cmake000066400000000000000000000050611450431004300215340ustar00rootroot00000000000000############################################################################# # Copyright (c) 2020 One Identity # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(CMakeParseArguments) function (add_module) cmake_parse_arguments(ADD_MODULE "" "TARGET" "GRAMMAR;SOURCES;DEPENDS;INCLUDES;LIBRARY_TYPE" ${ARGN}) if (ADD_MODULE_GRAMMAR) module_generate_y_from_ym(${CMAKE_CURRENT_SOURCE_DIR}/${ADD_MODULE_GRAMMAR} ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}) bison_target(${ADD_MODULE_TARGET}Grammar} ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}.y ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}.c COMPILE_FLAGS ${BISON_FLAGS} ) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS} ) list(APPEND ADD_MODULE_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}.h ${CMAKE_CURRENT_BINARY_DIR}/${ADD_MODULE_GRAMMAR}.c ) endif() if (NOT ADD_MODULE_LIBRARY_TYPE) set(ADD_MODULE_LIBRARY_TYPE SHARED) endif() add_library(${ADD_MODULE_TARGET} ${ADD_MODULE_LIBRARY_TYPE} ${ADD_MODULE_SOURCES}) target_include_directories(${ADD_MODULE_TARGET} SYSTEM PRIVATE ${ADD_MODULE_INCLUDES}) target_include_directories(${ADD_MODULE_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) target_link_libraries(${ADD_MODULE_TARGET} PRIVATE ${ADD_MODULE_DEPENDS} syslog-ng) if (ADD_MODULE_LIBRARY_TYPE STREQUAL SHARED) install(TARGETS ${ADD_MODULE_TARGET} LIBRARY DESTINATION lib/syslog-ng COMPONENT ${ADD_MODULE_TARGET}) endif() endfunction () syslog-ng-syslog-ng-4.4.0/cmake/add_tests.cmake000066400000000000000000000054551450431004300214200ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(CMakeParseArguments) if (BUILD_TESTING) include(CheckPIESupported) check_pie_supported() endif() function (add_unit_test) if (NOT BUILD_TESTING) return() endif() cmake_parse_arguments(ADD_UNIT_TEST "CRITERION;LIBTEST" "TARGET" "SOURCES;DEPENDS;INCLUDES" ${ARGN}) if (NOT ADD_UNIT_TEST_SOURCES) set(ADD_UNIT_TEST_SOURCES "${ADD_UNIT_TEST_TARGET}.c") endif() add_executable(${ADD_UNIT_TEST_TARGET} ${ADD_UNIT_TEST_SOURCES}) target_compile_definitions(${ADD_UNIT_TEST_TARGET} PRIVATE TOP_SRCDIR="${PROJECT_SOURCE_DIR}") target_link_libraries(${ADD_UNIT_TEST_TARGET} ${ADD_UNIT_TEST_DEPENDS} syslog-ng) target_include_directories(${ADD_UNIT_TEST_TARGET} PUBLIC ${ADD_UNIT_TEST_INCLUDES}) if (NOT APPLE) set_property(TARGET ${ADD_UNIT_TEST_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--no-as-needed") endif() if (${ADD_UNIT_TEST_CRITERION}) target_link_libraries(${ADD_UNIT_TEST_TARGET} ${CRITERION_LIBRARIES}) target_include_directories(${ADD_UNIT_TEST_TARGET} PUBLIC ${CRITERION_INCLUDE_DIRS}) set_property(TARGET ${ADD_UNIT_TEST_TARGET} PROPERTY POSITION_INDEPENDENT_CODE FALSE) endif() if (${ADD_UNIT_TEST_LIBTEST}) target_link_libraries(${ADD_UNIT_TEST_TARGET} libtest) endif() add_test (${ADD_UNIT_TEST_TARGET} ${ADD_UNIT_TEST_TARGET}) add_dependencies(check ${ADD_UNIT_TEST_TARGET}) set_tests_properties(${ADD_UNIT_TEST_TARGET} PROPERTIES ENVIRONMENT "ASAN_OPTIONS=detect_odr_violation=0;CRITERION_TEST_PATTERN=!(*/*performance*)") set_tests_properties(${ADD_UNIT_TEST_TARGET} PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR: (LeakSanitizer|AddressSanitizer)") endfunction () macro (add_test_subdirectory SUBDIR) if (BUILD_TESTING) add_subdirectory(${SUBDIR}) endif() endmacro() syslog-ng-syslog-ng-4.4.0/cmake/external_or_find_package.cmake000066400000000000000000000055521450431004300244410ustar00rootroot00000000000000############################################################################# # Copyright (c) 2017 Balabit # Copyright (c) 2017 Kokan # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# include(CMakeParseArguments) function(external_or_find_package LIB_NAME) cmake_parse_arguments(EXTERNAL_OR_FIND_PACKAGE "REQUIRED" "" "" ${ARGN}) set(${LIB_NAME}_SOURCE "auto" CACHE STRING "${LIB_NAME} library source") set_property(CACHE ${LIB_NAME}_SOURCE PROPERTY STRINGS internal system auto) include(External${LIB_NAME} OPTIONAL RESULT_VARIABLE EXT_${LIB_NAME}_PATH) if (NOT EXISTS ${EXT_${LIB_NAME}_PATH}) set(${LIB_NAME}_INTERNAL FALSE) endif() if (${LIB_NAME}_INTERNAL) set_target_properties(${LIB_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE) endif() if (${${LIB_NAME}_INTERNAL} AND ("internal" STREQUAL ${${LIB_NAME}_SOURCE} OR "auto" STREQUAL ${${LIB_NAME}_SOURCE} )) message(STATUS "Found ${LIB_NAME}: internal") set(${LIB_NAME}_FOUND TRUE PARENT_SCOPE) set(${LIB_NAME}_INCLUDE_DIR "${${LIB_NAME}_INTERNAL_INCLUDE_DIR}" CACHE STRING "${LIB_NAME} include path") set(${LIB_NAME}_LIBRARY "${${LIB_NAME}_INTERNAL_LIBRARY}" CACHE STRING "${LIB_NAME} library path") elseif ("system" STREQUAL ${${LIB_NAME}_SOURCE} OR "auto" STREQUAL ${${LIB_NAME}_SOURCE}) if (${EXTERNAL_OR_FIND_PACKAGE_REQUIRED}) find_package(${LIB_NAME} REQUIRED) else() find_package(${LIB_NAME} ) endif() set(${LIB_NAME}_FOUND "${${LIB_NAME}_FOUND}" PARENT_SCOPE) unset(${LIB_NAME}_INTERNAL) else() if (${EXTERNAL_OR_FIND_PACKAGE_REQUIRED}) message(FATAL_ERROR "Library ${LIB_NAME} is mandatory but NOTFOUND") else() message(STATUS "Library ${LIB_NAME} is NOTFOUND") endif() unset(${LIB_NAME}_INTERNAL) endif() if (${LIB_NAME}_INTERNAL) set(${LIB_NAME}_INTERNAL "${${LIB_NAME}_INTERNAL}" PARENT_SCOPE) endif() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/module_switch.cmake000066400000000000000000000030021450431004300222760ustar00rootroot00000000000000############################################################################# # Copyright (c) 2019 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# option(DISABLE_ALL_MODULES "disable all switchable modules by default" "OFF") function (module_switch NAME HELP_STRING) if (DEFINED ${NAME}) return() endif() if (DISABLE_ALL_MODULES) option(${NAME} ${HELP_STRING} "OFF") return () endif() foreach (symbol ${ARGN}) if (NOT ${symbol}) option(${NAME} "${HELP_STRING}" "OFF") return() endif() endforeach() option(${NAME} "${HELP_STRING}" "ON") endfunction () syslog-ng-syslog-ng-4.4.0/cmake/openssl_functions.cmake000066400000000000000000000040751450431004300232160ustar00rootroot00000000000000############################################################################# # Copyright (c) 2018 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# function (openssl_set_defines) set (CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) set (CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) include(CheckSymbolExists) set (check_symbol_headers openssl/asn1.h openssl/evp.h openssl/dh.h openssl/ssl.h openssl/x509v3.h openssl/bn.h) set (symbol_list EVP_MD_CTX_reset ASN1_STRING_get0_data SSL_CTX_get0_param X509_STORE_CTX_get0_cert X509_get_extension_flags DH_set0_pqg BN_get_rfc3526_prime_2048 SSL_CTX_set_num_tickets SSL_CTX_set_ciphersuites SSL_CTX_set1_sigalgs_list SSL_CTX_set1_client_sigalgs_list SSL_add_file_cert_subjects_to_stack SSL_add_dir_cert_subjects_to_stack) foreach (symbol ${symbol_list}) string(TOUPPER ${symbol} SYMBOL_UPPERCASE) check_symbol_exists(${symbol} "${check_symbol_headers}" SYSLOG_NG_HAVE_DECL_${SYMBOL_UPPERCASE}) set(SYSLOG_NG_HAVE_DECL_${SYMBOL_UPPERCASE} "${SYSLOG_NG_HAVE_DECL_${SYMBOL_UPPERCASE}}" PARENT_SCOPE) endforeach() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/print_config_summary.cmake000066400000000000000000000101031450431004300236660ustar00rootroot00000000000000# ############################################################################ # Copyright (c) 2022 One Identity # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # # ############################################################################ function(_print_summary_line _variableName _maxVarNameLen) string(ASCII 27 Esc) set(Red "${Esc}[31m") set(Green "${Esc}[32m") set(ResetFG "${Esc}[39m") set(_variableValue "${${_variableName}}") string(LENGTH "${_variableName}" _variableNameLen) math(EXPR _variableNameLen "${_maxVarNameLen} - ${_variableNameLen}") if(_variableNameLen LESS 0) set(_variableNameLen 0) endif() string(REPEAT " " ${_variableNameLen} _spaces) string(TOUPPER "${_variableValue}" _upperValue) if(_upperValue STREQUAL "ON" OR _upperValue STREQUAL "TRUE") message("${_variableName}${_spaces}${Green}On${ResetFG}") elseif(_upperValue STREQUAL "OFF" OR _upperValue STREQUAL "FALSE") message("${_variableName}${_spaces}${Red}Off${ResetFG}") else() message("${_variableName}${_spaces}${Green}${_variableValue}${ResetFG}") endif() endfunction() function(_print_separator) message(NOTICE "-----------------------------------") endfunction() function(_print_libraries _variableNames) foreach(_variableName ${_variableNames}) string(REGEX MATCH ".*(_LIBRARY|_LIBRARIES)$" _match_lib "${_variableName}") string(REGEX MATCH ".*(INCLUDE_DIR|INCLUDEDIR|INCLUDE_DIRS)$" _match_incl "${_variableName}") string(REGEX MATCH "^(CMAKE_|_).*" _cmakeInternal "${_variableName}") if((_match_lib OR _match_incl) AND NOT _cmakeInternal) _print_summary_line("${_variableName}" 40) endif() endforeach() endfunction() function(_print_importants _variableNames _importantVariableNames) foreach(_variableName ${_variableNames}) foreach(_importantVariableName ${_importantVariableNames}) string(REGEX MATCH "^${_importantVariableName}$" _match "${_variableName}") if(_match) _print_summary_line("${_importantVariableName}" 32) endif() endforeach() endforeach() endfunction() function(_print_options _variableNames) foreach(_variableName ${_variableNames}) string(REGEX MATCH "^ENABLE_" _match "${_variableName}") if(_match) _print_summary_line("${_variableName}" 32) endif() endforeach() endfunction() function(_print_full _variableNames) foreach(_variableName ${_variableNames}) message("${_variableName}=${${_variableName}}") endforeach() endfunction() # Lists actual module definition results # Behaves similar to the cmake -L option but filters out the relevant information and adds some highlighting # function(print_config_summary) get_cmake_property(_variableNames VARIABLES) list(SORT _variableNames) _print_separator() message(NOTICE "syslog-ng Open Source Edition ${SYSLOG_NG_VERSION} configured") _print_separator() if(SUMMARY_FULL) _print_full("${_variableNames}") else() if(SUMMARY_VERBOSE) _print_libraries("${_variableNames}") _print_separator() endif() list(APPEND _importantVariableNames "IVYKIS_INTERNAL" "BUILD_TESTING") _print_importants("${_variableNames}" "${_importantVariableNames}") _print_separator() _print_options("${_variableNames}") endif() _print_separator() endfunction() syslog-ng-syslog-ng-4.4.0/cmake/python_build_venv.cmake000066400000000000000000000012761450431004300232010ustar00rootroot00000000000000 set(PYTHON_VENV_DIR "${PROJECT_BINARY_DIR}/venv") set(PYTHON_VENV_TOUCHFILE "${PROJECT_BINARY_DIR}/.python-venv-built") set(PYTHON_VENV_EXECUTABLE "${PYTHON_VENV_DIR}/bin/python") add_custom_command( OUTPUT ${PYTHON_VENV_TOUCHFILE} COMMAND ${PROJECT_SOURCE_DIR}/scripts/build-python-venv.sh "${PYTHON_EXECUTABLE}" "${PROJECT_BINARY_DIR}/venv" "${PROJECT_SOURCE_DIR}" && touch "${PYTHON_VENV_TOUCHFILE}" VERBATIM ) # the touchfile is cleaned up by cmake automatically, we only need to remove # the venv directory set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PYTHON_VENV_DIR}") add_custom_target(BuildPyVirtualEnv DEPENDS ${PYTHON_VENV_TOUCHFILE}) syslog-ng-syslog-ng-4.4.0/cmake/syslog_ng_core_java_native.cmake000066400000000000000000000014321450431004300250200ustar00rootroot00000000000000 macro(create_syslog_ng_core_java_native) #The GENERATE_NATIVE_HEADERS variable introduced only in cmake 3.11.1 #This is just a dirty workaround for that: set(CMAKE_JAVA_COMPILE_FLAGS "${CMAKE_JAVA_COMPILE_FLAGS};-h;${CMAKE_CURRENT_BINARY_DIR};") add_jar(syslog-ng-core SOURCES ${JAVA_SOURCES} OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} GENERATE_NATIVE_HEADERS syslog-ng-core-java-native ) #The GENERATE_NATIVE_HEADERS has been introduced in cmake 3.11 if(NOT TARGET syslog-ng-core-java-native) add_library(syslog-ng-core-java-native INTERFACE) target_include_directories(syslog-ng-core-java-native INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) add_dependencies(syslog-ng-core-java-native syslog-ng-core) endif() endmacro(create_syslog_ng_core_java_native) syslog-ng-syslog-ng-4.4.0/configure.ac000066400000000000000000002541651450431004300176560ustar00rootroot00000000000000############################################################################# # Copyright (c) 2016 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# dnl Process this file with autoconf to produce a configure script. dnl dnl There are a couple of environment defined variables which this script dnl makes use of in addition to the standard CFLAGS/LDFLAGS/etc. These are: dnl dnl RELEASE_TAG - Debian release tag which is put to debian/changelog dnl SNAPSHOT_VERSION - snapshot version to add to version number dnl BINARY_BRANCH - the value is added to all source/binary packages dnl SOURCE_REVISION - Revision of the source-tree, will added to the version string dnl AC_INIT([syslog-ng], m4_esyscmd_s([scripts/version.sh])) AC_CONFIG_SRCDIR([syslog-ng/main.c]) AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) dnl *************************************************************************** dnl dependencies GLIB_MIN_VERSION="2.32" OPENSSL_MIN_VERSION="0.9.8" LIBDBI_MIN_VERSION="0.9.0" LIBRABBITMQ_MIN_VERSION="0.5.3" LIBRDKAFKA_MIN_VERSION="1.1.0" IVYKIS_MIN_VERSION="0.36.1" IVYKIS_UPDATED_VERSION="0.39" JSON_C_MIN_VERSION="0.9" PCRE2_MIN_VERSION="10.0" LMC_MIN_VERSION="1.0.0" LRMQ_MIN_VERSION="0.0.1" LRC_MIN_VERSION="1.6.0" LIBBPF_MIN_VERSION="1.0.1" JOURNALD_MIN_VERSION="195" LIBSYSTEMD_MIN_VERSION="209" LIBSYSTEMD_WITH_JOURNAL_NAMESPACES_MIN_VERSION="245" JAVA_MIN_VERSION="1.8" GRADLE_MIN_VERSION="3.4" HIREDIS_MIN_VERSION="0.11.0" CRITERION_MIN_VERSION="2.2.1" PROTOBUF_MIN_VERSION="3.12.0" GRPCPP_MIN_VERSION="1.16.1" dnl *************************************************************************** dnl Initial setup ostype=`uname -s` if test -r $srcdir/dist.conf; then # read defaults, dist.conf does not change # values for parameters that are already set . $srcdir/dist.conf fi if test -z "$RELEASE_TAG"; then RELEASE_TAG=unstable fi if test "`uname -s`" = "Linux";then CURRDATE=`date -R` else CURRDATE=`date +"%a, %d %b %Y %H:%M:%S %Z"` fi AM_INIT_AUTOMAKE([foreign no-define subdir-objects]) _AM_PROG_TAR([ustar]) if test -n "$SNAPSHOT_VERSION"; then PACKAGE_VERSION=$PACKAGE_VERSION+$SNAPSHOT_VERSION fi dnl *************************************************************************** dnl script snippet to generate user friendly version strings according to the dnl new versioning policy. All needed code are here to allow easy moving dnl between projects. if test -z "$RELEASE_TYPE"; then RELEASE_TYPE=stable fi if test -z "$BROCHURE_VERSION"; then _MAJOR=`echo $VERSION | cut -f1 -d'.'` _MINOR=`echo $VERSION | cut -f2 -d'.'` case "$RELEASE_TYPE" in stable) BROCHURE_VERSION="$_MAJOR";; feature) BROCHURE_VERSION="$_MAJOR F$_MINOR";; *) BROCHURE_VERSION="$VERSION dogfood edition. Please contact your syslog-ng release manager to fix the configure scritpt";; esac fi if test -z "$COMBINED_VERSION"; then COMBINED_VERSION="$BROCHURE_VERSION ($VERSION)" fi TECHNICAL_VERSION=$VERSION AC_DEFINE_UNQUOTED(RELEASE_TYPE, "$RELEASE_TYPE", [type of syslog-ng release. stable or feature]) AC_DEFINE_UNQUOTED(BROCHURE_VERSION, "$BROCHURE_VERSION", [pretty version for users depends on the release type]) AC_DEFINE_UNQUOTED(COMBINED_VERSION, "$COMBINED_VERSION", [normal and brochure version combined]) AC_DEFINE_UNQUOTED(SOURCE_REVISION, "$SOURCE_REVISION", [source revision]) AC_SUBST(RELEASE_TYPE) AC_SUBST(BROCHURE_VERSION) AC_SUBST(COMBINED_VERSION) AC_SUBST(TECHNICAL_VERSION) dnl *************************************************************************** if test "x$prefix" = "xNONE"; then prefix=$ac_default_prefix fi if test "x$exec_prefix" = "xNONE"; then exec_prefix='${prefix}' fi pidfiledir='${localstatedir}' moduledir='${exec_prefix}/lib/syslog-ng' loggenplugindir='${moduledir}/loggen' python_venvdir='${localstatedir}/python-venv' toolsdir='${datadir}/syslog-ng/tools' xsddir='${datadir}/syslog-ng/xsd' config_includedir='${datadir}/syslog-ng/include' scldir="${config_includedir}/scl" abs_topsrcdir=`(cd $srcdir && pwd)` AC_CONFIG_HEADERS(config.h) dnl *************************************************************************** dnl Arguments AC_ARG_WITH(libnet, [ --with-libnet=path use path to libnet-config script], , [with_libnet=""]) AC_ARG_WITH(net-snmp, [ --with-net-snmp=path use path to net-snmp-config script], , [with_net_snmp=""]) AC_ARG_WITH(pidfile-dir, [ --with-pidfile-dir=path Use path as the directory for storing pidfiles], pidfiledir=$with_pidfile_dir) AC_ARG_WITH(module-dir, [ --with-module-dir=path Use path as the directory to install modules into], moduledir=$with_module_dir) AC_ARG_WITH(loggen-plugin-dir, [ --with-loggen-plugin-dir=path Use path as the directory to install loggen plugins into], loggenplugindir=$with_loggen_plugin_dir) AC_ARG_WITH(python-venv-dir, [ --with-python-venv-dir=path Use path as the directory to install the Python venv into], python_venvdir=$with_python_venv_dir) AC_ARG_WITH(module-path, [ --with-module-path=path Use path as the list of ':' separated directories looked up when searching for modules], module_path=$with_module_path) AC_ARG_WITH(timezone-dir, [ --with-timezone-dir=path Use path as the directory to get the timezone files], timezonedir=$with_timezone_dir) AC_ARG_WITH(ld-library-path, [ --with-ld-library-path=path Set LD_LIBRARY_PATH during runtime to the value given], env_ld_library_path=$with_ld_library_path) AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])) AC_ARG_WITH(package_name, [ --with-package-name=package name Package name is printed out when syslog-ng started with --version], PACKAGE_NAME=$with_package_name) AC_ARG_ENABLE(forced_server_mode, [ --enable-forced-server-mode Enable forced server mode.],, enable_forced_server_mode="yes") AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging code.],, enable_debug="no") AC_ARG_ENABLE(force_gnu99, [ --enable-force-gnu99 Enforce C99 with gnu extensions.],, force_gnu99="no") AC_ARG_ENABLE(extra-warnings, [ --enable-extra-warnings Enable extra compiler warnings (recommended).],, enable_extra_warnings="no") AC_ARG_ENABLE(env-wrapper, [ --enable-env-wrapper Enable wrapper program to set up various environment variables],, enable_env_wrapper=auto) AC_ARG_ENABLE(gprof, [ --enable-gprof Enable gcc profiling.],, enable_gprof="no") AC_ARG_ENABLE(memtrace, [ --enable-memtrace Enable alternative leak debugging code.]) AC_ARG_WITH(sanitizer, [ --with-sanitizer=[address/undefined/etc...] Enables compiler sanitizer supports (default: no)] ,,with_sanitizer="no") AC_ARG_ENABLE(dynamic-linking, [ --enable-dynamic-linking Link everything dynamically.],,enable_dynamic_linking="auto") AC_ARG_ENABLE(mixed-linking, [ --enable-mixed-linking Link 3rd party libraries statically, system libraries dynamically],,enable_mixed_linking="auto") AC_ARG_ENABLE(ipv6, [ --enable-ipv6 Enable support for IPv6.],,enable_ipv6="auto") AC_ARG_ENABLE(tcp-wrapper, [ --enable-tcp-wrapper Enable support for TCP wrappers.],,enable_tcp_wrapper="auto") AC_ARG_ENABLE(spoof-source, [ --enable-spoof-source Enable support for spoofed source addresses.] ,,enable_spoof_source="auto") AC_ARG_ENABLE(sun-streams, [ --enable-sun-streams Enable support for Solaris /dev/log STREAMS device.] ,,enable_sun_streams="auto") AC_ARG_ENABLE(openbsd-system-source, [ --enable-openbsd-system-source Enable support for OpenBSD /dev/klog device.] ,,enable_openbsd_system_source="auto") AC_ARG_ENABLE(sql, [ --enable-sql Enable support for SQL destinations. (default: auto)] ,,enable_sql="auto") AC_ARG_ENABLE(pacct, [ --enable-pacct Enable support for reading Process Accounting files (EXPERIMENTAL, Linux only).] ,,enable_pacct="no") AC_ARG_ENABLE(linux-caps, [ --enable-linux-caps Enable support for managing Linux capabilities (default: auto)] ,,enable_linux_caps="auto") AC_ARG_ENABLE(ebpf, [ --enable-ebpf Enable support for loading of eBPF programs (default: no)] ,,enable_ebpf="no") AC_ARG_ENABLE(gcov, [ --enable-gcov Enable coverage profiling (default: no)] ,,enable_gcov="no") AC_ARG_ENABLE(mongodb, [ --enable-mongodb Enable mongodb destination (default: auto)] ,,enable_mongodb="auto") AC_ARG_WITH(jsonc, [ --with-jsonc=[yes/no] Link against the system supplied jsonc library or explicitly disable it. (default: yes)] ,,with_jsonc="yes") AC_ARG_ENABLE(json, [ --enable-json=[yes/no] Enable JSON support (default: yes)] ,[if test "x$enableval" != "xno"; then with_jsonc="system"; else with_jsonc="no"; fi],) AC_ARG_ENABLE(amqp, [ --enable-amqp Enable amqp destination (default: auto)] ,,enable_amqp="auto") AC_ARG_ENABLE(stomp, [ --enable-stomp Enable stomp destination (default: yes)] ,,enable_stomp="yes") AC_ARG_WITH(ivykis, [ --with-ivykis=[system/internal] Link against the system supplied or the built-in ivykis library.] ,,with_ivykis="internal") AC_ARG_ENABLE(smtp, [ --disable-smtp Disable SMTP support (default: auto)] ,,enable_smtp="auto") AC_ARG_WITH(libesmtp, AC_HELP_STRING([--with-libesmtp=DIR], [use libesmtp library from (prefix) directory DIR]),,) AC_ARG_ENABLE(mqtt, [ --disable-mqtt Disable MQTT support (default: auto)] ,,enable_mqtt="auto") AC_ARG_WITH(libpaho-mqtt, AC_HELP_STRING([--with-libpaho-mqtt=DIR], [use libpaho-mqtt library from (prefix) directory DIR]),,) AC_ARG_ENABLE(grpc, [ --enable-grpc Enable GRPC based driver support (OpenTelemetry) (default: auto)] ,,enable_grpc="auto") AC_ARG_WITH(protoc, AC_HELP_STRING([--with-protoc=PATH], [use protoc binary at PATH]),,) AC_ARG_WITH(protoc_gen_grpc_cpp_plugin, AC_HELP_STRING([--with-protoc-gen-grpc-cpp-plugin=PATH], [use protoc-gen-grpc-cpp plugin at PATH]),,) AC_ARG_ENABLE(cpp, [ --enable-cpp Enable C++ support (default: auto)] ,,enable_cpp="auto") AC_ARG_ENABLE(http, [ --disable-http Disable http support (default: auto)] ,,enable_http="auto") AC_ARG_WITH(libcurl, AC_HELP_STRING([--with-libcurl=DIR], [use libcurl library from (prefix) directory DIR]),,) AC_ARG_ENABLE(redis, [ --disable-redis Disable REDIS support (default: auto)] ,,enable_redis="auto") AC_ARG_WITH(libhiredis, AC_HELP_STRING([--with-libhiredis=DIR], [use libhiredis library from (prefix) directory DIR]),,) AC_ARG_ENABLE(systemd, [ --enable-systemd Enable systemd support (default: auto)] ,,enable_systemd="auto") AC_ARG_ENABLE(geoip2, [ --enable-geoip2 Enable GeoIP2 support (default: auto)] ,,enable_geoip2="auto") AC_ARG_ENABLE(riemann, [ --disable-riemann Disable riemann destination] ,,enable_riemann="auto") AC_ARG_WITH(compile-date, [ --without-compile-date Do not include the compile date in the binary] ,wcmp_date="${withval}", wcmp_date="yes") AC_ARG_WITH(systemd-journal, [ --with-systemd-journal=[system/optional/auto] Link against the system supplied or the wrapper library. (default: auto)] ,,with_systemd_journal="auto") AC_ARG_ENABLE(kafka, [ --enable-kafka Enable rdkafka support] ,,enable_kafka="auto") AC_ARG_ENABLE(python, [ --disable-python Disable Python module] ,,enable_python="auto") AC_ARG_ENABLE(python-modules, [ --disable-python-modules Disable Python based syslog-ng addons while installing the core Python modules] ,,enable_python_modules="auto") AC_ARG_WITH(python, [ --with-python=VERSION Build with a specific version of python] ,,with_python="auto") AC_ARG_WITH(python-packages, [ --with-python-packages=[system|venv|none] Use Python packages from the system or a private virtualenv or skip their installation (default: venv)] ,,with_python_packages="venv") AC_ARG_WITH(python3-home, [ --with-python3-home=path Use path as a hard-coded Python home directory that can not be overwritten by the PYTHONHOME environment variable], python3_home_dir=$with_python3_home) AC_ARG_WITH(pylint, [ --with-pylint=ABSOLUTE_PATH Specify pylint location]) AC_ARG_WITH(docbook, [ --with-docbook=FILE Compiling manpages using docbook in the specified path, if not set, it will be searched on the system, or online version will be used from http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl] ,,with_docbook="auto") AC_ARG_ENABLE(manpages, AC_HELP_STRING([ --enable-manpages], [ Enable generation of manpages (default: no)]), , [enable_manpages="no"; XSL_STYLESHEET=""]) AC_ARG_ENABLE(manpages-install, AC_HELP_STRING([ --enable-manpages-install], [ Enable installation of manpages (default: auto)]), , [enable_manpages_install="auto"]) AC_ARG_ENABLE(java, [ --enable-java Enable java destination (default: auto)],, enable_java="auto") AC_ARG_ENABLE(java-modules, [ --enable-java-modules Compile all Java modules (default: auto)],, enable_java_modules="auto") AC_ARG_ENABLE(native, [ --enable-native Enable native bindings (default: auto)] ,,enable_native="auto") AC_ARG_ENABLE(afsnmp, [ --enable-afsnmp Enable afsnmp module (default: auto)],, enable_afsnmp="auto") AC_ARG_ENABLE(all-modules, [ --enable-all-modules Forcibly enable all modules. (default: auto)] ,,enable_all_modules="auto") if test "x$enable_all_modules" != "xauto"; then state="$enable_all_modules" MODULES="spoof_source sun_streams sql pacct mongodb json amqp stomp \ redis systemd geoip2 riemann ipv6 smtp native python python_modules java java_modules \ http afsnmp kafka mqtt grpc" for mod in ${MODULES}; do modstate=$(eval echo \$enable_${mod}) if test "x$modstate" = "xauto"; then eval enable_${mod}=${state} fi done fi if test "x$wcmp_date" != "xno"; then wcmp_date="1" else wcmp_date="0" fi patheval() { OLD=$1 NEW=`eval echo $1` while test "x$OLD" != "x$NEW" do OLD=$NEW NEW=`eval echo $OLD` done echo $OLD } dnl *************************************************************************** dnl Checks for programs. AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O if test "x$ac_cv_prog_cc_c99" = "xno"; then AC_MSG_ERROR("C99 standard compliant C compiler required. Try GCC 3.x or later.") fi AC_PROG_YACC AM_PROG_LEX AC_PROG_MAKE_SET PKG_PROG_PKG_CONFIG LT_INIT([dlopen disable-static]) if test "x$with_python" = "xauto"; then AM_PATH_PYTHON(,,[:]) else AM_PATH_PYTHON([$with_python],,[:]) fi if test "${PYTHON}" = ":"; then AC_MSG_WARN([Python interpreter is missing.]) fi AM_CONDITIONAL([HAVE_PYTHON_INTERPRETER], [test "$PYTHON" != :]) dnl *************************************************************************** dnl C++ # Ok, here is the deal # clang cannot compile the current source, it has nultiple issues # replace it till not fixed them if test "x$CXX" = "xclang"; then AC_MSG_ERROR(["clang cannot compile syslog-ng C++ sources, try using gcc instead (export CXX=gcc) for C++ compilation (NOTE: on macOS you need Homebrew gcc not the Apple one)"]) elif test "x$CC" = "xclang"; then CPP_COMPILER="gcc" AC_MSG_WARN(["clang cannot compile syslog-ng C++ sources, switched to $CPP_COMPILER for C++ compilation (NOTE: on macOS you need Homebrew gcc not the Apple one)"]) else CPP_COMPILER="$CXX $CC" fi # This one is useful for checking the available compilers # AC_MSG_RESULT(gcc = $(which gcc) - g++ = $(which g++) - clang = $(which clang)) # AC_MSG_RESULT(Paths: gcc = $(ls -Al $(which gcc)) - g++ = $(ls -Al $(which g++)) - clang = $(ls -Al $(which clang))) # AC_MSG_RESULT($(gcc -v)) # AC_MSG_RESULT($(g++ -v)) # AC_MSG_RESULT($(clang -v)) # AC_MSG_RESULT(C++ compilers to be used $CPP_COMPILER) AC_PROG_CXX([$CPP_COMPILER]) if test "x$enable_cpp" = "xyes"; then AX_CXX_COMPILE_STDCXX(11,, mandatory) elif test "x$enable_cpp" = "xauto"; then AX_CXX_COMPILE_STDCXX(11,, optional) if test "x$HAVE_CXX11" = "x1"; then enable_cpp=yes else enable_cpp=no fi fi dnl *************************************************************************** dnl Validate yacc yacc_ok=0 if echo "$YACC" | grep -q bison; then # NOTE: m4 removes [], that's why it needs to be escaped bison_version=`$YACC --version | head -n 1 | sed 's/@<:@^0-9.@:>@*//'` bison_version_major=`echo $bison_version | cut -d. -f1` bison_version_minor=`echo $bison_version | cut -d. -f2` bison_version_patch=`echo $bison_version | cut -d. -f3` if ([[ "$bison_version_major" -gt 3 ]]) || ([[ "$bison_version_major" -eq 3 ]] && [[ "$bison_version_minor" -gt 7 ]]) || ([[ "$bison_version_major" -eq 3 ]] && [[ "$bison_version_minor" -eq 7 ]] && [[ "$bison_version_patch" -ge 6 ]]); then yacc_ok=1 else AC_MSG_WARN([bison is found, but your bison version $bison_version is not recent enough, at least 3.7.6 is required]) fi fi if test $yacc_ok = 0; then if test -f $srcdir/lib/cfg-grammar.c || test -f lib/cfg-grammar.c; then AC_MSG_WARN([No proper bison found, you'll not be able to change lib/cfg-grammar.y]) YACC="echo Required bison not found && false" else AC_MSG_ERROR([syslog-ng requires bison 3.7.6 or later. Your source tree seems to be from git, which doesn't have the bison generated files (like cfg-grammar.c). Please install/upgrade bison or use a distribution tarball.]) fi fi dnl *************************************************************************** dnl Validate flex if $LEX --version | grep "flex" >/dev/null; then lex_ok=1 else lex_ok=0 fi if test $lex_ok = 0 ; then if test -f $srcdir/lib/cfg-lex.c || test -f lib/cfg-lex.c; then AC_MSG_WARN([No flex found, you'll not be able to change lib/cfg-lex.l]) LEX="echo Required flex version not found && false" else AC_MSG_ERROR([syslog-ng requires flex in order to generate its config lexer. Your source tree seems to be from git, which doesn't have lib/cfg-lex.c. Please install flex or use a distribution tarball.]) fi fi dnl *************************************************************************** dnl Set up NO_PIE_LDFLAG: -no-pie is compatible with $CC. AX_COMPILER_VENDOR AX_COMPILER_VERSION if test $ostype = "Darwin"; then no_pie_ldflags="-Wl,-no_pie" else if test x$ax_cv_c_compiler_vendor = "xgnu"; then AX_COMPARE_VERSION($ax_cv_c_compiler_version, gt, [4.5], [no_pie_ldflags="-no-pie"], [no_pie_ldflags=""]) else no_pie_ldflags="-no-pie" fi; fi old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $no_pie_ldflags" AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) {return 0;}])], [no_pie_option_available=yes], [no_pie_option_available=no]) LDFLAGS="$old_LDFLAGS" if test "$no_pie_option_available" = "yes"; then NO_PIE_LDFLAG="$no_pie_ldflags" fi AC_SUBST([NO_PIE_LDFLAG]) dnl *************************************************************************** dnl Set up CFLAGS dnl The rest of CFLAGS. We produce dnl -g/-O2/-pg/-fprofile-arcs/-ftest-coverage combinations, the rest is dnl supplied by Makefile.am if test "x$ac_compiler_gnu" = "xyes"; then # by ignoring the existing $CFLAGS setting we can override the # default supplied by autoconf (which defaults to -O2), which # we don't want to use with our debugging builds. CFLAGS_ADD="" CXXFLAGS_ADD="" if test "x$enable_debug" = "xyes"; then CFLAGS_ADD="${CFLAGS_ADD} -g" CXXFLAGS_ADD="${CXXFLAGS_ADD} -g" else CFLAGS_ADD="${CFLAGS_ADD} -O2 -g" CXXFLAGS_ADD="${CXXFLAGS_ADD} -O2 -g" fi if test "x$enable_gprof" = "xyes"; then CFLAGS_ADD="${CFLAGS_ADD} -pg" CXXFLAGS_ADD="${CXXFLAGS_ADD} -pg" fi if test "x$enable_gcov" = "xyes"; then CFLAGS_ADD="${CFLAGS_ADD} -fprofile-arcs -ftest-coverage" CXXFLAGS_ADD="${CXXFLAGS_ADD} -fprofile-arcs -ftest-coverage" fi else enable_extra_warnings="no" fi CFLAGS_ADD="${CFLAGS_ADD} -pthread" dnl The current supported standard is C99 with gnu extensions if test "x$force_gnu99" = "xyes"; then CFLAGS_ADD="${CFLAGS_ADD} -std=gnu99" fi dnl We are checking for the postive warning flag, as gcc handles the dnl -Wno-XXX version oddly, so if no other warnings are present, it is not dnl reported at all, causing it to be unusable for detection purposes. AX_CFLAGS_GCC_OPTION(-Winitializer-overrides, CFLAGS_INITIALIZER_OVERRIDES, CFLAGS_ADD="${CFLAGS_ADD} -Wno-initializer-overrides") dnl User supplied CFLAGS come last CFLAGS="${CFLAGS_ADD} ${ac_cv_env_CFLAGS_value}" CXXFLAGS="${CXXFLAGS_ADD} ${ac_cv_env_CXXFLAGS_value}" AC_SYS_LARGEFILE # FIXME: skip tests on unsupported platforms/architectures... case "$ostype" in HP-UX) if $CC -v 2>&1 | grep gcc > /dev/null; then CFLAGS="${CFLAGS} -U_XOPEN_SOURCE -U_XOPEN_SOURCE_EXTENDED -D_HPUX_SOURCE" LDFLAGS="${LDFLAGS} -lcl" AC_DEFINE(HAVE_BROKEN_PREAD, 1, [define if your platform has a broken pread/pwrite (e.g. HP-UX)]) AC_MSG_WARN([NOTE: on HP-UX with gcc, you might need to edit sys/socket.h manually or you'll get compilation errors]) fi ;; AIX) if test "$ac_cv_sys_large_files" -ne 0; then CFLAGS="${CFLAGS} -D_LARGE_FILES=1" fi # NOTE: The -brtl option to the linker must be set before calling the # configure script, as otherwise the generated libtool will behave # differently. We need the runtime linker during execution (hence the # -brtl) to load external modules. Also, please note that with -brtl the # linker behaves similarly to what is expected on other UNIX systems, # without it, it refuses to link an .so in if there's no reference from # the main program, even if there is a proper -llibname option. LDFLAGS="$LDFLAGS -Wl,-brtl" MODULE_LDFLAGS="-avoid-version -module" ;; Darwin) MODULE_LDFLAGS="-avoid-version -dylib" LDFLAGS="$LDFLAGS -Wl,-flat_namespace" CFLAGS="$CFLAGS -D__APPLE_USE_RFC_3542" ;; OSF1) CFLAGS="${CFLAGS} -D_XOPEN_SOURCE=500 -D_XOPEN_SOURCE_EXTENDED -D_OSF_SOURCE -D_POSIX_C_SOURCE" ;; esac if test "$enable_dynamic_linking" = "auto" -a "$enable_mixed_linking" = "auto"; then enable_dynamic_linking="yes" enable_mixed_linking="no" fi linkopts=0 if test "x$enable_dynamic_linking" = "xyes"; then linkopts=`expr $linkopts + 1` fi if test "x$enable_mixed_linking" = "xyes"; then linkopts=`expr $linkopts + 1` fi if test "$linkopts" -gt 1; then AC_MSG_ERROR([You cannot specify multiple linking options at the same time (--enable-dynamic-linking, --enable-mixed-linking).]) fi if test "x$enable_dynamic_linking" = "xyes"; then enable_dynamic_linking="yes" enable_mixed_linking="no" linking_mode="dynamic" elif test "x$enable_mixed_linking" = "xyes"; then enable_dynamic_linking="no" enable_mixed_linking="yes" linking_mode="mixed" fi dnl *************************************************************************** dnl Check for --whole-archive flag dnl *************************************************************************** if test $ostype = "Darwin"; then WHOLE_ARCHIVE_OPT="-all_load" NO_WHOLE_ARCHIVE_OPT="-noall_load" else WHOLE_ARCHIVE_OPT="--whole-archive" NO_WHOLE_ARCHIVE_OPT="--no-whole-archive" fi dnl *************************************************************************** dnl Is the __thread keyword available? dnl *************************************************************************** AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#include __thread int a; ]], [a=0;])], [ac_cv_have_tls=yes; AC_DEFINE_UNQUOTED(HAVE_THREAD_KEYWORD, 1, "Whether Thread Local Storage is supported by the system")]) dnl *************************************************************************** dnl How to do static linking? dnl *************************************************************************** AC_MSG_CHECKING(how to enable static linking for certain libraries) ldversion=`ld -V 2>&1 | head -n 1` if echo $ldversion | egrep "GNU|Solaris" > /dev/null; then LD_START_STATIC="-Wl,-Bstatic" LD_END_STATIC="-Wl,-Bdynamic" AC_MSG_RESULT(GNU or Solaris) elif test $ostype = "HP-UX" > /dev/null; then LD_START_STATIC="-Wl,-a,archive" LD_END_STATIC="-Wl,-a,shared_archive" AC_MSG_RESULT(HP-UX) elif test "$ostype" = "AIX"; then LD_START_STATIC="-Wl,-bstatic" LD_END_STATIC="-Wl,-bdynamic" AC_MSG_RESULT(AIX) else LD_START_STATIC="" LD_END_STATIC="" AC_MSG_RESULT([no clues, linking everything dynamically, please send appropriate ld arguments to syslog-ng@lists.balabit.hu]) fi dnl *************************************************************************** dnl Miscellanneous headers dnl *************************************************************************** AC_HEADER_STDC AC_CHECK_HEADER(dmalloc.h) AC_CHECK_HEADER(dlfcn.h) AC_CHECK_HEADERS(strings.h \ getopt.h \ stropts.h \ sys/strlog.h \ door.h \ sys/capability.h \ sys/prctl.h \ linux/sock_diag.h \ utmp.h \ utmpx.h) AC_CHECK_HEADERS(tcpd.h) AC_CHECK_TYPES([struct ucred, struct cmsgcred], [], [], [#define _GNU_SOURCE 1 #define _DEFAULT_SOURCE 1 #include #include ]) dnl *************************************************************************** dnl Header checks dnl *************************************************************************** dnl Checks for typedefs, structures, and compiler characteristics. AC_STRUCT_TM AC_CHECK_MEMBER(struct tm.tm_gmtoff,AC_DEFINE(HAVE_STRUCT_TM_TM_GMTOFF,1,[Whether you have tm_gmtoff field in struct tm]),,[ #if TM_IN_SYS_TIME #include #else #include #endif]) AC_CHECK_MEMBER(struct msghdr.msg_control,AC_DEFINE(HAVE_CTRLBUF_IN_MSGHDR,1,[Whether you have msg_control field in msghdr in socket.h]),,[ #include ]) AC_CACHE_CHECK(for I_CONSLOG, blb_cv_c_i_conslog, [AC_EGREP_CPP(I_CONSLOG, [ #include I_CONSLOG ], blb_cv_c_i_conslog=no, blb_cv_c_i_conslog=yes)]) old_CPPFLAGS=$CPPFLAGS CPPFLAGS="-D_GNU_SOURCE -D_DEFAULT_SOURCE" AC_CACHE_CHECK(for O_LARGEFILE, blb_cv_c_o_largefile, [AC_EGREP_CPP(O_LARGEFILE, [ #include O_LARGEFILE ], blb_cv_c_o_largefile=no, blb_cv_c_o_largefile=yes)]) CPPFLAGS=$old_CPPFLAGS if test "x$blb_cv_c_o_largefile" = "xyes"; then AC_DEFINE(HAVE_O_LARGEFILE, 1, [O_LARGEFILE is present]) fi AC_CACHE_CHECK(for struct sockaddr_storage, blb_cv_c_struct_sockaddr_storage, [AC_EGREP_HEADER([sockaddr_storage], sys/socket.h, blb_cv_c_struct_sockaddr_storage=yes,blb_cv_c_struct_sockaddr_storage=no)]) if test "$blb_cv_c_struct_sockaddr_storage" = "yes"; then AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE,[1],[struct sockaddr_storage is present on your system]) fi AC_CACHE_CHECK(for struct sockaddr_in6, blb_cv_c_struct_sockaddr_in6, [AC_EGREP_HEADER([sockaddr_in6], netinet/in.h, blb_cv_c_struct_sockaddr_in6=yes,blb_cv_c_struct_sockaddr_in6=no)]) AC_CACHE_CHECK(for PR_SET_KEEPCAPS, blb_cv_keepcaps, [AC_EGREP_CPP(PR_SET_KEEPCAPS, [ #include PR_SET_KEEPCAPS ], blb_cv_keepcaps=no, blb_cv_keepcaps=yes)]) if test "x$blb_cv_keepcaps" = "xyes"; then AC_DEFINE(HAVE_PR_SET_KEEPCAPS, 1, [have PR_SET_KEEPCAPS]) fi if test "$ostype" != "Darwin" ; then AC_DEFINE(HAVE_ENVIRON, [1], [Specifies whether the environ global variable exists]) fi AC_CACHE_CHECK(for modern utmp, blb_cv_c_modern_utmp, [AC_TRY_COMPILE([ #ifdef HAVE_UTMPX_H #include #else #include #endif ], [ #ifdef HAVE_UTMPX_H struct utmpx ut; #else struct utmp ut; #endif return sizeof(ut.ut_type) & sizeof(ut.ut_user); ], blb_cv_c_modern_utmp=yes, blb_cv_c_modern_utmp=no)]) if test "x$blb_cv_c_modern_utmp" = "xyes"; then AC_DEFINE(HAVE_MODERN_UTMP, 1, [have modern utmp/utmpx format]) fi AC_CHECK_DECLS(SO_MEMINFO, AC_DEFINE(ENABLE_AFSOCKET_MEMINFO_METRICS, 1, [enable SO_MEMINFO based metrics in afsocket]), AC_DEFINE(ENABLE_AFSOCKET_MEMINFO_METRICS, 0, [enable SO_MEMINFO based metrics in afsocket]), [[#include ]]) dnl *************************************************************************** dnl Checks for libraries AC_CHECK_LIB(m, round, BASE_LIBS="$BASE_LIBS -lm") AC_CHECK_LIB(door, door_create, BASE_LIBS="$BASE_LIBS -ldoor") AC_CHECK_LIB(socket, socket, BASE_LIBS="$BASE_LIBS -lsocket") AC_CHECK_LIB(rt, nanosleep, BASE_LIBS="$BASE_LIBS -lrt") AC_CHECK_FUNC(gethostbyname, [], AC_CHECK_LIB(nsl, gethostbyname, BASE_LIBS="$BASE_LIBS -lnsl")) AC_CHECK_LIB(regex, regexec, REGEX_LIBS="-lregex") AC_CHECK_LIB(resolv, res_init, RESOLV_LIBS="-lresolv") AC_CHECK_FUNCS(strdup \ strtol \ strtoll \ strtoimax \ inet_aton \ inet_ntoa \ getaddrinfo \ getnameinfo \ getutent \ getutxent \ pread \ pwrite \ posix_fallocate \ strcasestr \ memrchr \ localtime_r \ getprotobynumber_r \ gmtime_r \ strnlen \ getline \ strtok_r) old_LIBS=$LIBS LIBS=$BASE_LIBS AC_CHECK_FUNCS(clock_gettime) LIBS=$old_LIBS dnl *************************************************************************** dnl check inotify dnl *************************************************************************** AC_CHECK_FUNCS([inotify_init]) dnl *************************************************************************** dnl check getrandom dnl *************************************************************************** AC_CHECK_FUNCS([getrandom]) dnl *************************************************************************** dnl libevtlog headers/libraries (remove after relicensing libevtlog) dnl *************************************************************************** EVTLOG_LIBS="\$(top_builddir)/lib/eventlog/src/libevtlog.la" EVTLOG_NO_LIBTOOL_LIBS="\$(top_builddir)/lib/eventlog/src/.libs/libevtlog.so" EVTLOG_CFLAGS="-I\$(top_srcdir)/lib/eventlog/src -I\$(top_builddir)/lib/eventlog/src" dnl *************************************************************************** dnl secret storage libraries dnl *************************************************************************** SECRETSTORAGE_LIBS="\$(top_builddir)/lib/secret-storage/libsecret-storage.la" SECRETSTORAGE_NO_LIBTOOL_LIBS="\$(top_builddir)/lib/secret-storage/.libs/libsecret-storage.so" dnl *************************************************************************** dnl libwrap headers/libraries dnl *************************************************************************** old_LIBS=$LIBS AC_CACHE_CHECK(for TCP wrapper library, blb_cv_c_lwrap, for libwrap in "-lwrap" "/usr/local/lib/libwrap.a"; do LIBS="$old_LIBS $libwrap" [AC_TRY_LINK(, [ } int allow_severity; int deny_severity; extern int hosts_access(void); int foo(void) { hosts_access(); ], [blb_cv_c_lwrap=$libwrap break], blb_cv_c_lwrap="") done ]) LIBS=$old_LIBS LIBWRAP_LIBS=$blb_cv_c_lwrap if test "x$enable_tcp_wrapper" = "xauto"; then AC_MSG_CHECKING(whether to enable TCP wrapper support) if test "x$ac_cv_header_tcpd_h" = "xyes" -a "x$blb_cv_c_lwrap" != "x"; then enable_tcp_wrapper=yes AC_MSG_RESULT(yes) else LIBWRAP_LIBS="" AC_MSG_RESULT(no) enable_tcp_wrapper=no fi elif test "x$enable_tcp_wrapper" != "xyes"; then LIBWRAP_LIBS="" fi dnl *************************************************************************** dnl -ldl dnl *************************************************************************** AC_CHECK_LIB(dl, dlsym, DL_LIBS="-ldl") dnl *************************************************************************** dnl libdbi headers/libraries dnl *************************************************************************** if test "x$enable_sql" = "xyes" || test "x$enable_sql" = "xauto"; then PKG_CHECK_MODULES(LIBDBI, dbi >= $LIBDBI_MIN_VERSION, with_libdbi="1", with_libdbi="0") if test "$with_libdbi" -eq 0; then dnl if libdbi has no .pc file (e.g., Ubuntu Precise), try it without one AC_CHECK_LIB(dbi, dbi_initialize_r, LIBDBI_LIBS="-ldbi"; LIBDBI_CFLAGS="-I/usr/include/dbi"; with_libdbi="1") fi AC_MSG_CHECKING(whether to enable SQL support) if test "$with_libdbi" -eq 1; then enable_sql="yes" AC_MSG_RESULT(yes) elif test "x$enable_sql" = "xyes"; then AC_MSG_RESULT(no) enable_sql="no" AC_MSG_ERROR([Could not find libdbi, and SQL support was explicitly enabled.]) else AC_MSG_RESULT(no) fi fi dnl *************************************************************************** dnl GLib headers/libraries dnl *************************************************************************** GLIB_ADDONS="gmodule-2.0 gthread-2.0" PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_MIN_VERSION $GLIB_ADDONS,,) if test "$linking_mode" != "dynamic"; then # strip out -ldl & -lrt as it cannot be linked statically GLIB_LIBS=`echo $GLIB_LIBS | tr ' ' '\n' | egrep -v "^(-ldld?)|(-lrt)$" | tr '\n' ' '` old_LIBS=$LIBS LIBS="$LD_START_STATIC $GLIB_LIBS $LD_END_STATIC $BASE_LIBS" AC_CHECK_FUNC(g_hash_table_new, blb_cv_static_glib=yes, blb_cv_static_glib=no) LIBS=$old_LIBS fi GLIB_CFLAGS="${GLIB_CFLAGS} -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32" old_CPPFLAGS=$CPPFLAGS CPPFLAGS="$GLIB_CFLAGS" old_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $GLIB_LIBS" old_LIBS=$LIBS LIBS="$LIBS $GLIB_LIBS" AC_CHECK_FUNCS(g_list_copy_deep \ g_ptr_array_find_with_equal_func \ g_canonicalize_filename) LIBS=$old_LIBS AC_CACHE_CHECK(sanity checking Glib headers, blb_cv_glib_sane, [AC_TRY_RUN([ #include int main() { if (sizeof(long) != GLIB_SIZEOF_LONG) return 1; return 0; } ], blb_cv_glib_sane=yes, blb_cv_glib_sane=no, blb_cv_glib_sane=yes)]) CPPFLAGS=$old_CPPFLAGS LDFLAGS=$old_LDFLAGS if test "x$blb_cv_glib_sane" = "xno"; then AC_MSG_ERROR([Glib headers inconsistent with current compiler setting. You might be using 32 bit Glib with a 64 bit compiler, check PKG_CONFIG_PATH]) fi if test "x$linking_mode" != "xdynamic" -a "x$blb_cv_static_glib" = "xno"; then AC_MSG_ERROR([static GLib libraries not found (a file named libglib-2.0.a), either link GLib dynamically using the --enable-dynamic-linking or install a static GLib]) fi dnl *************************************************************************** dnl geoip2 headers/libraries dnl *************************************************************************** if test "x$enable_geoip2" = "xyes" || test "x$enable_geoip2" = "xauto"; then if test "x$MAXMINDDB_LIBS" != "x"; then AC_MSG_CHECKING([for MAXMINDDB]) AC_MSG_RESULT([yes (MAXMINDDB_LIBS set, will use that.)]) with_maxminddb="yes" else AC_MSG_CHECKING([for MAXMINDDB]) AC_CHECK_LIB(maxminddb, MMDB_open, MAXMINDDB_LIBS="-lmaxminddb"; with_maxminddb="yes", with_maxminddb="no") AC_SUBST(MAXMINDDB_LIBS) fi if test "x$with_maxminddb" = "xno" && test "x$enable_geoip2" = "xyes"; then AC_MSG_ERROR([Could not find libmaxminddb, and geoip2 support was explicitly enabled.]) fi if test "x$with_maxminddb" = "xyes"; then AC_CONFIG_LINKS([modules/geoip2/tests/test.mmdb:modules/geoip2/tests/test.mmdb]) fi enable_geoip2="$with_maxminddb" fi dnl *************************************************************************** dnl pcre headers/libraries dnl *************************************************************************** if test "x$linking_mode" = "xmixed"; then # check if we have a pcre bundled in glib. In case glib is # dynamic it doesn't matter as glib doesn't export those # symbols. But in case glib is static, linking it through # glib and through libpcre would clash. old_LIBS="$LIBS" LIBS="$LD_START_STATIC $GLIB_LIBS $LD_END_STATIC $LIBS" AC_CHECK_FUNC(pcre_compile2, AC_MSG_ERROR([You cannot use a GLib embedded PCRE in mixed linking mode])) LIBS="$old_LIBS" fi PKG_CHECK_MODULES(PCRE2, libpcre2-8 >= $PCRE2_MIN_VERSION,, PCRE2_LIBS="") if test -z "$PCRE2_LIBS"; then AC_MSG_ERROR(Cannot find pcre2 version >= $PCRE2_MIN_VERSION which is a hard dependency from syslog-ng 3.6 onwards) fi dnl *************************************************************************** dnl OpenSSL headers/libraries dnl *************************************************************************** # openssl is needed for: # * TLS support dnl check OpenSSL static linking PKG_CHECK_MODULES(OPENSSL, openssl >= $OPENSSL_MIN_VERSION,, AC_MSG_ERROR(Cannot find OpenSSL libraries with version >= $OPENSSL_MIN_VERSION it is a hard dependency from syslog-ng 3.7 onwards)) if test -n "$OPENSSL_LIBS" -a "$linking_mode" != "dynamic"; then dnl required for openssl, but only when linking statically AC_CHECK_LIB(z, inflate, ZLIB_LIBS="-lz") dnl Remove -ldl as it cannot be linked statically on some platforms, it'll be present in DL_LIBS OPENSSL_LIBS=`echo $OPENSSL_LIBS | tr ' ' '\n' | egrep -v "^-ldld?$" | tr '\n' ' '` old_LIBS=$LIBS LIBS="$LD_START_STATIC $OPENSSL_LIBS $ZLIB_LIBS $LD_END_STATIC $DL_LIBS" AC_CHECK_FUNC(SSL_library_init, blb_cv_static_openssl=yes, blb_cv_static_openssl=no) LIBS=$old_LIBS fi CPPFLAGS_SAVE="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $OPENSSL_CFLAGS" AC_CHECK_DECLS([SSL_CTX_get0_param],[], [], [[#include ]]) AC_CHECK_DECLS([SSL_CTX_set_ciphersuites],[], [], [[#include ]]) AC_CHECK_DECLS([X509_STORE_CTX_get0_cert],[], [], [[#include ]]) AC_CHECK_DECLS([X509_get_extension_flags], [], [], [[#include ]]) AC_CHECK_DECLS([EVP_MD_CTX_reset], [], [], [[#include ]]) AC_CHECK_DECLS([ASN1_STRING_get0_data], [], [], [[#include ]]) AC_CHECK_DECLS([DH_set0_pqg], [], [], [[#include ]]) AC_CHECK_DECLS([BN_get_rfc3526_prime_2048], [], [], [[#include ]]) AC_CHECK_DECLS([SSL_CTX_set_num_tickets],[], [], [[#include ]]) AC_CHECK_DECLS([SSL_CTX_set1_sigalgs_list],[], [], [[#include ]]) AC_CHECK_DECLS([SSL_CTX_set1_client_sigalgs_list],[], [], [[#include ]]) AC_CHECK_DECLS([SSL_add_file_cert_subjects_to_stack],[], [], [[#include ]]) AC_CHECK_DECLS([SSL_add_dir_cert_subjects_to_stack],[], [], [[#include ]]) CPPFLAGS="$CPPFLAGS_SAVE" dnl dnl Right now, openssl is never linked statically as it is only used by the dnl TLS build of the afsocket plugin which is loaded dynamically anyway. dnl dnl The static check remains though, because the core may need openssl in the dnl future, in which case it becomes relevant again. dnl dnl if test "x$linking_mode" != "xdynamic" -a "x$blb_cv_static_openssl" = "xno"; then dnl AC_MSG_ERROR([static OpenSSL libraries not found (libssl.a, libcrypto.a and their external dependencies like libz.a), either link OpenSSL statically using the --enable-dynamic-linking, or install a static OpenSSL]) dnl fi dnl *************************************************************************** dnl libnet headers/libraries dnl *************************************************************************** AC_MSG_CHECKING(for LIBNET) if test "x$with_libnet" = "x"; then LIBNET_CONFIG="`which libnet-config`" else LIBNET_CONFIG="$with_libnet/libnet-config" fi if test -n "$LIBNET_CONFIG" -a -x "$LIBNET_CONFIG"; then LIBNET_CFLAGS="`$LIBNET_CONFIG --defines`" LIBNET_LIBS="`$LIBNET_CONFIG --libs`" AC_MSG_RESULT(yes) dnl libnet-config does not provide the _DEFAULT_SOURCE define, that can cause warning during build dnl as upstream libnet-config does uses _DEFAULT_SOURCE this is just a fix till LIBNET_CFLAGS="$LIBNET_CFLAGS -D_DEFAULT_SOURCE" else LIBNET_LIBS= AC_MSG_RESULT(no) fi if test "x$enable_spoof_source" = "xauto"; then AC_MSG_CHECKING(whether to enable spoof source support) if test "x$LIBNET_LIBS" != "x"; then enable_spoof_source=yes AC_MSG_RESULT(yes) else enable_spoof_source=no LIBNET_LIBS= LIBNET_CFLAGS= AC_MSG_RESULT(no) fi elif test "x$enable_spoof_source" = "xyes"; then if test "x$LIBNET_LIBS" = "x"; then AC_MSG_ERROR([Could not find libnet, and spoof source support was explicitly enabled.]) fi elif test "x$enable_spoof_source" = "xno"; then LIBNET_CFLAGS="" LIBNET_LIBS="" enable_spoof_source=no else AC_MSG_ERROR([Invalid value ($enable_spoof_source) for enable-spoof-source]) fi dnl *************************************************************************** dnl afsnmp module & net-snmp headers/libraries dnl *************************************************************************** AC_MSG_CHECKING(whether to enable snmp destination driver) if test "x$with_net_snmp" = "x"; then NETSNMP_CONFIG="`which net-snmp-config`" else NETSNMP_CONFIG="$with_net_snmp/net-snmp-config" fi if test "x$enable_afsnmp" = "xyes"; then if test -n "$NETSNMP_CONFIG" -a -x "$NETSNMP_CONFIG"; then enable_afsnmp="yes" AC_MSG_RESULT(yes) else enable_afsnmp_dest="no" AC_MSG_RESULT(no) AC_MSG_ERROR("AFSNMP module is explicit enabled but no net-snmp lib found") fi elif test "x$enable_afsnmp" = "xauto"; then if test -n "$NETSNMP_CONFIG" -a -x "$NETSNMP_CONFIG"; then enable_afsnmp="yes" AC_MSG_RESULT(yes) else enable_afsnmp="no" AC_MSG_RESULT(no) fi else enable_afsnmp="no" AC_MSG_RESULT(no) fi if test "$enable_afsnmp" = "yes"; then NETSNMP_CFLAGS="`$NETSNMP_CONFIG --cflags`" NETSNMP_LIBS="`$NETSNMP_CONFIG --libs`" else NETSNMP_CFLAGS= NETSNMP_LIBS= fi dnl *************************************************************************** dnl Criterion headers/libraries dnl *************************************************************************** PKG_CHECK_MODULES(CRITERION, criterion >= $CRITERION_MIN_VERSION, [with_criterion="system"], [AC_MSG_WARN([pkg-config was not able to find Criterion >= $CRITERION_MIN_VERSION]); with_criterion="no"]) if test "$with_criterion" != "no"; then enable_tests=yes else enable_tests=no fi dnl *************************************************************************** dnl ivykis headers/libraries dnl *************************************************************************** IVYKIS_INTERNAL_SOURCE_EXISTS="test -f $srcdir/lib/ivykis/src/iv_main_posix.c" if $IVYKIS_INTERNAL_SOURCE_EXISTS; then AC_CONFIG_SUBDIRS([lib/ivykis]) IVYKIS_SUBDIRS=lib/ivykis fi INTERNAL_IVYKIS_CFLAGS="" if test "x$with_ivykis" = "xinternal"; then if $IVYKIS_INTERNAL_SOURCE_EXISTS; then # these can only be used in lib as it assumes # the current directory just one below ivykis IVYKIS_LIBS="-Wl,${WHOLE_ARCHIVE_OPT} -L\$(top_builddir)/lib/ivykis/src -livykis -Wl,${NO_WHOLE_ARCHIVE_OPT}" IVYKIS_CFLAGS="-isystem \$(top_srcdir)/lib/ivykis/src/include -isystem \$(top_builddir)/lib/ivykis/src/include" INTERNAL_IVYKIS_CFLAGS="-isystem \${includedir}/syslog-ng/ivykis" IVYKIS_VERSION_UPDATED="yes" # LIBS to use when libtool is not applicable (when linking the main syslog-ng executable in mixed linking mode) IVYKIS_NO_LIBTOOL_LIBS="-Wl,${WHOLE_ARCHIVE_OPT} -L\$(top_builddir)/lib/ivykis/src/.libs -livykis -Wl,${NO_WHOLE_ARCHIVE_OPT}" AC_DEFINE(HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION, 1) else AC_MSG_ERROR([Internal ivykis sources not found in lib/ivykis. This is a hard dependency, unable to build syslog-ng without them.]) fi else with_ivykis="system" PKG_CHECK_MODULES(IVYKIS, ivykis >= $IVYKIS_MIN_VERSION,,) PKG_CHECK_MODULES(IVYKIS_VERSION_CHECK, ivykis >= $IVYKIS_UPDATED_VERSION, [IVYKIS_VERSION_UPDATED="yes"], [IVYKIS_VERSION_UPDATED="no"]) # in case we're using a system installed ivykis, we can link against # it even without libtool and without extra linker arguments (as # we're linking dynamically) IVYKIS_NO_LIBTOOL_LIBS="$IVYKIS_LIBS" dnl check if iv_work_pool_submit_continuation is available in the system ivykis old_LIBS=$LIBS LIBS="$LIBS $IVYKIS_LIBS" AC_CHECK_FUNCS(iv_work_pool_submit_continuation, [], [AC_DEFINE(HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION, 0)]) LIBS=$old_LIBS fi dnl *************************************************************************** dnl json headers/libraries dnl *************************************************************************** enable_json="no" if test "x$with_jsonc" = "xinternal"; then AC_MSG_ERROR([The internal (bundled) json-c library is no longer supported!]) fi if test "x$with_jsonc" = "xsystem"; then with_jsonc="yes" fi if test "x$with_jsonc" = "xyes" -o "x$with_jsonc" = "xauto"; then enable_json="yes" PKG_CHECK_EXISTS(json-c, json_module_name="json-c", PKG_CHECK_EXISTS(json, json_module_name="json")) PKG_CHECK_MODULES(JSON, $json_module_name >= $JSON_C_MIN_VERSION,[with_jsonc="yes"], [JSON_LIBS=""; enable_json="no"]) if test "x$with_jsonc" = "xyes" -a "x$enable_json" = "xno"; then AC_MSG_ERROR([json-c library development files cannot be not found on system!]) fi fi dnl *************************************************************************** dnl mongo-c-driver headers/libraries dnl *************************************************************************** PKG_CHECK_MODULES(LIBMONGO, libmongoc-1.0 >= $LMC_MIN_VERSION, with_mongoc="yes", with_mongoc="no") if test "x$with_mongoc" = "xno" && test "x$enable_mongodb" = "xyes"; then AC_MSG_ERROR([Could not find mongo-c-driver, and MongoDB support was explicitly enabled.]) fi if test "x$with_mongoc" = "xyes"; then CPPFLAGS_SAVE="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $LIBMONGO_CFLAGS" AC_CHECK_DECLS([mongoc_uri_set_option_as_int32], [], [], [[#include ]]) AC_CHECK_DECLS([MONGOC_URI_SERVERSELECTIONTIMEOUTMS], [], [], [[#include ]]) CPPFLAGS="$CPPFLAGS_SAVE" fi dnl *************************************************************************** dnl libesmtp headers/libraries dnl *************************************************************************** if test "x$enable_smtp" != "xno" && test "x$with_libesmtp" != "xno"; then libesmtp="yes" if test "x$with_libesmtp" != "xyes" && test "x$with_libesmtp" != "x"; then CPPFLAGS_SAVE="$CPPFLAGS" LDFLAGS_SAVE="$LDFLAGS" CPPFLAGS="$CPPFLAGS -I$with_libesmtp/include" LDFLAGS="$LDFLAGS -L$with_libesmtp/lib" AC_CHECK_HEADER(libesmtp.h, [LIBESMTP_CFLAGS="-I$with_libesmtp/include" LIBESMTP_LIBS="-L$with_libesmtp/lib -lesmtp"], [libesmtp=no]) CPPFLAGS="$CPPFLAGS_SAVE" LDFLAGS="$LDFLAGS_SAVE" else PKG_CHECK_MODULES(LIBESMTP, libesmtp-1.0, libesmtp="yes", libesmtp="no") if test "x$libesmtp" = "xno"; then AC_MSG_CHECKING(for libESMTP with libesmtp-config) if libesmtp-config --version >/dev/null 2>&1; then AC_MSG_RESULT(yes) LIBESMTP_CFLAGS="`libesmtp-config --cflags`" LIBESMTP_LIBS="`libesmtp-config --libs`" libesmtp="yes" else AC_MSG_RESULT(no) libesmtp=no fi fi fi if test "x$enable_smtp" = "xyes" && test "x$libesmtp" = "xno"; then AC_MSG_ERROR(libESMTP not found) fi enable_smtp=$libesmtp fi dnl *************************************************************************** dnl libmqtt headers/libraries dnl *************************************************************************** if test "x$enable_mqtt" = "xyes" || test "x$enable_mqtt" = "xauto"; then if test "x$with_libpaho_mqtt" != "x"; then CPPFLAGS_SAVE="$CPPFLAGS" LDFLAGS_SAVE="$LDFLAGS" CPPFLAGS="$CPPFLAGS -I$with_libpaho_mqtt/include" LDFLAGS="$LDFLAGS -L$with_libpaho_mqtt -lpaho-mqtt3cs" AC_CHECK_HEADER(MQTTClient.h, [LIBPAHO_MQTT_CFLAGS="-I$with_libpaho_mqtt/include" LIBPAHO_MQTT_LIBS="-L$with_libpaho_mqtt/lib -lpaho-mqtt3cs" libpaho_mqtt="yes"], [libpaho_mqtt=no]) CPPFLAGS="$CPPFLAGS_SAVE" LDFLAGS="$LDFLAGS_SAVE" else AC_CHECK_LIB(paho-mqtt3cs, MQTTClient_create, LIBPAHO_MQTT_LIBS="-lpaho-mqtt3cs"; libpaho_mqtt="yes", libpaho_mqtt="no") fi if test "x$enable_mqtt" = "xyes" && test "x$libpaho_mqtt" = "xno"; then AC_MSG_ERROR(libPAHO_MQTT not found) fi if test "x$libpaho_mqtt" = "xyes"; then CPPFLAGS_SAVE="$CPPFLAGS" LDFLAGS_SAVE="$LDFLAGS" CPPFLAGS="$CPPFLAGS $LIBPAHO_MQTT_CFLAGS" LDFLAGS="$LDFLAGS $LIBPAHO_MQTT_LIBS" AC_CHECK_MEMBER([MQTTClient_connectOptions.httpProxy], [have_paho_http_proxy=1], [have_paho_http_proxy=0], [[#include "MQTTClient.h"]]) CPPFLAGS="$CPPFLAGS_SAVE" LDFLAGS="$LDFLAGS_SAVE" AC_DEFINE_UNQUOTED(HAVE_PAHO_HTTP_PROXY, $have_paho_http_proxy, [libpaho-mqtt supports MQTTClient_connectOptions::httpProxy]) fi enable_mqtt=$libpaho_mqtt fi dnl *************************************************************************** dnl GRPC headers/libraries dnl *************************************************************************** # C++ if ! test "x$enable_grpc" = "xno"; then if test "x$enable_cpp" = "xno"; then if test "x$enable_grpc" = "xyes"; then AC_MSG_ERROR(C++ support is mandatory when the GRPC modules are enabled.) else enable_grpc=no fi fi fi # ProtoBuf libraries if ! test "x$enable_grpc" = "xno"; then PKG_CHECK_MODULES(PROTOBUF, protobuf >= $PROTOBUF_MIN_VERSION, protobuf_found="yes", protobuf_found="no") if test "$protobuf_found" = "no"; then if test "x$enable_grpc" = "xyes"; then AC_MSG_ERROR(ProtoBuf libraries not found.) else enable_grpc=no fi fi fi # ProtoC compiler if ! test "x$enable_grpc" = "xno"; then if ! test "x$with_protoc" = "x"; then PROTOC=$with_protoc else AC_PATH_PROG([PROTOC], [protoc]) if test "x$PROTOC" = "x"; then if test "x$enable_grpc" = "xyes"; then AC_MSG_ERROR(ProtoBuf compiler "protoc" not found.) else enable_grpc=no fi else PROTOC_VERSION=`${PROTOC} --version | cut -f2 -d' '` PROTOC_VERSION_MAJOR=`echo $PROTOC_VERSION | cut -f1 -d'.'` PROTOC_VERSION_MINOR=`echo $PROTOC_VERSION | cut -f2 -d'.'` PROTOC_VERSION_PATCH=`echo $PROTOC_VERSION | cut -f3 -d'.'` fi fi fi # GRPC CPP plugin for ProtoC compiler if ! test "x$enable_grpc" = "xno"; then if ! test "x$with_protoc_gen_grpc_cpp_plugin" = "x"; then PROTOC_GEN_GRPC_CPP_PLUGIN=$with_protoc_gen_grpc_cpp_plugin else AC_PATH_PROG([PROTOC_GEN_GRPC_CPP_PLUGIN], [grpc_cpp_plugin]) if test "x$PROTOC_GEN_GRPC_CPP_PLUGIN" = "x"; then if test "x$enable_grpc" = "xyes"; then AC_MSG_ERROR(GRPC CPP plugin for ProtoC compiler not found.) else enable_grpc=no fi fi fi if ! test "x$PROTOC_GEN_GRPC_CPP_PLUGIN" = "x"; then PROTOC_GEN_GRPC_CPP_PLUGIN_FLAGS='--plugin=protoc-gen-grpc-cpp="${PROTOC_GEN_GRPC_CPP_PLUGIN}"' if test ${PROTOC_VERSION_MAJOR} -eq 3 -a ${PROTOC_VERSION_MINOR} -lt 15; then PROTOC_GEN_GRPC_CPP_PLUGIN_FLAGS="${PROTOC_GEN_GRPC_CPP_PLUGIN_FLAGS} --experimental_allow_proto3_optional" fi AC_SUBST(PROTOC_GEN_GRPC_CPP_PLUGIN_FLAGS) fi fi # GRPC++ libraries if ! test "x$enable_grpc" = "xno"; then PKG_CHECK_MODULES(GRPCPP, grpc++ >= $GRPCPP_MIN_VERSION, grpcpp_found="yes", grpcpp_found="no") if test "$grpcpp_found" = "no"; then if test "x$enable_grpc" = "xyes"; then AC_MSG_ERROR(GRPC++ libraries not found.) else enable_grpc=no fi fi fi if ! test "x$enable_grpc" = "xno"; then enable_grpc=yes fi dnl *************************************************************************** dnl libcurl headers/libraries dnl *************************************************************************** if test "x$enable_http" != "xno" && test "x$with_libcurl" != "xno"; then libcurl="yes" if test "x$with_libcurl" != "xyes" && test "x$with_libcurl" != "x"; then CPPFLAGS_SAVE="$CPPFLAGS" LDFLAGS_SAVE="$LDFLAGS" CPPFLAGS="$CPPFLAGS -I$with_libcurl/include" LDFLAGS="$LDFLAGS -L$with_libcurl/lib" AC_CHECK_HEADER(curl/curl.h, [LIBCURL_CFLAGS="-I$with_libcurl/include" LIBCURL_LIBS="-L$with_libcurl/lib -lcurl"], [libcurl=no]) CPPFLAGS="$CPPFLAGS_SAVE" LDFLAGS="$LDFLAGS_SAVE" else AC_MSG_CHECKING(for libcurl) if curl-config --version >/dev/null 2>&1; then AC_MSG_RESULT(yes) LIBCURL_CFLAGS="`curl-config --cflags`" LIBCURL_LIBS="`curl-config --libs`" else AC_MSG_RESULT(no) libcurl=no fi fi if test "x$enable_http" = "xyes" && test "x$libcurl" = "xno"; then AC_MSG_ERROR(libcurl not found) fi enable_http=$libcurl if test "$enable_http" = "yes"; then old_CFLAGS=$CFLAGS CFLAGS=$LIBCURL_CFLAGS AC_CHECK_DECLS([CURL_SSLVERSION_TLSv1_0, CURL_SSLVERSION_TLSv1_1, CURL_SSLVERSION_TLSv1_2, CURL_SSLVERSION_TLSv1_3, CURLOPT_TLS13_CIPHERS, CURLOPT_SSL_VERIFYSTATUS, CURLOPT_REDIR_PROTOCOLS_STR], [], [], [[#include ]]) CFLAGS=$old_CFLAGS AC_CHECK_HEADER(zlib.h, AC_DEFINE(HAVE_ZLIB, , [Define if zlib is available]), AC_MSG_WARN([ZLIB not found.])) fi fi dnl *************************************************************************** dnl libhiredis headers/libraries dnl *************************************************************************** if test "x$enable_redis" != "xno" && test "x$with_redis" != "xno"; then hiredis="yes" if test "x$with_libhiredis" != "xyes" && test "x$with_libhiredis" != "x"; then CFLAGS_SAVE="$CFLAGS" LDFLAGS_SAVE="$LDFLAGS" CFLAGS="$CFLAGS -I$with_libhiredis/include" LDFLAGS="$LDFLAGS -L$with_libhiredis/lib" AC_CHECK_HEADER(hiredis/hiredis.h, [HIREDIS_CFLAGS="-I$with_libhiredis/include" HIREDIS_LIBS="-L$with_libhiredis/lib -lhiredis"], [hiredis=no]) CFLAGS="$CFLAGS_SAVE" LDFLAGS="$LDFLAGS_SAVE" else hiredis="yes" PKG_CHECK_MODULES(HIREDIS, hiredis >= $HIREDIS_MIN_VERSION, , [AC_MSG_WARN([pkg-config was not able to find hiredis >= $HIREDIS_MIN_VERSION]) PKG_CHECK_MODULES(HIREDIS, libhiredis >= $HIREDIS_MIN_VERSION,, [AC_MSG_WARN([pkg-config was not able to find libhiredis >= $HIREDIS_MIN_VERSION]) hiredis=no])]) fi if test "x$enable_redis" = "xyes" && test "x$hiredis" = "xno"; then AC_MSG_ERROR(libHIREDIS not found) fi enable_redis=$hiredis fi dnl *************************************************************************** dnl rabbitmq-c headers/libraries dnl *************************************************************************** PKG_CHECK_MODULES(LIBRABBITMQ, librabbitmq >= $LIBRABBITMQ_MIN_VERSION, with_librabbitmq_client="yes", with_librabbitmq_client="no") if test "$enable_amqp" = "yes" && test "$with_librabbitmq_client" = "no"; then AC_MSG_ERROR([Could not find librabbitmq-c, and AMQP support was explicitly enabled.]) fi old_LIBS=$LIBS LIBS=$LIBRABBITMQ_LIBS AC_CHECK_FUNCS(amqp_ssl_socket_set_verify_peer) LIBS=$old_LIBS dnl *************************************************************************** dnl rdkafka headers/libraries dnl *************************************************************************** PKG_CHECK_MODULES(LIBRDKAFKA, rdkafka >= $LIBRDKAFKA_MIN_VERSION, with_librdkafka="yes", with_librdkafka="no") if test "$enable_kafka" = "yes" && test "$with_librdkafka" = "no"; then AC_MSG_ERROR([Could not find librdkafka, and Kafka support was explicitly enabled.]) fi dnl dnl Check if librdkafka has transactional api dnl old_LIBS=$LIBS old_CFLAGS=$CFLAGS LIBS=$LIBRDKAFKA_LIBS CFLAGS=$LIBRDKAFKA_CFLAGS AC_CHECK_FUNCS(rd_kafka_init_transactions) LIBS=$old_LIBS CFLAGS=$old_CFLAGS if test "x$enable_native" = "xyes" -o "x$enable_native" = "xauto"; then AC_CONFIG_FILES([syslog-ng-native-connector.pc]) fi dnl *************************************************************************** dnl riemann-client headers/libraries dnl *************************************************************************** if test "$enable_riemann" != "no"; then PKG_CHECK_MODULES(RIEMANN_CLIENT, riemann-client >= $LRC_MIN_VERSION,,riemann_found="no") if test "$riemann_found" = "no" && test "$enable_riemann" = "yes"; then AC_MSG_ERROR([Dependency for Riemann not found!]) fi if test "$riemann_found" = "no"; then enable_riemann="no"; else enable_riemann="yes"; fi if test "$enable_riemann" = "yes"; then old_CFLAGS=$CFLAGS CFLAGS=`pkg-config --cflags riemann-client` AC_CHECK_DECLS(RIEMANN_EVENT_FIELD_TIME_MICROS, AC_DEFINE(HAVE_RIEMANN_MICROSECONDS, 1, [Riemann microseconds support]),, [[#include ]]) CFLAGS=$old_CFLAGS fi fi dnl *************************************************************************** dnl libsystemd headers/libraries dnl *************************************************************************** PKG_CHECK_MODULES(libsystemd, libsystemd >= ${LIBSYSTEMD_MIN_VERSION}, have_libsystemd="yes", have_libsystemd="no") PKG_CHECK_MODULES(libsystemd_namespaces, libsystemd >= ${LIBSYSTEMD_WITH_JOURNAL_NAMESPACES_MIN_VERSION}, journal_namespaces="yes", journal_namespaces="no") dnl *************************************************************************** dnl python checks dnl *************************************************************************** if test "x$enable_python" != "xno"; then if test "x$with_python" = "xauto"; then PKG_CHECK_MODULES(PYTHON, python3-embed, python_found="yes", [ PKG_CHECK_MODULES(PYTHON, python3, python_found="yes", python_found="no") ]) else case "$with_python" in [[0-9]]) with_python="python${with_python}" ;; [[0-9]].[[0-9]]) with_python="python-${with_python}" ;; [[0-9]].[[0-9][0-9]]) with_python="python-${with_python}" ;; esac PKG_CHECK_MODULES(PYTHON, $with_python-embed, python_found="yes", [ PKG_CHECK_MODULES(PYTHON, $with_python, python_found="yes", python_found="no") ]) fi if test "x$enable_python" = "xyes" -a "x$python_found" = "xno"; then AC_MSG_ERROR([Could not find the requested Python development libraries]) fi enable_python="$python_found" else with_python="" fi if test "x$enable_python" = "xyes"; then if test "x$with_python_packages" = "xvenv"; then PYTHON_VENV_DIR=`pwd`/venv PYTHON_VENV=${PYTHON_VENV_DIR}/bin/python elif test "x$with_python_packages" = "xnone"; then PYTHON_VENV=$PYTHON else with_python_packages="system" PYTHON_VENV=$PYTHON fi fi dnl *************************************************************************** dnl python modules dnl *************************************************************************** if test "x$enable_python_modules" = "xauto"; then enable_python_modules=$enable_python fi dnl *************************************************************************** dnl docbook dnl *************************************************************************** if test "x$enable_manpages" != "xno"; then if test "x$with_docbook" = "xauto"; then XSL_STYLESHEET=`find /usr/share/{xml,sgml} -path '*/manpages/docbook.xsl' 2>/dev/null | head -n 1` if test -z "$XSL_STYLESHEET"; then XSL_STYLESHEET="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl" fi else XSL_STYLESHEET=$with_docbook fi fi if test "x$enable_manpages_install" = "xauto"; then dnl do we have the generated manpages (part of the tarball but not in git) if test -f doc/man/syslog-ng.8 -o "x$enable_manpages" = "xyes"; then enable_manpages_install=yes else enable_manpages_install=no fi fi dnl *************************************************************************** dnl java headers/libraries dnl *************************************************************************** if test "x$enable_java" = "xauto" || test "x$enable_java" = "xyes"; then if test "x$enable_java" = "xauto"; then AC_CHECK_JAVA_VERSION([$JAVA_MIN_VERSION], [enable_java=yes], [enable_java=no]) else AC_CHECK_JAVA_VERSION([$JAVA_MIN_VERSION], [enable_java=yes], [AC_MSG_ERROR([Java not found])]) fi fi if test "x$enable_java" = "xyes"; then if test "x$enable_java_modules" = "xauto" || test "x$enable_java_modules" = "xyes"; then if test "x$enable_java_modules" = "xauto"; then AC_CHECK_GRADLE_VERSION([$GRADLE_MIN_VERSION], [enable_java_modules=yes], [enable_java_modules=no]) else AC_CHECK_GRADLE_VERSION([$GRADLE_MIN_VERSION], [enable_java_modules=yes], [AC_MSG_ERROR([Gradle not found])]) fi fi else if test "x$enable_java_modules" = "xyes"; then AC_MSG_ERROR([Could not build Java modules without Java]) elif test "x$enable_java_modules" = "xauto"; then AC_MSG_WARN([Could not build Java modules without Java]) enable_java_modules=no fi fi dnl *************************************************************************** dnl misc features to be enabled dnl *************************************************************************** if test "x$ac_cv_lib_door_door_create" = "xyes"; then AC_CHECK_HEADERS(pthread.h) AC_CHECK_LIB(pthread, pthread_create) fi AC_MSG_CHECKING(whether to enable Sun STREAMS support) if test "x$ac_cv_header_stropts_h" = "xyes" -a \ "x$ac_cv_header_sys_strlog_h" = "xyes" -a \ "x$enable_sun_streams" != "xno" -a \ "x$blb_cv_c_i_conslog" != "xno"; then enable_sun_streams=yes AC_MSG_RESULT(yes) else enable_sun_streams=no AC_MSG_RESULT(no) fi AC_MSG_CHECKING(whether to enable OpenBSD system source support) if test "x$enable_openbsd_system_source" = "xyes"; then enable_openbsd_system_source="yes" AC_MSG_RESULT(yes) elif test "x$enable_openbsd_system_source" = "xauto" -a \ "$ostype" = "OpenBSD" ; then enable_openbsd_system_source="yes" AC_MSG_RESULT(yes) else enable_openbsd_system_source="no" AC_MSG_RESULT(no) fi if test "x$enable_env_wrapper" = "xauto"; then if test "x$env_ld_library_path" != "x"; then enable_env_wrapper="yes" else enable_env_wrapper="no" fi fi if test "x$enable_ipv6" = "xauto"; then AC_MSG_CHECKING(whether to enable IPv6 support) if test "x$blb_cv_c_struct_sockaddr_in6" = "xyes"; then enable_ipv6=yes AC_MSG_RESULT(yes) else enable_ipv6=no AC_MSG_RESULT(no) fi fi AC_CHECK_DECLS([TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT], [], [], [[#include #include #include ]]) if test "x$ac_cv_have_decl_TCP_KEEPIDLE" = "xyes" -a "x$ac_cv_have_decl_TCP_KEEPINTVL" = "xyes" -a "x$ac_cv_have_decl_TCP_KEEPCNT" = "xyes"; then AC_DEFINE(HAVE_TCP_KEEPALIVE_TIMERS, 1, [TCP keepalive timers]) fi if test "x$enable_linux_caps" = "xyes" -o "x$enable_linux_caps" = "xauto"; then PKG_CHECK_MODULES(LIBCAP, libcap, has_linux_caps="yes", has_linux_caps="no") if test "x$has_linux_caps" = "xno"; then if test "x$ac_cv_header_sys_capability_h" = "xyes"; then AC_CHECK_LIB(cap, cap_set_proc, LIBCAP_LIBS="-lcap"; has_linux_caps="yes", has_linux_caps="no") else has_linux_caps="no" fi AC_MSG_CHECKING(whether to enable Linux capability support) AC_MSG_RESULT([$has_linux_caps]) fi if test "x$enable_linux_caps" = "xyes" -a "x$has_linux_caps" = "xno"; then AC_MSG_ERROR([Cannot enable Linux capability support.]) fi enable_linux_caps="$has_linux_caps" fi if test "x$enable_mongodb" = "xauto"; then AC_MSG_CHECKING(whether to enable mongodb destination support) if test "x$with_mongoc" != "xno"; then enable_mongodb="yes" else enable_mongodb="no" fi AC_MSG_RESULT([$enable_mongodb]) fi if test "x$enable_amqp" = "xauto"; then AC_MSG_CHECKING(whether to enable amqp destination support) if test "x$with_librabbitmq_client" != "xno"; then enable_amqp="yes" else enable_amqp="no" fi AC_MSG_RESULT([$enable_amqp]) fi if test "x$enable_kafka" = "xauto"; then AC_MSG_CHECKING(whether to enable kafka support) if test "x$with_librdkafka" != "xno"; then enable_kafka="yes" else enable_kafka="no" fi AC_MSG_RESULT([$enable_kafka]) fi if test "x$enable_systemd" = "xauto"; then if test "$ostype" = "Linux" -a "$have_libsystemd" = "yes"; then enable_systemd=yes else enable_systemd=no fi fi if test "x$enable_systemd" != "xyes"; then if test "x$with_systemd_journal" = "xauto"; then with_systemd_journal=no fi fi if test "x$enable_systemd" = "xyes"; then if test "x$with_systemdsystemunitdir" = "xyes"; then # no arguments, just --with-systemdsystemunitdir systemdsystemunitdir=`$PKG_CONFIG --variable=systemdsystemunitdir systemd` if test "$systemdsystemunitdir" = ""; then AC_MSG_ERROR([Error autodetecting systemdsystemunitdir, systemd pkg-config file not found?]) fi elif test "$systemdsystemunitdir" = "no"; then # --without-systemdsystemunitdir was specified systemdsystemunitdir="" else systemdsystemunitdir="$with_systemdsystemunitdir" fi if test "x$have_libsystemd" = "xno"; then PKG_CHECK_MODULES(libsystemd_daemon, libsystemd-daemon >= 31,enable_systemd="yes",enable_systemd="no") if test "x$with_systemd_journal" = "xauto"; then PKG_CHECK_MODULES(LIBSYSTEMD_JOURNAL, libsystemd-journal >= $JOURNALD_MIN_VERSION, with_systemd_journal=system, with_systemd_journal=optional) elif test "x$with_systemd_journal" = "xsystem"; then PKG_CHECK_MODULES(LIBSYSTEMD_JOURNAL, libsystemd-journal >= $JOURNALD_MIN_VERSION,, AC_MSG_ERROR([Detecting system related systemd-journal library failed])) fi libsystemd_CFLAGS="${LIBSYSTEMD_JOURNAL_CFLAGS} ${libsystemd_daemon_CFLAGS}" libsystemd_LIBS="${LIBSYSTEMD_JOURNAL_LIBS} ${libsystemd_daemon_LIBS}" AC_SUBST(libsystemd_CFLAGS) AC_SUBST(libsystemd_LIBS) else if test "x$with_systemd_journal" = "xauto"; then with_systemd_journal="system" fi fi fi if test "x$enable_ebpf" = "xyes"; then PKG_CHECK_MODULES(LIBBPF, libbpf >= $LIBBPF_MIN_VERSION) # we are using a distinct C compiler for compiling BPF code and # pkg-config removes builtin paths from its output. Reference it # directly. LIBBPF_INCLUDE=`$PKG_CONFIG --variable includedir libbpf` AC_PATH_PROG(BPFTOOL, bpftool) AC_PATH_PROG(BPF_CC, clang) if test "$BPFTOOL" = "" -o "$BPF_CC" = ""; then AC_MSG_ERROR([eBPF toolchain is required to build with eBPF (bpftool and clang)]) fi AC_SUBST(BPFTOOL) AC_SUBST(BPF_CC) fi dnl *************************************************************************** dnl check if we have timezone variable in dnl *************************************************************************** AC_VAR_TIMEZONE_EXTERNALS dnl *************************************************************************** dnl check fmemopen dnl *************************************************************************** AC_CHECK_FUNCS([fmemopen]) dnl *************************************************************************** dnl sanitizer dnl *************************************************************************** if test "x$with_sanitizer" != "xno"; then CFLAGS="$CFLAGS -O1 -fsanitize=$with_sanitizer -fno-omit-frame-pointer" fi dnl *************************************************************************** dnl default modules to be loaded dnl *************************************************************************** ### The default set of modules are those that provide functionality that ### were provided in syslog-ng 3.2 and prior, unless explicitly overridden ### by the user. ### ### New plugins can be loaded by explicit "@module foo" lines in the ### configuration file, or by the autoloading mechanism. if test "x$module_path" = "x"; then module_path="$moduledir" java_module_path="$moduledir"/java-modules fi python_moduledir="$moduledir"/python python_sysconf_moduledir="${sysconfdir}/python" CPPFLAGS="$CPPFLAGS $GLIB_CFLAGS $EVTLOG_CFLAGS $PCRE2_CFLAGS $OPENSSL_CFLAGS $LIBNET_CFLAGS $LIBDBI_CFLAGS $IVYKIS_CFLAGS $LIBCAP_CFLAGS -D_GNU_SOURCE -D_DEFAULT_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" ######################################################## ## NOTES: on how syslog-ng is linked # # There are two major linking modes currently: # 1) dynamic: all libraries are linked dynamically, and assumed to be available as dynamic libraries # # 2) mixed: typical system provided libraries are linked dynamicaly, the # rest is linked statically (Glib etc). Please note that _only_ the # main syslog-ng executable is linked this way so that it can be # started early during startup, tools and unit tests are linked # dynamically the same way. # # The following variables are introduced and AC_SUBSTed to be used in Makefiles: # # SYSLOGNG_DEPS_LIBS: # includes all dependendent libraries used by binary that can be linked in mixed mode (e.g. only the syslog-ng binary). # # TOOL_DEPS_LIBS: # executables (e.g. tools & unit test programs) that link against # libsyslog-ng.so should be linked with this set of libraries. other # tools that do not use libsyslog-ng.so can use the _LIBS variables # directly. # # CORE_DEPS_LIBS: # libsyslog-ng.so is linked with this set of libraries. # # MODULE_DEPS_LIBS: # The set of libraries that modules should be linked against. Only to # satisfy their "core" dependency, any other libs that the core doesn't # depend on must be linked explicitly. # # MODULE_LDFLAGS: # The LDFLAGS to be passed when linking modules (may not contain # library references -l and such, only linker flags) # # Modules should be linked against libsyslog-ng.la and libraries that are # _NOT_ linked into libsyslog-ng.la no need to define a LIBS variable for # that. if test -z "$MODULE_LDFLAGS"; then MODULE_LDFLAGS="-avoid-version -module -no-undefined" fi MODULE_DEPS_LIBS="\$(top_builddir)/lib/libsyslog-ng.la" if test "x$linking_mode" = "xdynamic"; then SYSLOGNG_DEPS_LIBS="$LIBS $BASE_LIBS $GLIB_LIBS $EVTLOG_LIBS $SECRETSTORAGE_LIBS $RESOLV_LIBS $LIBCAP_LIBS $PCRE2_LIBS $REGEX_LIBS $DL_LIBS" if test "x$with_ivykis" = "xinternal"; then # when using the internal ivykis, we're linking it statically into libsyslog-ng.so TOOL_DEPS_LIBS="$SYSLOGNG_DEPS_LIBS" CORE_DEPS_LIBS="$SYSLOGNG_DEPS_LIBS $IVYKIS_LIBS" else # otherwise everything needs to link against libivykis.so SYSLOGNG_DEPS_LIBS="$SYSLOGNG_DEPS_LIBS $IVYKIS_LIBS" TOOL_DEPS_LIBS="$SYSLOGNG_DEPS_LIBS" CORE_DEPS_LIBS="$SYSLOGNG_DEPS_LIBS" fi # syslog-ng binary is linked with the default link command (e.g. libtool) SYSLOGNG_LINK='$(LINK)' else SYSLOGNG_DEPS_LIBS="$LIBS $BASE_LIBS $RESOLV_LIBS $EVTLOG_NO_LIBTOOL_LIBS $SECRETSTORAGE_NO_LIBTOOL_LIBS $LD_START_STATIC -Wl,${WHOLE_ARCHIVE_OPT} $GLIB_LIBS $PCRE2_LIBS $REGEX_LIBS -Wl,${NO_WHOLE_ARCHIVE_OPT} $IVYKIS_NO_LIBTOOL_LIBS $LD_END_STATIC $LIBCAP_LIBS $DL_LIBS" TOOL_DEPS_LIBS="$LIBS $BASE_LIBS $GLIB_LIBS $EVTLOG_LIBS $SECRETSTORAGE_LIBS $RESOLV_LIBS $LIBCAP_LIBS $PCRE2_LIBS $REGEX_LIBS $IVYKIS_LIBS $DL_LIBS" CORE_DEPS_LIBS="" # bypass libtool in case we want to do mixed linking because it # doesn't support -Wl,-Bstatic -Wl,-Bdynamic on a per-library basis. SYSLOGNG_LINK='$(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@' fi YFLAGS="-d" enable_value() { if test "x$1" = "xyes" ; then echo 1 else echo 0 fi } journald_mode() { if test "x$with_systemd_journal" = "xno"; then echo SYSLOG_NG_JOURNALD_OFF elif test "x$with_systemd_journal" = "xsystem"; then echo SYSLOG_NG_JOURNALD_SYSTEM else echo SYSLOG_NG_JOURNALD_OPTIONAL fi } AC_DEFINE_UNQUOTED(JOURNALD_OFF, 0, ["Disable systemd-journal source"]) AC_DEFINE_UNQUOTED(JOURNALD_OPTIONAL, 1, ["Enable systemd-journal source if journald is available"]) AC_DEFINE_UNQUOTED(JOURNALD_SYSTEM, 2, ["Force systemd-journal source to use system's journald"]) AC_DEFINE_UNQUOTED(HAVE_JOURNAL_NAMESPACES, `(test "$journal_namespaces" = "yes" ) && echo 1 || echo 0`, [have journal namespaces]) AC_DEFINE_UNQUOTED(VERSION, "$PACKAGE_VERSION", [version number]) AC_DEFINE_UNQUOTED(SOURCE_REVISION, "$SOURCE_REVISION", [source revision]) AC_DEFINE_UNQUOTED(LICENSE_VERSION, "$LICENSE_VERSION", [Required license version]) AC_DEFINE_UNQUOTED(PATH_PREFIX, "$prefix", [prefix directory]) AC_DEFINE_UNQUOTED(PATH_EXECPREFIX, "$exec_prefix", [execprefix directory]) AC_DEFINE_UNQUOTED(PATH_SYSCONFDIR, "$sysconfdir", [sysconfdir]) AC_DEFINE_UNQUOTED(PATH_LOCALSTATEDIR, "$localstatedir", [local state directory]) AC_DEFINE_UNQUOTED(PATH_PIDFILEDIR, "$pidfiledir", [local state directory]) AC_DEFINE_UNQUOTED(PATH_DATAROOTDIR, "$datarootdir", [data root directory]) AC_DEFINE_UNQUOTED(PATH_DATADIR, "$datadir", [data directory]) AC_DEFINE_UNQUOTED(PATH_PKGDATADIR, "$datadir/$PACKAGE", [pkgdata directory]) AC_DEFINE_UNQUOTED(PATH_CONFIG_INCLUDEDIR, "$config_includedir", [include directory]) AC_DEFINE_UNQUOTED(PATH_SCLDIR, "$scldir", [SCL directory]) AC_DEFINE_UNQUOTED(PATH_XSDDIR, "$xsddir", [XSD directory]) AC_DEFINE_UNQUOTED(PATH_LIBEXECDIR, "$libexecdir", [libexec directory]) if test -n "$timezonedir"; then AC_DEFINE_UNQUOTED(PATH_TIMEZONEDIR, "$timezonedir", [timezone base directory]) fi if test -n "$env_ld_library_path"; then AC_DEFINE_UNQUOTED(ENV_LD_LIBRARY_PATH, "$env_ld_library_path", [set LD_LIBRARY_PATH to this value]) fi AC_DEFINE_UNQUOTED(PATH_MODULEDIR, "$moduledir", [module installation directory]) AC_DEFINE_UNQUOTED(PYTHON_MODULE_DIR, "$python_moduledir", [Python module installation directory]) AC_DEFINE_UNQUOTED(PYTHON_VENV_DIR, "$python_venvdir", [Python virtualenv for hosting Python dependencies]) AC_DEFINE_UNQUOTED(PYTHON3_HOME_DIR, "$python3_home_dir", [Hard-coded Python 3 home directory]) AC_DEFINE_UNQUOTED(PYTHON_SYSCONF_MODULE_DIR, "$python_sysconf_moduledir", [Python module installation directory]) AC_DEFINE_UNQUOTED(PATH_LOGGENPLUGINDIR, "$loggenplugindir", [loggenplugin installation directory]) AC_DEFINE_UNQUOTED(MODULE_PATH, "$module_path", [module search path]) AC_DEFINE_UNQUOTED(JAVA_MODULE_PATH, "$java_module_path", [java module search path]) AC_DEFINE_UNQUOTED(PATH_TOPSRC_DIR, "$abs_topsrcdir", [self-defined top_srcdir path]) AC_DEFINE_UNQUOTED(PACKAGE_NAME, "$PACKAGE_NAME", [package name]) AC_DEFINE_UNQUOTED(WITH_COMPILE_DATE, $wcmp_date, [Include the compile date in the binary]) AC_DEFINE_UNQUOTED(ENABLE_FORCED_SERVER_MODE, `enable_value $enable_forced_server_mode`, [Enable forced server mode]) AC_DEFINE_UNQUOTED(ENABLE_DEBUG, `enable_value $enable_debug`, [Enable debugging]) AC_DEFINE_UNQUOTED(ENABLE_GPROF, `enable_value $enable_gprof`, [Enable gcc profiling]) AC_DEFINE_UNQUOTED(ENABLE_MEMTRACE, `enable_value $enable_memtrace`, [Enable memtrace]) AC_DEFINE_UNQUOTED(ENABLE_SPOOF_SOURCE, `enable_value $enable_spoof_source`, [Enable spoof source support]) AC_DEFINE_UNQUOTED(ENABLE_IPV6, `enable_value $enable_ipv6`, [Enable IPv6 support]) AC_DEFINE_UNQUOTED(ENABLE_TCP_WRAPPER, `enable_value $enable_tcp_wrapper`, [Enable TCP wrapper support]) AC_DEFINE_UNQUOTED(ENABLE_LINUX_CAPS, `enable_value $enable_linux_caps`, [Enable Linux capability management support]) AC_DEFINE_UNQUOTED(ENABLE_EBPF, `enable_value $enable_ebpf`, [Enable Linux eBPF support]) AC_DEFINE_UNQUOTED(ENABLE_ENV_WRAPPER, `enable_value $enable_env_wrapper`, [Enable environment wrapper support]) AC_DEFINE_UNQUOTED(ENABLE_SYSTEMD, `enable_value $enable_systemd`, [Enable systemd support]) AC_DEFINE_UNQUOTED(ENABLE_KAFKA, `enable_value $enable_kafka`, [Enable kafka support]) AC_DEFINE_UNQUOTED(ENABLE_CPP, `enable_value $enable_cpp`, [Enable C++ support]) AC_DEFINE_UNQUOTED(SYSTEMD_JOURNAL_MODE, `journald_mode`, [Systemd-journal support mode]) AC_DEFINE_UNQUOTED(HAVE_INOTIFY, `enable_value $ac_cv_func_inotify_init`, [Have inotify]) AC_DEFINE_UNQUOTED(USE_CONST_IVYKIS_MOCK, `enable_value $IVYKIS_VERSION_UPDATED`, [ivykis version is greater than $IVYKIS_UPDATED_VERSION]) AM_CONDITIONAL(ENABLE_ENV_WRAPPER, [test "$enable_env_wrapper" = "yes"]) AM_CONDITIONAL(ENABLE_SYSTEMD, [test "$enable_systemd" = "yes"]) AM_CONDITIONAL(ENABLE_SYSTEMD_UNIT_INSTALL, [test "$systemdsystemunitdir" != ""]) AM_CONDITIONAL(ENABLE_SQL, [test "$enable_sql" = "yes"]) AM_CONDITIONAL(ENABLE_SUN_STREAMS, [test "$enable_sun_streams" = "yes"]) AM_CONDITIONAL(ENABLE_OPENBSD_SYSTEM_SOURCE, [test "$enable_openbsd_system_source" = "yes"]) AM_CONDITIONAL(ENABLE_EBPF, [test "$enable_ebpf" = "yes"]) AM_CONDITIONAL(ENABLE_PACCT, [test "$enable_pacct" = "yes"]) AM_CONDITIONAL(ENABLE_MONGODB, [test "$enable_mongodb" = "yes"]) AM_CONDITIONAL(ENABLE_SMTP, [test "$enable_smtp" = "yes"]) AM_CONDITIONAL(ENABLE_MQTT, [test "$enable_mqtt" = "yes"]) AM_CONDITIONAL(ENABLE_CPP, [test "$enable_cpp" = "yes"]) AM_CONDITIONAL(ENABLE_GRPC, [test "$enable_grpc" = "yes"]) AM_CONDITIONAL(ENABLE_HTTP, [test "$enable_http" = "yes"]) AM_CONDITIONAL(ENABLE_AMQP, [test "$enable_amqp" = "yes"]) AM_CONDITIONAL(ENABLE_STOMP, [test "$enable_stomp" = "yes"]) AM_CONDITIONAL(ENABLE_JSON, [test "$enable_json" = "yes"]) AM_CONDITIONAL(ENABLE_GEOIP2, [test "$enable_geoip2" = "yes"]) AM_CONDITIONAL(ENABLE_REDIS, [test "$enable_redis" = "yes"]) AM_CONDITIONAL(ENABLE_KAFKA, [test "$enable_kafka" = "yes"]) AM_CONDITIONAL(IVYKIS_INTERNAL, [test "x$with_ivykis" = "xinternal"]) AM_CONDITIONAL(LIBMONGO_INTERNAL, [test "x$LIBMONGO_SUBDIRS" != "x"]) AM_CONDITIONAL(LIBRABBITMQ_INTERNAL, [test "x$with_librabbitmq_client" = "xinternal"]) AM_CONDITIONAL(ENABLE_RIEMANN, [test "$enable_riemann" != "no"]) AM_CONDITIONAL(ENABLE_JOURNALD, [test "$with_systemd_journal" != "no"]) AM_CONDITIONAL(ENABLE_PYTHON, [test "$enable_python" != "no"]) AM_CONDITIONAL(ENABLE_PYTHON_MODULES, [test "$enable_python_modules" != "no"]) AM_CONDITIONAL(ENABLE_JAVA, [test "$enable_java" = "yes"]) AM_CONDITIONAL(ENABLE_JAVA_MODULES, [test "$enable_java_modules" = "yes"]) AM_CONDITIONAL(ENABLE_AFSNMP, [test "$enable_afsnmp" = "yes"]) AM_CONDITIONAL(ENABLE_MANPAGES, [test "$enable_manpages" != "no"]) AM_CONDITIONAL(ENABLE_MANPAGES_INSTALL, [test "$enable_manpages_install" != "no"]) AM_CONDITIONAL(ENABLE_NATIVE, [test "$enable_native" != "no"]) AM_CONDITIONAL(ENABLE_EXTRA_WARNINGS, [test "$enable_extra_warnings" = "yes"]) AM_CONDITIONAL(ENABLE_TESTING, [test "$enable_tests" != "no"]) AM_CONDITIONAL(ENABLE_SANITIZER, [test "$with_sanitizer" != "no"]) AM_CONDITIONAL(ENABLE_DEBUG, [test "$enable_debug" != "no"]) AM_CONDITIONAL([HAVE_INOTIFY], [test x$ac_cv_func_inotify_init = xyes]) AM_CONDITIONAL([HAVE_GETRANDOM], [test x$ac_cv_func_getrandom = xyes]) AM_CONDITIONAL([HAVE_FMEMOPEN], [test x$ac_cv_func_fmemopen = xyes]) AM_CONDITIONAL([HAVE_JAVAH], [test -n "$JAVAH_BIN"]) AM_CONDITIONAL(ENABLE_IPV6, [test $enable_ipv6 = yes]) AC_SUBST(PYTHON_VENV) AC_SUBST(PYTHON_VENV_DIR) AC_SUBST(with_python_packages) AC_SUBST(timezonedir) AC_SUBST(pidfiledir) AC_SUBST(moduledir) AC_SUBST(python_moduledir) AC_SUBST(python_venvdir) AC_SUBST(python_sysconf_moduledir) AC_SUBST(loggenplugindir) AC_SUBST(toolsdir) AC_SUBST(config_includedir) AC_SUBST(scldir) AC_SUBST(abs_topsrcdir) AC_SUBST(xsddir) AC_SUBST(systemdsystemunitdir) AC_SUBST(SYSLOGNG_LINK) AC_SUBST(SYSLOGNG_DEPS_LIBS) AC_SUBST(TOOL_DEPS_LIBS) AC_SUBST(CORE_DEPS_LIBS) AC_SUBST(MODULE_DEPS_LIBS) AC_SUBST(MODULE_LDFLAGS) AC_SUBST(BASE_LIBS) AC_SUBST(YFLAGS) AC_SUBST(LIBNET_LIBS) AC_SUBST(LIBNET_CFLAGS) AC_SUBST(NETSNMP_CFLAGS) AC_SUBST(NETSNMP_LIBS) AC_SUBST(LIBWRAP_LIBS) AC_SUBST(LIBWRAP_CFLAGS) AC_SUBST(ZLIB_LIBS) AC_SUBST(ZLIB_CFLAGS) AC_SUBST(LIBDBI_LIBS) AC_SUBST(LIBDBI_CFLAGS) AC_SUBST(LIBMONGO_LIBS) AC_SUBST(LIBMONGO_CFLAGS) AC_SUBST(LIBMONGO_SUBDIRS) AC_SUBST(LIBPAHO_MQTT_CFLAGS) AC_SUBST(LIBPAHO_MQTT_LIBS) AC_SUBST(LIBESMTP_CFLAGS) AC_SUBST(LIBESMTP_LIBS) AC_SUBST(LIBCURL_CFLAGS) AC_SUBST(LIBCURL_LIBS) AC_SUBST(LIBRABBITMQ_LIBS) AC_SUBST(LIBRABBITMQ_CFLAGS) AC_SUBST(LIBRABBITMQ_SUBDIRS) AC_SUBST(JSON_LIBS) AC_SUBST(JSON_CFLAGS) AC_SUBST(JSON_DEPENDENCY) AC_SUBST(IVYKIS_SUBDIRS) AC_SUBST(RESOLV_LIBS) AC_SUBST(LIBBPF_INCLUDE) AC_SUBST(CURRDATE) AC_SUBST(RELEASE_TAG) AC_SUBST(SNAPSHOT_VERSION) AC_SUBST(SOURCE_REVISION) AC_SUBST(with_ivykis) AC_SUBST(INTERNAL_IVYKIS_CFLAGS) AC_SUBST(LIBSYSTEMD_JOURNAL_CFLAGS) AC_SUBST(LIBSYSTEMD_JOURNAL_LIBS) AC_SUBST(XSL_STYLESHEET) AX_PREFIX_CONFIG_H(syslog-ng-config.h, "SYSLOG_NG") AX_VALGRIND_CHECK AC_OUTPUT(dist.conf Makefile syslog-ng.pc libtest/syslog-ng-test.pc scripts/update-patterndb scripts/syslog-ng-update-virtualenv ) echo echo "syslog-ng Open Source Edition $PACKAGE_VERSION configured" echo " Edition settings:" echo " Release type : $RELEASE_TYPE" echo " Pretty version : $BROCHURE_VERSION" echo " Combined vers. : $COMBINED_VERSION" echo " Package name : $PACKAGE_NAME" echo " Compiler options:" echo " compiler : $CC" echo " compiler options : $CFLAGS $CPPFLAGS" echo " C++ enabled : ${enable_cpp:=no}" if test "x$enable_cpp" = "xyes"; then echo " C++ compiler : $CXX" echo " C++ compiler options : $CXXFLAGS" fi echo " linker flags : $LDFLAGS $LIBS" echo " prefix : $prefix" echo " linking mode : $linking_mode" echo " embedded crypto : ${with_embedded_crypto:=no}" echo " __thread keyword : ${ac_cv_have_tls:=no}" echo " Test dependencies:" echo " Criterion : ${with_criterion:=no}" echo " Unit tests : ${enable_tests:=no}" echo " Submodules:" echo " ivykis : $with_ivykis" echo " Features:" echo " Forced server mode : ${enable_forced_server_mode:=yes}" echo " Debug symbols : ${enable_debug:=no}" echo " GCC profiling : ${enable_gprof:=no}" echo " Memtrace : ${enable_memtrace:=no}" echo " IPV6 support : ${enable_ipv6:=no}" echo " spoof-source support : ${enable_spoof_source:=no}" echo " tcp-wrapper support : ${enable_tcp_wrapper:=no}" echo " Linux capability support : ${has_linux_caps:=no}" echo " Env wrapper support : ${enable_env_wrapper:=no}" echo " systemd support : ${enable_systemd:=no} (unit dir: ${systemdsystemunitdir:=none})" echo " systemd-journal support : ${with_systemd_journal:=no}" echo " JSON support : $with_jsonc" echo " Build options:" echo " Generate manual pages : ${enable_manpages:=no}" echo " Install manual pages : ${enable_manpages_install:=no}" echo " Modules:" echo " Module search path : ${module_path}" echo " Sun STREAMS support (module): ${enable_sun_streams:=no}" echo " OpenBSD syslog (module) : ${enable_openbsd_system_source:=no}" echo " SQL support (module) : ${enable_sql:=no}" echo " PACCT module (EXPERIMENTAL) : ${enable_pacct:=no}" echo " MongoDB destination (module): ${enable_mongodb:=no}" echo " JSON support (module) : ${enable_json:=no}" echo " SMTP support (module) : ${enable_smtp:=no}" echo " HTTP support (module) : ${enable_http:=no}" echo " AMQP destination (module) : ${enable_amqp:=no}" echo " STOMP destination (module) : ${enable_stomp:=no}" echo " MQTT (module) : ${enable_mqtt:=no}" echo " GRPC (module) : ${enable_grpc:=no}" echo " GEOIP2 support (module) : ${enable_geoip2:=no}" echo " Redis support (module) : ${enable_redis:=no}" echo " Kafka support (module) : ${enable_kafka:=no}" echo " Riemann destination (module): ${enable_riemann:=no}, microseconds: ${riemann_micros:=no}" echo " Python : ${enable_python:=no} (pkg-config package: ${with_python:=none}, packages: ${with_python_packages})" echo " Python modules : ${enable_python_modules:=no}" echo " Java : ${enable_java:=no}" echo " Java modules : ${enable_java_modules:=no}" echo " afsnmp module : ${enable_afsnmp:=no}" echo " eBPF module : ${enable_ebpf:=no}" echo " native bindings : ${enable_native:=no}" syslog-ng-syslog-ng-4.4.0/contrib/000077500000000000000000000000001450431004300170135ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/Brewfile000066400000000000000000000007121450431004300204750ustar00rootroot00000000000000brew "autoconf-archive" brew "autoconf" brew "automake" brew "binutils" brew "bison" brew "flex" brew "gcc@11" brew "glib" brew "ivykis" brew "json-c" brew "libtool" brew "openssl@3" brew "pcre" brew "pkg-config" brew "curl" brew "gradle" brew "hiredis" brew "libdbi" brew "libmaxminddb" brew "libnet" brew "librdkafka" brew "mongo-c-driver" brew "net-snmp" brew "python@3", link: true, force: true brew "rabbitmq-c" brew "riemann-client" brew "criterion" syslog-ng-syslog-ng-4.4.0/contrib/Makefile.am000066400000000000000000000067771450431004300210700ustar00rootroot00000000000000dist_sbin_SCRIPTS += \ contrib/syslog-ng-debun EXTRA_DIST += \ contrib/README \ \ contrib/README.syslog-ng-debun \ contrib/syslog-ng-debun \ \ contrib/init.d.solaris \ contrib/init.d.HP-UX \ contrib/init.d.RedHat \ contrib/init.d.SuSE \ contrib/init.d.SunOS \ contrib/init.d.solaris \ contrib/init.d.RedHat-7.3 \ \ contrib/syslog-ng.conf.HP-UX \ contrib/syslog-ng.conf.RedHat \ contrib/syslog-ng.conf.SunOS \ \ contrib/syslog2ng \ contrib/syslog-mc \ \ contrib/syslog-ng.conf.doc \ contrib/relogger.pl \ \ contrib/Brewfile \ \ contrib/fedora-packaging/syslog-ng.conf \ contrib/fedora-packaging/syslog-ng.init \ contrib/fedora-packaging/syslog-ng.sysconfig \ contrib/fedora-packaging/syslog-ng.logrotate \ \ contrib/rhel-packaging/syslog-ng.conf \ contrib/rhel-packaging/syslog-ng.init \ contrib/rhel-packaging/syslog-ng.logrotate \ \ contrib/aix-packaging/syslog-ng.conf \ \ contrib/hpux-packaging/syslog-ng.conf \ contrib/hpux-packaging/syslog-ng.init \ \ contrib/lfs-packaging/Makefile.lfs \ contrib/lfs-packaging/README.lfs \ contrib/lfs-packaging/syslog-ng.init.lfs \ \ contrib/cygwin-packaging/cygwin-postinstall \ contrib/cygwin-packaging/syslog-ng-config \ contrib/cygwin-packaging/syslog-ng.sh \ \ contrib/solaris-packaging/solaris10_install.txt \ contrib/solaris-packaging/syslog-ng.example.xml \ contrib/solaris-packaging/syslog-ng@default \ contrib/solaris-packaging/syslog-ng-sol11-smf.example.xml \ contrib/solaris-packaging/syslog-ng.method \ \ contrib/freebsd-packaging/syslog-ng.rc.d \ contrib/freebsd-packaging/syslog-ng.conf.example \ contrib/openbsd-packaging/syslog-ng.conf \ \ contrib/selinux/README \ contrib/selinux/src/root_unsafe/syslog_ng.el6.fc.in \ contrib/selinux/src/root_unsafe/syslog_ng.el789.fc.in \ contrib/selinux/src/root_unsafe/syslog_ng.el5.fc.in \ contrib/selinux/src/root_safe/syslog_ng.el6.fc.in \ contrib/selinux/src/root_safe/syslog_ng.el789.fc.in \ contrib/selinux/src/root_safe/syslog_ng.el5.fc.in \ contrib/selinux/src/syslog_ng.el6.0to4.te.in \ contrib/selinux/src/syslog_ng.el7.te.in \ contrib/selinux/src/syslog_ng.el8.te.in \ contrib/selinux/src/syslog_ng.el9.te.in \ contrib/selinux/src/syslog_ng.module.version \ contrib/selinux/src/syslog_ng.el6.5up.te.in \ contrib/selinux/src/syslog_ng.el5.te.in \ contrib/selinux/labels.txt \ contrib/selinux/syslog_ng.sh \ \ contrib/apparmor/opt.syslog-ng.sbin.syslog-ng \ \ contrib/balabit-initscripts/init.d \ contrib/balabit-initscripts/init.d.freebsd \ contrib/balabit-initscripts/init-functions \ \ contrib/upstart/syslog-ng.conf.upstart \ contrib/systemd/syslog-ng@.service \ contrib/systemd/syslog-ng@default \ \ contrib/scripts/config-graph-json-to-dot.py \ \ contrib/valgrind/syslog-ng.supp \ \ contrib/syslog-ng-helm-chart/.helmignore \ contrib/syslog-ng-helm-chart/values.yaml \ contrib/syslog-ng-helm-chart/Chart.yaml \ contrib/syslog-ng-helm-chart/templates/NOTES.txt \ contrib/syslog-ng-helm-chart/templates/_helpers.tpl \ contrib/syslog-ng-helm-chart/templates/compress-job.yaml \ contrib/syslog-ng-helm-chart/templates/config.yaml \ contrib/syslog-ng-helm-chart/templates/deployment.yaml \ contrib/syslog-ng-helm-chart/templates/hpa.yaml \ contrib/syslog-ng-helm-chart/templates/pvc.yaml \ contrib/syslog-ng-helm-chart/templates/service.yaml \ contrib/syslog-ng-helm-chart/templates/serviceaccount.yaml \ contrib/syslog-ng-helm-chart/templates/tests/test-connection.yaml if ENABLE_SYSTEMD_UNIT_INSTALL systemdsystemunit_DATA = contrib/systemd/syslog-ng@.service endif syslog-ng-syslog-ng-4.4.0/contrib/README000066400000000000000000000017301450431004300176740ustar00rootroot00000000000000This directory contains unsorted user contributions of syslog-ng. They are not maintained, nor supported, but may be useful to some. NOTE: these were simply copied from syslog-ng 1.6 distribution, therefore might not work out-of-the-box for syslog-ng 2.0. init.d.HP-UX - sample init script for HP-UX init.d.RedHat - sample init script for RedHat GNU/Linux init.d.SunOS - sample init script for Sun Solaris init.d.solaris - another sample init script for Sun Solaris syslog-ng.conf.HP-UX - sample configuration for HP-UX syslog-ng.conf.RedHat - sample configuration for RedHat GNU/Linux syslog-ng.conf.SunOS - sample configuration for SunOS syslog-ng.conf.doc - sample configuration file with inline documentation as comments syslog2ng - script to convert old syslog.conf to syslog-ng.conf relogger.pl - script to replay syslog messages at the original rate fedora-packaging - directory containing files related to Fedora packaging syslog-mc - syslog multicast client syslog-ng-syslog-ng-4.4.0/contrib/README.syslog-ng-debun000066400000000000000000000044021450431004300227070ustar00rootroot00000000000000README for syslog-ng-debun, the Syslog-ng DEBUg buNdle generator The main purpose of this software is to collect and save information about your syslog-ng installation / implementation for that case, if you want to ask help about your syslog-ng related problem. usage examples: # syslog-ng-debun -r Create a simple debug bundle, collecting about your environmental information. eg. list of packages, which contains the word: syslog ldd of your syslog-binary, etc. # syslog-ng-debun -r -l Like previuos, but left out some information, which may you think harm your privacy. Eg fstab, df's output, mount info, ip / network interface configuration, DNS resolv info, and process tree is NOT collected. # syslog-ng-debun -r -d Besides collecting information, it stops system's syslog-ng, then start in debug mode with -Fedv --enable-core, and until you do not press enter, it stays in that mode. Debug's output is collected into a separate file, and also collected. # syslog-ng-debun -r -p Will run packet capture with filter: "port 514 or port 601 or port 53" Also wait for pressing enter, like debug mode. # syslog-ng-debun -r -p -t 10 Like the previous one, but do not wait for pressing enter, it will exit from tcpdump mode after 10 seconds. (noninteractive debug mode) # syslog-ng-debun -r -P "host 1.2.3.4" -D "-Fev --enable-core" packet capturing's filter will be changed from default to host 1.2.3.4 Debugging paramters will be changed from default to -Fev --enable-core And, since a timout is not given, it will wait for pressing enter. # syslog-ng-debun -r -p -d -w 5 -t 10 Collect pcap and debug mode output following this scenario: * start packet capture with default params * wait 5 seconds * stop system's syslog-ng * start syslog-ng in debug mode with default params, syslog's debug messages are also appearing on your console * wait 10 seconds * stop syslog-ng debugging * start system's syslog-ng * stops packet capturing # syslog-ng-debun -r -W /var/tmp -R /usr/local Collect debug info, but the temporary files, and the result will be in /var/tmp instead of /tmp and don't try to search syslog-ng in /opt/syslog-ng, it will search in /usr/local # syslog-ng-debun -r -s -t 10 Collect debug info, start tracing, and exit tracing after 10 seconds syslog-ng-syslog-ng-4.4.0/contrib/aix-packaging/000077500000000000000000000000001450431004300215165ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/aix-packaging/syslog-ng.conf000066400000000000000000000041641450431004300243140ustar00rootroot00000000000000# # sample configuration file for syslog-ng on AIX # users should customize to fit their needs # # log syslog-ng's own messages to /var/log/syslog-ng.log source s_internal { internal(); }; destination d_syslognglog { file("/var/log/syslog-ng.log" owner("root") group("adm") perm(0640)); }; log { source(s_internal); destination(d_syslognglog); }; # log everything to /var/log/messages source s_local { unix-dgram("/dev/log"); }; destination d_messages { file("/var/log/messages" owner("root") group("adm") perm(0640)); }; log { source(s_local); destination(d_messages); }; # Remote logging # #source s_remote { # tcp(ip(0.0.0.0) port(514)); # udp(ip(0.0.0.0) port(514)); #}; # #destination d_separatedbyhosts { # file("/var/log/syslog-ng/$HOST/messages" owner("root") group("root") perm(0640) dir_perm(0750) create_dirs(yes)); #}; # #log { # source(s_remote); # destination(d_separatedbyhosts); #}; # # Local filters examples # #filter f_messages { level(info..emerg); }; #filter f_secure { facility(authpriv); }; #filter f_mail { facility(mail); }; #filter f_cron { facility(cron); }; #filter f_emerg { level(emerg); }; #filter f_spooler { level(crit..emerg) and facility(uucp, news); }; #filter f_local7 { facility(local7); }; # # Local destination examples # #destination d_secure { file("/var/log/secure"); }; #destination d_maillog { file("/var/log/maillog"); }; #destination d_cron { file("/var/log/cron"); }; #destination d_console { usertty("root"); }; #destination d_spooler { file("/var/log/spooler"); }; #destination d_bootlog { file("/var/log/boot.log"); }; # # Local log examples - order DOES matter ! # #log { source(s_local); filter(f_emerg); destination(d_console); }; #log { source(s_local); filter(f_secure); destination(d_secure); flags(final); }; #log { source(s_local); filter(f_maillog); destination(d_maillog); flags(final); }; #log { source(s_local); filter(f_cron); destination(d_cron); flags(final); }; #log { source(s_local); filter(f_spooler); destination(d_spooler); }; #log { source(s_local); filter(f_local7); destination(d_bootlog); }; #log { source(s_local); filter(f_messages); destination(d_messages); }; syslog-ng-syslog-ng-4.4.0/contrib/apparmor/000077500000000000000000000000001450431004300206345ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/apparmor/opt.syslog-ng.sbin.syslog-ng000066400000000000000000000022031450431004300261520ustar00rootroot00000000000000# $Id: opt.syslog-ng.sbin.syslog-ng 12 2008-08-19 16:68:41Z folti $ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License published by the Free Software Foundation. # # ------------------------------------------------------------------ #include /opt/syslog-ng/sbin/syslog-ng { #include #include #include capability sys_admin, capability sys_tty_config, capability dac_override, capability dac_read_search, /dev/log wl, /var/lib/*/dev/log wl, /dev/tty* w, /dev/xconsole rw, /etc/syslog.conf r, /boot/System.map* r, /proc/kmsg r, /opt/syslog-ng/sbin/syslog-ng rmix, /var/log/** rw, /var/run/syslog-ng.pid rwl, /var/run/utmp rw, /var/spool/compaq/nic/messages_fifo rw, } syslog-ng-syslog-ng-4.4.0/contrib/balabit-initscripts/000077500000000000000000000000001450431004300227625ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/balabit-initscripts/init-functions000066400000000000000000000117231450431004300256620ustar00rootroot00000000000000# /lib/lsb/init-functions replacement for syslog-ng Premium Edition RED= YELLOW= NORMAL= FANCYTTY= PSOPTS= ECHO=echo OS=`uname -s` # LSB Functions # ripped from ubuntu/debian lsb log_use_fancy_output() { case "$TERM" in dumb|raw|serial|vt*|cons*|unknown) return 1 ;; *) if [ -n "$FANCYTTY" ] && [ $FANCYTTY -ne 1 ]; then return 1 fi RED="\033[31m" YELLOW="\033[33m" NORMAL="\033[0m" return 0 ;; esac return 1 } log_success_msg() { $ECHO "$@" } log_failure_msg() { log_use_fancy_output $ECHO "${RED}$@${NORMAL}" } log_warning_msg() { log_use_fancy_output $ECHO "${YELLOW}$@${NORMAL}" } # NON-LSB Functions log_begin_msg() { if [ -z "$1" ]; then return 1 fi $ECHO "$@\c " } log_daemon_msg() { if [ -z "$1" ];then return 1 fi if [ -z "$2" ]; then $ECHO "$1:\c " return fi $ECHO "$1: $2\c " } log_progress_msg() { if [ -z "$1" ]; then return 1 fi if [ $1 -eq 0 ]; then $ECHO "." else $ECHO " failed" fi } log_end_msg() { if [ -z "$1" ]; then return 1 fi log_fancy_output if [ $1 -eq 0 ];then $ECHO "." else $ECHO "${RED}failed!${NORMAL}" fi return $1 } log_action_msg() { $ECHO "$@." } log_action_begin_msg() { $ECHO "$@...\c " } log_action_cont_msg() { $ECHO "$@...\c " } log_action_end_msg() { if [ -z "$2" ]; then end="." else end=" ($2)." fi log_fancy_output if [ $1 -eq 0 ]; then $ECHO "done${end}" else $ECHO "${RED}failed${end}${NORMAL}" fi } # overide log_*_msg if the init-functions file exits on the system [ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions # in these three cases we have to use our functions unalias start_daemon 2>/dev/null unalias killproc 2>/dev/null unalias pidofproc 2>/dev/null disable_xpg_echo() { # \X chars only passed to echo under bash, if xpg_echo enabled or echo -e # used on Linux. if [ -n "$BASH_VERSION" ];then shopt -s xpg_echo fi } case $OS in # default ps -e cuts the process' name at 8 characters, so we have to list it # in a long form SunOS) PSOPTS=" -o pid -o tty -o time -o comm" disable_xpg_echo ;; Linux) if [ -z "$BASH_VERSION" ]; then # beware of dash's builtin echo ... ECHO="/bin/echo -e" fi ;; *) disable_xpg_echo ;; esac _checkpid() { _pid=$1 _proc=$2 for _ret in `ps -e $PSOPTS | grep "$_proc" | sed -e 's/^ *//' -e 's/ .*//'`; do if [ -n "$_ret" ] && [ "$_ret" = "$_pid" ]; then return 0 fi done return 1 } _pid_from_pidfile() { pidfile=$1 procname=$2 pid= if [ -f "$pidfile" ];then pid=`head -1 $pidfile 2> /dev/null` if [ $? -ne 0 ]; then # on slow machines (or ones under high load) the pidfile could be # erased between -f and `head` ... return 3 fi if _checkpid $pid $procname; then return 0 fi return 1 # pidfile exist, but proc not running fi return 3 # proc not running } pidofproc() { proc= pidfile= if [ "$1" = "-p" ];then pidfile=$2 shift shift fi if [ -z "$1" ];then echo "Usage: pidofproc [-p pidfile] {program}" return 1 fi proc=$1 shift base=`basename ${proc}` if [ -z "${pidfile}" ]; then pidfile=/var/run/${base}.pid fi if [ -f ${pidfile} ];then _pid_from_pidfile "${pidfile}" "${base}" _ret=$? if [ $_ret -eq 0 ]; then if kill -0 ${pid} 2> /dev/null; then echo "$pid" return 0 fi else return $_ret fi fi return 4 } start_daemon() { proc= pidfile= force= nice= if [ "$1" = "-f" ]; then force="force" shift fi if [ "$1" = "-n" ];then nice="nice $2" shift shift fi if [ "$1" = "-p" ];then pidfile=$2 shift shift fi if [ -z "$1" ];then echo "Usage: start_daemon [-f] [-n nicelevel] [-p pidfile] {program} [args]" return 1 fi proc=$1 shift base=`basename ${proc}` if [ -z "${pidfile}" ]; then pidfile=/var/run/${base}.pid fi _pid_from_pidfile "${pidfile}" "${base}" if [ -n "$pid" ] && [ -z "$force" ];then return fi $nice $proc $* return $? } killproc() { proc= signal=-15 pidfile= if [ "$1" = "-p" ];then pidfile=$2 shift shift fi if [ -z "$1" ];then echo "Usage: killproc [-p pidfile] {program}" return 1 fi proc=$1 shift if [ -n "$1" ];then signal=$1 echo "${signal}" | grep '^-' >/dev/null 2>&1 if [ $? -ne 0 ]; then signal="-${signal}" fi fi base=`basename $proc` if [ -z "${pidfile}" ]; then pidfile=/var/run/${base}.pid fi _pid_from_pidfile "${pidfile}" "${base}"; _ret=$? if [ $_ret -ne 0 ];then rm -f ${pidfile} return $_ret fi if [ -n "$pid" ]; then kill $signal $pid _status="$?" if [ $_status -eq 0 ];then pidofproc -p "${pidfile}" "$proc" >/dev/null || rm -f "${pidfile}" fi fi return $_retval } # vim: ft=sh ts=2 expandtab syslog-ng-syslog-ng-4.4.0/contrib/balabit-initscripts/init.d000066400000000000000000000155771450431004300241110ustar00rootroot00000000000000#!/bin/sh # syslog-ng This starts and stops syslog-ng # # chkconfig: - 12 88 # processname: /opt/syslog-ng/sbin/syslog-ng # config: /opt/syslog-ng/etc/syslog-ng.conf # config: /etc/sysconfig/syslog-ng # pidfile: /var/run/syslog-ng.pid ### BEGIN INIT INFO # Provides: syslog # Description: reads and logs messages to the system console, log \ # files, other machines and/or users as specified by \ # its configuration file. # Short-Description: Next-generation syslog server. # Required-Start: $local_fs # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 ### END INIT INFO OS=`uname -s` DEFAULTFILE=/etc/default/syslog-ng [ -f ${DEFAULTFILE} ] && . ${DEFAULTFILE} SYSLOGNG_PREFIX=${SYSLOGNG_PE_PREFIX:-/opt/syslog-ng} export SYSLOGNG_PREFIX SYSLOGNG="$SYSLOGNG_PREFIX/sbin/syslog-ng" CONFFILE=$SYSLOGNG_PREFIX/etc/syslog-ng.conf PIDFILE=$SYSLOGNG_PREFIX/var/run/syslog-ng.pid SYSLOGPIDFILE="/var/run/syslog.pid" SLNG_INIT_FUNCTIONS=$SYSLOGNG_PREFIX/lib/init-functions MAXWAIT=30 # for RedHat... SUBSYSDIR=/var/lock/subsys retval=0 # in HPUX, PATH for init scripts does not contain standard dirs for binaries if [ "$OS" = "HP-UX" ]; then PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin fi # OS specific I-didn't-do-anything exit function. exit_noop() { case $OS in HP-UX) exit 2 ;; *) exit 0 ;; esac } # Platform specific echo -n implementation. echo_n() { case "$OS" in SunOS) echo "$@\c " ;; HP-UX) echo " $@\c " ;; *) echo -n "$@" ;; esac } test -x ${SYSLOGNG} || exit_noop test -r ${CONFFILE} || exit_noop if [ -f /etc/lsb-release ]; then . /etc/lsb-release fi if [ -f "/etc/redhat-release" ];then # redhat uses a different syslogd pidfile... SYSLOGPIDFILE="/var/run/syslogd.pid" fi if [ "$OS" = "SunOS" ] || [ "$OS" = "Solaris" ];then if [ "`uname -r`" = "5.8" ];then SYSLOGPIDFILE="/etc/syslog.pid" fi fi . $SLNG_INIT_FUNCTIONS case "$OS" in Linux) SYSLOGNG_OPTIONS="--no-caps" ;; esac #we source /etc/default/syslog-ng if exists [ -r /etc/default/syslog-ng ] && . /etc/default/syslog-ng # Source config on RPM systems [ -r /etc/sysconfig/syslog-ng ] && . /etc/sysconfig/syslog-ng #we source /etc/default/syslog-ng if exists [ -r $SYSLOGNG_PREFIX/etc/default/syslog-ng ] && \ . $SYSLOGNG_PREFIX/etc/default/syslog-ng create_xconsole() { if grep -v '^#' $CONFFILE | grep /dev/xconsole >/dev/null 2>&1; then if [ ! -e /dev/xconsole ]; then mknod -m 640 /dev/xconsole p fi fi } check_syntax() { ${SYSLOGNG} --no-caps --syntax-only _rval=$? [ $_rval -eq 0 ] || exit $_rval } slng_waitforpid() { _pid=$1 _process=$2 _cnt=$MAXWAIT # no pid, return... [ -z "$_pid" ] && return 0 _procname=`basename $_process` while [ $_cnt -gt 0 ]; do _numproc=`ps -p $_pid $PSOPTS | grep $_procname | wc -l` if [ $_numproc -eq 0 ]; then return 0 fi _cnt=`expr $_cnt - 1` sleep 1 done return 1 } returnmessage() { _rval=$1 is_debian=0 case "$OS" in Linux) res=`cat /etc/issue | grep Debian` is_debian=$? ;; esac if [ $_rval -ne 0 ];then if [ $is_debian -eq 0 ];then log_failure_msg "failed" else log_failure_msg fi else if [ $is_debian -eq 0 ];then log_success_msg "OK" else log_success_msg fi fi } syslogng_start() { echo_n "Starting syslog-ng: " PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1` if [ -n "$PID" ] && [ $PID -gt 0 ] ;then log_success_msg "already running: $PID" return $retval fi rm -f ${PIDFILE} start_daemon -f -p ${PIDFILE} ${SYSLOGNG} ${SYSLOGNG_OPTIONS} retval=$? returnmessage $retval if [ $retval -eq 0 ];then if [ "$OS" = "Linux" ] && [ -d $SUBSYSDIR ];then touch $SUBSYSDIR/syslog-ng fi # remove symlinks if [ -h $SYSLOGPIDFILE ];then rm -f $SYSLOGPIDFILE fi if [ ! -f $SYSLOGPIDFILE ];then ln -s $PIDFILE $SYSLOGPIDFILE fi fi return $retval } # Can't name the function stop, because HP-UX has a default alias named stop... syslogng_stop() { echo_n "Stopping syslog-ng: " PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1` retval=$? if [ $retval -ne 0 ] || [ -z "$PID" ];then return $retval fi killproc -p ${PIDFILE} ${SYSLOGNG} retval=$? if [ $retval -eq 0 ];then slng_waitforpid "$PID" ${SYSLOGNG} if [ $? -ne 0 ]; then retval=$? log_failure_msg " Timeout" killproc -p ${PIDFILE} ${SYSLOGNG} -KILL else returnmessage $retval fi fi if [ $retval -eq 0 ];then rm -f $SUBSYSDIR/syslog-ng ${PIDFILE} if [ -h $SYSLOGPIDFILE ];then rm -f $SYSLOGPIDFILE fi fi return $retval } syslogng_restart() { check_syntax echo_n "Restarting syslog-ng: " syslogng_stop syslogng_start return $retval } syslogng_reload() { echo_n "Reloading syslog-ng's config file: " check_syntax killproc -p ${PIDFILE} ${SYSLOGNG} -HUP retval=$? returnmessage $retval return $retval } syslogng_status() { echo_n "Checking for syslog-ng service: " pid=`pidofproc -p ${PIDFILE} ${SYSLOGNG}` retval=$? if [ $retval -ne 0 ];then msg= case $retval in 1) msg="dead but pidfile exists." ;; *) msg="stopped" ;; esac log_failure_msg "$msg" else log_success_msg "$pid running" fi return $retval } syslogng_probe() { if [ ${CONFFILE} -nt ${PIDFILE} ]; then echo reload fi } case $OS in Linux) case "x$CONSOLE_LOG_LEVEL" in x[1-8]) dmesg -n $CONSOLE_LOG_LEVEL ;; x) ;; *) echo "CONSOLE_LOG_LEVEL is of unaccepted value." ;; esac create_xconsole ;; SunOS) # # Before syslog-ng starts, save any messages from previous # crash dumps so that messages appear in chronological order. # if [ -r /dev/dump ]; then /usr/bin/savecore -m fi if [ -r /etc/dumpadm.conf ]; then . /etc/dumpadm.conf if [ -n "$DUMPADM_DEVICE" ] && [ -r "$DUMPADM_DEVICE" ] && \ [ "x$DUMPADM_DEVICE" != xswap ]; then /usr/bin/savecore -m -f $DUMPADM_DEVICE fi fi ;; HP-UX) # /etc/default/syslog-ng, the HP-UX way. [ -r /etc/rc.config.d/syslog-ng ] && . /etc/rc.config.d/syslog-ng ;; esac case "$1" in start_msg) echo "Start syslog-ng system message logging daemon" ;; stop_msg) echo "Stop syslog-ng system message logging daemon" ;; start|stop|restart|reload|probe) syslogng_$1 ;; force-reload) syslogng_restart ;; reload-or-restart) PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1` if [ -n "$PID" ] && [ $PID -gt 0 ] ;then syslogng_reload else syslogng_start fi ;; status) syslogng_status ;; condrestart|try-restart) [ ! -f $lockfile ] || syslogng_restart ;; rotate) syslogng_reload ;; *) echo "Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload|probe}" exit 2 ;; esac exit $retval # vim: ts=2 ft=sh noexpandtab syslog-ng-syslog-ng-4.4.0/contrib/balabit-initscripts/init.d.freebsd000066400000000000000000000040761450431004300255120ustar00rootroot00000000000000#!/bin/sh # startup script for FreeBSD 6.x. # Written by Tamas Pal # PROVIDE: syslogd # REQUIRE: mountcritremote cleanvar newsyslog # BEFORE: SERVERS # Enabling syslog-ng: # * copy this script to /etc/rc.d or /usr/local/etc/rc.d # * Edit /etc/rc.conf and add the following lines: # ----- CUT HERE ----- # syslogd_enable="NO" # syslogng_enable="YES" # syslogng_flags="" # ----- CUT HERE ----- # * Add your extra flags to syslogng_flags EXCEPT the -p and -f # flags. These are added automatically by this script. To set # their value, change the value of the conf_file and pidfile variables below # BalaBit's platform independent variables. Please do not modify. SYSLOGNG_PREFIX=/opt/syslog-ng . "/etc/rc.subr" # FreeBSD rc specific variables. Please do not modify. name="syslogng" rcvar=`set_rcvar` pidfile="$SYSLOGNG_PREFIX/var/run/syslog-ng.pid" command="$SYSLOGNG_PREFIX/sbin/syslog-ng" required_files="$SYSLOGNG_PREFIX/etc/syslog-ng.conf" start_precmd="syslog_ng_start_precmd" start_postcmd="syslog_ng_start_postcmd" stop_postcmd="syslog_ng_stop_postcmd" reload_precmd="syslog_ng_reload_precmd" extra_commands="reload" # get original syslog pidfile from initscript. _syslogd_pidfile=`sed -n -e 's/^pidfile="\([^"]*\)"/\1/p' /etc/rc.d/syslogd 2> /dev/null` syslog_ng_start_precmd() { if [ ! -L /dev/log ]; then ln -s /var/run/log /dev/log fi } syslog_ng_reload_precmd() { $command --syntax-only _rval=$? if [ $_rval -ne 0 ];then exit $_rval fi } syslog_ng_start_postcmd() { if [ -n "$_syslogd_pidfile" ]; then # remove symlinks if [ -h $_syslogd_pidfile ]; then rm -f $_syslogd_pidfile fi if [ ! -f $_syslogd_pidfile ]; then ln -s "$pidfile" "$_syslogd_pidfile" fi fi } syslog_ng_stop_postcmd() { if [ -n "$_syslogd_pidfile" ]; then if [ -h $_syslogd_pidfile ]; then rm -f "$_syslogd_pidfile" fi fi } load_rc_config "$name" case $1 in start) # Reportedly needed on 7.x. PATH=$PATH:$SYSLOGNG_PREFIX/sbin export PATH syslogng_flags="${syslog_ng_flags}" ;; esac run_rc_command "$1" # vim: ft=sh syslog-ng-syslog-ng-4.4.0/contrib/com.syslog-ng.syslog-ng.plist000066400000000000000000000020771450431004300245160ustar00rootroot00000000000000 Label com.syslog-ng.syslog-ng ProgramArguments /usr/local/sbin/syslog-ng -F -p /var/run/syslog-ng.pid RunAtLoad KeepAlive syslog-ng-syslog-ng-4.4.0/contrib/cygwin-packaging/000077500000000000000000000000001450431004300222355ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/cygwin-packaging/cygwin-postinstall000077500000000000000000000037761450431004300260520ustar00rootroot00000000000000#!/bin/bash if [ -z "$1" ] then echo "Usage: $0 DESTDIR" exit 1 fi DESTDIR="$1" if [ ! -d "contrib/cygwin-packaging" ] then echo "Please run 'contrib/cygwin-packaging/cygwin-postinstall' from the top-level source directory." exit 1 fi if [ ! -f "${DESTDIR}/usr/sbin/syslog-ng.exe" ] then echo "Please run 'make install-strip' first." exit 2 fi if [ ! -f "config.log" ] then echo "Please run './configure' first." echo "Have a look into 'contrib/cygwin-packaging/cygwin-postinstall' how to do it." exit 3 fi pushd "${DESTDIR}" || exit 4 mkdir -p etc/defaults/etc etc/postinstall mv etc/syslog-ng etc/defaults/etc cd usr/lib rm *.a *.la if [ -d bin ] then mv bin/* syslog-ng rmdir bin fi cd syslog-ng rm *.a *.la *.so ln -s cygafsocket-tls.dll cygafsocket.dll popd cp contrib/cygwin-packaging/syslog-ng-config "${DESTDIR}/usr/bin/" cp contrib/cygwin-packaging/syslog-ng.sh "${DESTDIR}/etc/postinstall/" mkdir -p "${DESTDIR}/usr/share/doc/Cygwin" cat > "${DESTDIR}/usr/share/doc/Cygwin/syslog-ng.README" <<'EOF' If you want to use syslog-ng, just run the /usr/bin/syslog-ng-config script. This script will create a default configuration file /etc/syslog-ng.conf and it will install syslog-ng as a service on NT systems on request. Please note that you cannot use syslogd from the inetutils package and syslog-ng together. Only one syslog daemon should run at a time. The syslog-ng-config script, as well as the latest version of the syslogd-config script are taking care of this when requested to install as service. The syslog-ng package has been created using the following command sequence from the top level source dir: ./configure \ --prefix=/usr \ --sysconfdir=/etc/syslog-ng \ --libexecdir='${prefix}/lib' \ --localstatedir=/var/lib/syslog-ng \ --datadir='${prefix}/share/syslog-ng' make mkdir /tmp/syslog-ng make install-strip DESTDIR=/tmp/syslog-ng contrib/cygwin-packaging/cygwin-postinstall /tmp/syslog-ng tar -cjf syslog-ng-VERSION.tar.bz2 -C /tmp/syslog-ng etc usr EOF syslog-ng-syslog-ng-4.4.0/contrib/cygwin-packaging/syslog-ng-config000077500000000000000000000101071450431004300253470ustar00rootroot00000000000000#!/bin/sh # # syslog-ng-config, Copyright 2005, 2006, 2010 Corinna Vinschen # # This file is part of the Cygwin port of syslog-ng. # set -x # Subdirectory where the new package is being installed PREFIX="/usr" # Directory where the config files are stored SYSCONFDIR="/etc/syslog-ng" # Paths of the config files starting with 3.2.1. SYSCONFFILE="${SYSCONFDIR}/syslog-ng.conf" SCLFILE="${SYSCONFDIR}/scl.conf" MODULESFILE="${SYSCONFDIR}/modules.conf" # Directory in which the templates are stored. DEFAULTDIR="/etc/defaults" progname=$0 auto_answer="" request() { if [ "${auto_answer}" = "yes" ] then return 0 elif [ "${auto_answer}" = "no" ] then return 1 fi answer="" while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ] do echo -n "$1 (yes/no) " read answer done if [ "X${answer}" = "Xyes" ] then return 0 else return 1 fi } # Check options while : do case $# in 0) break ;; esac option=$1 shift case "$option" in -d | --debug ) set -x ;; -y | --yes ) auto_answer=yes ;; -n | --no ) auto_answer=no ;; *) echo "usage: ${progname} [OPTION]..." echo echo "This script creates a basic syslog-ng configuration." echo echo "Options:" echo " --debug -d Enable shell's debug output." echo " --yes -y Answer all questions with \"yes\" automatically." echo " --no -n Answer all questions with \"no\" automatically." echo exit 1 ;; esac done # Check for ${SYSCONFDIR} directory if [ -e "${SYSCONFDIR}" -a ! -d "${SYSCONFDIR}" ] then echo echo "${SYSCONFDIR} is existant but not a directory." echo "Cannot create global configuration files." echo exit 1 fi # Create it if necessary [ ! -e "${SYSCONFDIR}" ] && mkdir -p "${SYSCONFDIR}" if [ ! -e "${SYSCONFDIR}" ] then echo echo "Creating ${SYSCONFDIR} directory failed." echo exit 1 fi setfacl -m u:system:rwx "${SYSCONFDIR}" # Only offer to overwrite if template files exist. if [ -f "${DEFAULTDIR}${SYSCONFFILE}" ] then # Check if syslog-ng.conf exists. If yes, ask for overwriting if [ -f "${SYSCONFFILE}" ] then if request "Overwrite existing ${SYSCONFFILE} file?" then mv -f "${SYSCONFFILE}" "${SYSCONFFILE}.old" if [ -f "${SYSCONFFILE}" ] then echo "Can't overwrite. ${SYSCONFFILE} is write protected." else echo "${SYSCONFFILE} has been renamed to ${SYSCONFFILE}.old." fi fi fi if [ ! -f "${SYSCONFFILE}" ] then echo "Creating default syslog-ng configuration files in ${SYSCONFDIR}" cp "${DEFAULTDIR}${SYSCONFFILE}" "${SYSCONFFILE}" setfacl -m u:system:rw- "${SYSCONFFILE}" if [ -f "${DEFAULTDIR}${SCLFILE}" ] then cp "${DEFAULTDIR}${SCLFILE}" "${SCLFILE}" setfacl -m u:system:rw- "${SCLFILE}" fi if [ -f "${DEFAULTDIR}${MODULESFILE}" ] then cp "${DEFAULTDIR}${MODULESFILE}" "${MODULESFILE}" setfacl -m u:system:rw- "${MODULESFILE}" fi fi fi # Check if syslogd is installed and remove on user request. if cygrunsrv -Q syslogd > /dev/null 2>&1 then echo "Warning: The syslogd service is already installed. You can not" echo "run both, syslogd and syslog-ng in parallel." echo if request "Do you want to deinstall the syslogd service in favor of syslog-ng?" then cygrunsrv -E syslogd cygrunsrv -R syslogd fi fi # Install syslog-ng service if it is not already installed if ! cygrunsrv -Q syslog-ng > /dev/null 2>&1 then echo echo echo "Warning: The following function requires administrator privileges!" echo echo "Do you want to install syslog-ng as service?" if request "(Say \"no\" if it's already installed as service)" then if cygrunsrv -I syslog-ng -d "CYGWIN syslog-ng" -p /usr/sbin/syslog-ng -a "-F" then echo echo "The service has been installed under LocalSystem account." echo "To start the service, call \`net start syslog-ng' or \`cygrunsrv -S syslog-ng'." echo echo "Check ${SYSCONFDIR}/syslog-ng.conf first, if it suits your needs." fi fi fi echo echo "Configuration finished. Have fun!" syslog-ng-syslog-ng-4.4.0/contrib/cygwin-packaging/syslog-ng.sh000077500000000000000000000032631450431004300245220ustar00rootroot00000000000000#!/bin/bash # # syslog-ng.sh, postinstall script for Cygwin # # This file is part of the Cygwin port of syslog-ng. # Directory where the config files are stored SYSCONFDIR="/etc/syslog-ng" # Old config file, up to 3.0.1. OLDSYSCONFFILE="/etc/syslog-ng.conf" # Paths of the config files starting with 3.2.1. SYSCONFFILE="${SYSCONFDIR}/syslog-ng.conf" SCLFILE="${SYSCONFDIR}/scl.conf" MODULESFILE="${SYSCONFDIR}/modules.conf" # Directory in which the templates are stored. DEFAULTDIR="/etc/defaults" # Directory to keep state information LOCALSTATEDIR=/var/lib/syslog-ng # If an old syslog-ng.conf file exists, but no new one, move the old # one over to the new configuration directory. if [ -f "${OLDSYSCONFFILE}" -a ! -f "${SYSCONFFILE}" ] then # Check for ${SYSCONFDIR} directory, create it if necessary. [ -e "${SYSCONFDIR}" -a ! -d "${SYSCONFDIR}" ] && exit 1 [ ! -e "${SYSCONFDIR}" ] && mkdir -p "${SYSCONFDIR}" [ ! -e "${SYSCONFDIR}" ] && exit 2 setfacl -m u:system:rwx "${SYSCONFDIR}" mv -f "${OLDSYSCONFFILE}" "${SYSCONFFILE}" setfacl -m u:system:rw- "${SYSCONFFILE}" # Always copy template files to ${SYSCONFDIR} and add a ".new" suffix # to the ${SYSCONFFILE} template so the admin knows something has changed. cp "${DEFAULTDIR}${SYSCONFFILE}" "${SYSCONFFILE}.new" cp "${DEFAULTDIR}${SCLFILE}" "${SCLFILE}" cp "${DEFAULTDIR}${MODULESFILE}" "${MODULESFILE}" fi # Make sure /var/lib/syslog-ng exists. if [ -e "${LOCALSTATEDIR}" -a ! -d "${LOCALSTATEDIR}" ] then rm -f "${LOCALSTATEDIR}" [ -e "${LOCALSTATEDIR}" ] && exit 3 fi [ ! -e "${LOCALSTATEDIR}" ] && mkdir -p "${LOCALSTATEDIR}" [ ! -d "${LOCALSTATEDIR}" ] && exit 4 setfacl -m u:system:rwx "${LOCALSTATEDIR}" exit 0 syslog-ng-syslog-ng-4.4.0/contrib/fedora-packaging/000077500000000000000000000000001450431004300221755ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/fedora-packaging/syslog-ng.conf000066400000000000000000000054251450431004300247740ustar00rootroot00000000000000# syslog-ng configuration file. # # This should behave pretty much like the original syslog on RedHat. But # it could be configured a lot smarter. # # See syslog-ng(8) and syslog-ng.conf(5) for more information. # # 20000925 gb@sysfive.com # # Updated by Frank Crawford () - 10 Aug 2002 # - for Red Hat 7.3 # - totally do away with klogd # - add message "kernel:" as is done with klogd. # # Updated by Frank Crawford () - 22 Aug 2002 # - use the log_prefix option as per Balazs Scheidler's email # # Updated by Jose Pedro Oliveira () - 05 Apr 2003 # - corrected filters 'f_filter2' and 'f_filter6' # these filters were only allowing messages of one specific # priority level; they should be allowing messages from that # priority and upper levels. # # Updated by Jose Pedro Oliveira () - 25 Jan 2005 # - Don't sync the d_mail destination # # Updated by Jose Pedro Oliveira () - 01 Feb 2005 # - /proc/kmsg is a file not a pipe. # (https://lists.balabit.hu/pipermail/syslog-ng/2005-February/006963.html) # options { sync (0); time_reopen (10); log_fifo_size (1000); long_hostnames (off); use_dns (no); use_fqdn (no); create_dirs (no); keep_hostname (yes); }; source s_sys { file ("/proc/kmsg" program_override("kernel")); unix-stream ("/dev/log"); internal(); # udp(ip(0.0.0.0) port(514)); }; destination d_cons { file("/dev/console"); }; destination d_mesg { file("/var/log/messages"); }; destination d_auth { file("/var/log/secure"); }; destination d_mail { file("/var/log/maillog" sync(10)); }; destination d_spol { file("/var/log/spooler"); }; destination d_boot { file("/var/log/boot.log"); }; destination d_cron { file("/var/log/cron"); }; destination d_mlal { usertty("*"); }; #filter f_filter1 { facility(kern); }; filter f_filter2 { level(info..emerg) and not facility(mail,authpriv,cron); }; filter f_filter3 { facility(authpriv); }; filter f_filter4 { facility(mail); }; filter f_filter5 { level(emerg); }; filter f_filter6 { facility(uucp) or (facility(news) and level(crit..emerg)); }; filter f_filter7 { facility(local7); }; filter f_filter8 { facility(cron); }; #log { source(s_sys); filter(f_filter1); destination(d_cons); }; log { source(s_sys); filter(f_filter2); destination(d_mesg); }; log { source(s_sys); filter(f_filter3); destination(d_auth); }; log { source(s_sys); filter(f_filter4); destination(d_mail); }; log { source(s_sys); filter(f_filter5); destination(d_mlal); }; log { source(s_sys); filter(f_filter6); destination(d_spol); }; log { source(s_sys); filter(f_filter7); destination(d_boot); }; log { source(s_sys); filter(f_filter8); destination(d_cron); }; syslog-ng-syslog-ng-4.4.0/contrib/fedora-packaging/syslog-ng.init000066400000000000000000000031061450431004300250040ustar00rootroot00000000000000#!/bin/sh # # syslog-ng This starts and stops syslog-ng # # chkconfig: 2345 12 88 # description: reads and logs messages to the system console, log \ # files, other machines and/or users as specified by \ # its configuration file. # processname: /sbin/syslog-ng # config: /etc/syslog-ng/syslog-ng.conf # config: /etc/sysconfig/syslog-ng # pidfile: /var/run/syslog-ng.pid # ### BEGIN INIT INFO # Provides: $syslog ### END INIT INFO # Source function library. . /etc/rc.d/init.d/functions exec="/sbin/syslog-ng" prog=$(basename $exec) [ -f $exec ] || exit 0 # Source config [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog lockfile=/var/lock/subsys/$prog umask 077 start() { echo -n $"Starting $prog: " daemon $exec $SYSLOGNG_OPTIONS retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { stop start } reload() { echo -n $"Reloading syslog-ng.conf file: " killproc $prog -HUP retval=$? echo return $retval } force_reload() { restart } fdr_status() { status $prog } case "$1" in start|stop|restart|reload) $1 ;; force-reload) force_reload ;; status) fdr_status ;; condrestart|try-restart) [ ! -f $lockfile ] || restart ;; *) echo $"Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload}" exit 2 esac syslog-ng-syslog-ng-4.4.0/contrib/fedora-packaging/syslog-ng.logrotate000066400000000000000000000003461450431004300260440ustar00rootroot00000000000000/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/boot.log /var/log/cron { sharedscripts postrotate /bin/kill -HUP `cat /var/run/syslog-ng.pid 2> /dev/null` 2> /dev/null || true endscript } syslog-ng-syslog-ng-4.4.0/contrib/fedora-packaging/syslog-ng.sysconfig000066400000000000000000000001431450431004300260430ustar00rootroot00000000000000#--- # Syslog-ng command line options # See syslog-ng(8) for more details #--- SYSLOGNG_OPTIONS="" syslog-ng-syslog-ng-4.4.0/contrib/freebsd-packaging/000077500000000000000000000000001450431004300223475ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/freebsd-packaging/syslog-ng.conf.example000066400000000000000000000104441450431004300265750ustar00rootroot00000000000000# defauld syslogd config converted from freebsd 6.1 options { dir_perm(0755); perm(0644); chain_hostnames(no); keep_hostname(yes); }; # Default local source. source local { unix-dgram("/var/run/log"); unix-dgram("/var/run/logpriv" perm(0600)); file("/dev/klog"); udp(ip(0.0.0.0) port(514)); internal(); }; # FILTERS: START # Filter LEGO bricks to build your castle :) # syslog level filters filter f_crit_emerg { level(crit..emerg); }; filter f_err_emerg { level(err..emerg); }; filter f_warn_emerg { level(warning..emerg); }; filter f_debug_emerg { level(debug..emerg); }; filter f_notice_emerg { level(notice..emerg); }; filter f_info_emerg { level(info..emerg); }; filter f_info { level(info); }; filter f_not_authpriv { not facility(authpriv); }; filter f_debug { level(debug); }; filter f_emerg { level(emerg); }; # Facility filters filter f_mail { facility(mail); }; filter f_kern { facility(kern); }; filter f_auth { facility(auth); }; filter f_lpr { facility(lpr); }; filter f_news { facility(news); }; filter f_kern { facility(kern); }; filter f_security { facility(security); }; filter f_auth{ facility(auth); }; filter f_authpriv { facility(authpriv); }; filter f_ftp { facility(ftp); }; filter f_cron { facility(cron); }; # program filters filter f_startslip { program("startslip"); }; filter f_ppp { program("ppp"); }; ## FILTERS: END # DESTINATIONS: START destination d_devconsole { file("/dev/console" create_dirs(yes)); }; destination d_messages { file("/var/log/messages" create_dirs(yes)); }; destination d_maillog { file("/var/log/maillog" create_dirs(yes)); }; destination d_security { file("/var/log/security" create_dirs(yes)); }; destination d_authlog { file("/var/log/auth.log" create_dirs(yes)); }; destination d_ldperr { file("/var/log/lpd-errs" create_dirs(yes)); }; destination d_xferlog { file("/var/log/xferlog" create_dirs(yes)); }; destination d_cron { file("/var/log/cron" create_dirs(yes)); }; destination d_debuglog { file("/var/log/debug.log" create_dirs(yes)); }; destination d_usertty { usertty("*"); }; destination d_slip { file("/var/log/slip.log" create_dirs(yes)); }; destination d_ppp { file("/var/log/ppp.log" create_dirs(yes)); }; # DESTINATIONS: END # LOGS: START # *.err;kern.warning;auth.notice;mail.crit /dev/console log { source(local); filter(f_mail); filter(f_crit_emerg); destination(d_devconsole); }; log { source(local); filter(f_err_emerg); destination(d_devconsole); }; log { source(local); filter(f_kern); filter(f_warn_emerg); destination(d_devconsole); }; log { source(local); filter(f_auth); filter(f_notice_emerg); destination(d_devconsole); }; # *.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err /var/log/messages log { source(local); filter(f_notice_emerg); filter(f_not_authpriv); destination(d_messages); }; log { source(local); filter(f_lpr); filter(f_info); destination(d_messages); }; log { source(local); filter(f_mail); filter(f_crit_emerg); destination(d_messages); }; log { source(local); filter(f_news); filter(f_err_emerg); destination(d_messages); }; log { source(local); filter(f_kern); filter(f_debug_emerg); destination(d_messages); }; # mail.info /var/log/maillog log { source(local); filter(f_mail); filter(f_info_emerg); destination(d_maillog); }; ## security.* /var/log/security log { source(local); filter(f_security); filter(f_debug_emerg); destination(d_security); }; # auth.info;authpriv.info /var/log/auth.log log { source(local); filter(f_auth); filter(f_info_emerg); destination(d_authlog); }; log { source(local); filter(f_authpriv); filter(f_info_emerg); destination(d_authlog); }; # lpr.info /var/log/lpd-errs log { source(local); filter(f_lpr); filter(f_info); destination(d_ldperr); }; # ftp.info /var/log/xferlog log { source(local); filter(f_ftp); filter(f_info_emerg); destination(d_xferlog); }; # cron.* /var/log/cron log { source(local); filter(f_cron); filter(f_debug_emerg); destination(d_cron); }; ## *.=debug /var/log/debug.log log { source(local); filter(f_debug); destination(d_debuglog); }; ## *.emerg * log { source(local); filter(f_emerg); destination(d_usertty); }; # !starslip # *.* /var/log/slip.log log { source(local); filter(f_startslip); destination(d_slip); }; # !ppp # *.* /var/log/ppp.log log { source(local); filter(f_ppp); destination(d_ppp); }; # LOGS: END syslog-ng-syslog-ng-4.4.0/contrib/freebsd-packaging/syslog-ng.rc.d000066400000000000000000000026741450431004300250520ustar00rootroot00000000000000#!/bin/sh # startup script for FreeBSD 6.x. # Written by Tamas Pal # PROVIDE: syslogd # REQUIRE: mountcritremote cleanvar newsyslog # BEFORE: SERVERS # Enabling syslog-ng: # * copy this script to /etc/rc.d or /usr/local/etc/rc.d # * Edit /etc/rc.conf and add the following lines: # ----- CUT HERE ----- # syslogd_enable="NO" # syslogng_enable="YES" # syslogng_flags="" # ----- CUT HERE ----- # * Add your extra flags to syslogng_flags EXCEPT the -p and -f # flags. These are added automatically by this script. To set # their value, change the value of the conf_file and pidfile variables below . "/etc/rc.subr" name="syslogng" rcvar=`set_rcvar` pidfile="/var/run/syslog-ng.pid" ## CONFIG OPTIONS: START # modify them according to your environment. installdir="/opt/syslog-ng" localstatedir="${installdir}/var" libpath="${installdir}/lib" conf_file="${installdir}/etc/syslog-ng.conf" ## CONFIG OPTIONS: END command="${installdir}/sbin/syslog-ng" required_files="$conf_file" start_precmd="syslog_ng_precmd" extra_commands="reload" LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$libpath export LD_LIBRARY_PATH syslog_ng_precmd() { if [ ! -d ${localstatedir} ]; then mkdir -p ${localstatedir} fi if [ ! -L /dev/log ]; then ln -s /var/run/log /dev/log fi } load_rc_config "$name" case $1 in start) syslogng_flags=" -p ${pidfile} -f ${conf_file} ${syslog_ng_flags}" ;; esac run_rc_command "$1" # vim: ft=sh syslog-ng-syslog-ng-4.4.0/contrib/get-github-actions-status.py000077500000000000000000000030271450431004300244100ustar00rootroot00000000000000#!/bin/env python3 import json import sys import urllib.parse import urllib.request from time import sleep def get_workflow_runs(workflow): url = "https://api.github.com/repos/syslog-ng/syslog-ng/actions/workflows/{}.yml/runs?branch=master".format(workflow) request = urllib.request.Request(url, None, {}) try: with urllib.request.urlopen(request) as response: binary_response = response.read() except urllib.error.HTTPError: print('"' + workflow + '" is not a valid workflow. See .github/workflows/') sys.exit(1) runs = json.loads(binary_response.decode())["workflow_runs"] if len(runs) == 0: print('No runs have been executed of "' + workflow + '" yet.') sys.exit(1) return runs def main(): workflow = sys.argv[1] while True: runs = get_workflow_runs(workflow) not_pr_runs = filter(lambda run: run["event"] != "pull_request", runs) latest_run = max(not_pr_runs, key=lambda run: run["updated_at"]) if latest_run["status"] != "completed": print("Job is still running. Trying again in 10 minutes.") sleep(10 * 60) continue result = latest_run["conclusion"] print('"' + latest_run["name"] + '" job finished.') print("Date: " + latest_run["updated_at"]) print("URL: " + latest_run["html_url"]) print("Result: " + result) if result == "success": sys.exit(0) else: sys.exit(1) if __name__ == "__main__": main() syslog-ng-syslog-ng-4.4.0/contrib/hpux-packaging/000077500000000000000000000000001450431004300217215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/hpux-packaging/syslog-ng.conf000066400000000000000000000042331450431004300245140ustar00rootroot00000000000000# # sample configuration file for syslog-ng on HP-UX # users should customize to fit their needs # # log syslog-ng's own messages to /var/log/syslog-ng.log source s_internal { internal(); }; destination d_syslognglog { file("/var/adm/syslog/syslog-ng.log" owner("root") group("adm") perm(0640)); }; log { source(s_internal); destination(d_syslognglog); }; # log everything to /var/adm/syslog/messages source s_local { pipe("/dev/log" pad_size(2048)); }; destination d_messages { file("/var/adm/syslog/messages" owner("root") group("adm") perm(0640)); }; log { source(s_local); destination(d_messages); }; # Remote logging # #source s_remote { # tcp(ip(0.0.0.0) port(514)); # udp(ip(0.0.0.0) port(514)); #}; # #destination d_separatedbyhosts { # file("/var/adm/syslog/syslog-ng/$HOST/messages" owner("root") group("root") perm(0640) dir_perm(0750) create_dirs(yes)); #}; # #log { # source(s_remote); # destination(d_separatedbyhosts); #}; # # Local filters examples # #filter f_messages { level(info..emerg); }; #filter f_secure { facility(authpriv); }; #filter f_mail { facility(mail); }; #filter f_cron { facility(cron); }; #filter f_emerg { level(emerg); }; #filter f_spooler { level(crit..emerg) and facility(uucp, news); }; #filter f_local7 { facility(local7); }; # # Local destination examples # #destination d_secure { file("/var/log/secure"); }; #destination d_maillog { file("/var/log/maillog"); }; #destination d_cron { file("/var/log/cron"); }; #destination d_console { usertty("root"); }; #destination d_spooler { file("/var/log/spooler"); }; #destination d_bootlog { file("/var/log/boot.log"); }; # # Local log examples - order DOES matter ! # #log { source(s_local); filter(f_emerg); destination(d_console); }; #log { source(s_local); filter(f_secure); destination(d_secure); flags(final); }; #log { source(s_local); filter(f_maillog); destination(d_maillog); flags(final); }; #log { source(s_local); filter(f_cron); destination(d_cron); flags(final); }; #log { source(s_local); filter(f_spooler); destination(d_spooler); }; #log { source(s_local); filter(f_local7); destination(d_bootlog); }; #log { source(s_local); filter(f_messages); destination(d_messages); }; syslog-ng-syslog-ng-4.4.0/contrib/hpux-packaging/syslog-ng.init000066400000000000000000000065261450431004300245410ustar00rootroot00000000000000#!/bin/sh ################################################################################ # # Program: syslog-ng init script # # Description: # # This is an init script for syslog-ng on the HP-UX platform. # # To start the service, we check if the daemon program is executable. # Accordingly, the preferred way to disable the service PERMANENTLY # is to rename the binary or remove execute permissions. # Ideally, you would remove the software from your system entirely. # # The lowest PID of a running instance of the executable is logged to a # file. This PID is used for killing the daemon. This is a best guess of # course, it is much better to use built-in shutdown functions if the # daemon has those. # # # Platforms (tested): HP-UX (B.10.20) # # # Author: Gregor Binder # # Last Changed: October 10, 2000 # # Copyright (c) 2000 by sysfive.com GmbH, All rights reserved. # ################################################################################ ################################################################################ # configuration # INIT_PROG="/opt/syslog-ng/sbin/syslog-ng" # FULL path to daemon required for fuser INIT_OPTS="" # options passed to daemon INIT_HOOK="1" # in case you want to use /etc/rc.config.d # comment this out and edit code below INIT_RDIR="/var/run" PATH=/bin:/sbin:/usr/bin:/usr/sbin INIT_NAME=`basename "$INIT_PROG"` INIT_RPID="${INIT_RDIR}/${INIT_NAME}.pid" ################################################################################ # init # INIT_RETURN=0 umask 077 # Error Handling the HP way # set_return () { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" INIT_RETURN=1 # always 1 so that 2 can be used for other reasons fi } case "$1" in 'start_msg') echo "Start $INIT_NAME" ;; 'stop_msg') echo "Stopping $INIT_NAME" ;; 'start') # Remove comments to enable reading config files # # if [ -f /etc/rc.config ] ; then # . /etc/rc.config # else # echo "ERROR: /etc/rc.config defaults file MISSING" # fi if [ "$INIT_HOOK" -eq 1 -a -x $INIT_PROG ] ; then $INIT_PROG $INIT_OPTS && echo "$INIT_NAME" set_return else INIT_RETURN=2 fi ;; 'stop') # Remove comments to enable reading config files # # if [ -f /etc/rc.config ] ; then # . /etc/rc.config # else # echo "ERROR: /etc/rc.config defaults file MISSING" # fi # Determine PID of process(es) to stop # if [ "$INIT_HOOK" -ne 1 ] ; then INIT_RETURN=2 else [ -r "$INIT_RPID" ] && { INIT_CPID=`cat "$INIT_RPID"` INIT_CPRG="`ps -ef | awk '$2 == '"$INIT_CPID"' { print $8 }'`" set_return [ "${INIT_CPRG:="unknown"}" = "$INIT_PROG" ] || { echo "process ID mismatch: [$INIT_CPID] is $INIT_CPRG" INIT_RETURN=1 } [ $INIT_RETURN -eq 0 ] && kill "$INIT_CPID" set_return [ $INIT_RETURN -eq 0 ] && rm -f "$INIT_RPID" set_return if [ $INIT_RETURN -eq 0 ]; then echo "$INIT_NAME stopped" else echo "Unable to stop $INIT_NAME" fi } fi ;; *) echo "usage: $0 {start|stop}" INIT_RETURN=1 ;; esac exit $INIT_RETURN syslog-ng-syslog-ng-4.4.0/contrib/init.d.HP-UX000066400000000000000000000065031450431004300207670ustar00rootroot00000000000000: ################################################################################ # # Program: syslog-ng init script # # Description: # # This is an init script for syslog-ng on the HP-UX platform. # # To start the service, we check if the daemon program is executable. # Accordingly, the preferred way to disable the service PERMANENTLY # is to rename the binary or remove execute permissions. # Ideally, you would remove the software from your system entirely. # # The lowest PID of a running instance of the executable is logged to a # file. This PID is used for killing the daemon. This is a best guess of # course, it is much better to use built-in shutdown functions if the # daemon has those. # # # Platforms (tested): HP-UX (B.10.20) # # # Author: Gregor Binder # # Last Changed: October 10, 2000 # # Copyright (c) 2000 by sysfive.com GmbH, All rights reserved. # ################################################################################ ################################################################################ # configuration # INIT_PROG="/path_to/syslog-ng" # FULL path to daemon required for fuser INIT_OPTS="" # options passed to daemon INIT_HOOK="1" # in case you want to use /etc/rc.config.d # comment this out and edit code below INIT_RDIR="/var/run" PATH=/bin:/sbin:/usr/bin:/usr/sbin INIT_NAME=`basename "$INIT_PROG"` INIT_RPID="${INIT_RDIR}/${INIT_NAME}.pid" ################################################################################ # init # INIT_RETURN=0 umask 077 # Error Handling the HP way # set_return () { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" INIT_RETURN=1 # always 1 so that 2 can be used for other reasons fi } case "$1" in 'start_msg') echo "Start $INIT_NAME" ;; 'stop_msg') echo "Stopping $INIT_NAME" ;; 'start') # Remove comments to enable reading config files # # if [ -f /etc/rc.config ] ; then # . /etc/rc.config # else # echo "ERROR: /etc/rc.config defaults file MISSING" # fi if [ "$INIT_HOOK" -eq 1 -a -x $INIT_PROG ] ; then $INIT_PROG $INIT_OPTS && echo "$INIT_NAME" set_return else INIT_RETURN=2 fi ;; 'stop') # Remove comments to enable reading config files # # if [ -f /etc/rc.config ] ; then # . /etc/rc.config # else # echo "ERROR: /etc/rc.config defaults file MISSING" # fi # Determine PID of process(es) to stop # if [ "$INIT_HOOK" -ne 1 ] ; then INIT_RETURN=2 else [ -r "$INIT_RPID" ] && { INIT_CPID=`cat "$INIT_RPID"` INIT_CPRG="`ps -ef | awk '$2 == '"$INIT_CPID"' { print $9 }'`" set_return [ "${INIT_CPRG:="unknown"}" = "$INIT_PROG" ] || { echo "process ID mismatch: [$INIT_CPID] is $INIT_CPRG" INIT_RETURN=1 } [ $INIT_RETURN -eq 0 ] && kill "$INIT_CPID" set_return [ $INIT_RETURN -eq 0 ] && rm -f "$INIT_RPID" set_return if [ $INIT_RETURN -eq 0 ]; then echo "$INIT_NAME stopped" else echo "Unable to stop $INIT_NAME" fi } fi ;; *) echo "usage: $0 {start|stop}" INIT_RETURN=1 ;; esac exit $INIT_RETURN syslog-ng-syslog-ng-4.4.0/contrib/init.d.RedHat000066400000000000000000000034321450431004300212730ustar00rootroot00000000000000: ################################################################################ # # Program: syslog-ng init script # # Description: # # This is an init script for syslog-ng on the Linux platform. # # It totally relies on the Redhat function library and works the same # way as other typical Redhat init scripts. # # # Platforms (tested): Linux (Redhat 6.1) # # # Author: Gregor Binder # # Last Changed: October 10, 2000 # # Copyright (c) 2000 by sysfive.com GmbH, All rights reserved. # ################################################################################ ################################################################################ # configuration # INIT_PROG="/path_to/syslog-ng" # Full path to daemon INIT_OPTS="" # options passed to daemon PATH=/bin:/sbin:/usr/bin:/usr/sbin INIT_NAME=`basename "$INIT_PROG"` # Source Redhat function library. # . /etc/rc.d/init.d/functions # Uncomment this if you are on Redhat and think this is useful # #. /etc/sysconfig/network # #if [ ${NETWORKING} = "no" ] #then # exit 0 #fi RETVAL=0 umask 077 ulimit -c 0 # See how we were called. case "$1" in start) echo -n "Starting $INIT_NAME: " daemon --check $INIT_PROG "$INIT_PROG $INIT_OPTS" RETVAL=$? echo -n "Starting Kernel Logger: " [ -x "/sbin/klogd" ] && daemon klogd echo [ $RETVAL -eq 0 ] && touch "/var/lock/subsys/${INIT_NAME}" ;; stop) echo -n "Stopping $INIT_NAME: " killproc $INIT_PROG RETVAL=$? echo -n "Stopping Kernel Logger: " [ -x "/sbin/klogd" ] && killproc klogd echo [ $RETVAL -eq 0 ] && rm -f "/var/lock/subsys/${INIT_NAME}" ;; status) status $INIT_PROG RETVAL=$? ;; restart|reload) $0 stop $0 start RETVAL=$? ;; *) echo "Usage: $0 {start|stop|status|restart|reload}" exit 1 esac exit $RETVAL syslog-ng-syslog-ng-4.4.0/contrib/init.d.RedHat-7.3000066400000000000000000000075251450431004300216070ustar00rootroot00000000000000################################################################################ # # Program: syslog-ng init script for Red Hat # ################################################################################ # the following information is for use by chkconfig # if you are want to manage this through chkconfig (as you should), you must # first must add syslog-ng to chkconfig's list of startup scripts it # manages by typing: # # chkconfig --add syslog-ng # # DO NOT CHANGE THESE LINES (unless you know what you are doing) # chkconfig: 2345 12 88 # description: syslog-ng is the next generation of the syslog daemon. \ # syslog-ng gives you the flexibility of logging not only by facility and \ # severity, but also by host, message content, date, etc. it can also replace \ # klogd's function of logging kernel messages # # This following block of lines is correct, do not change! (for more info, see # http://www.linuxbase.org/spec/refspecs/LSB_1.1.0/gLSB/facilname.html) ### BEGIN INIT INFO # Provides: $syslog ### END INIT INFO ################################################################################ # # This is an init script for syslog-ng on the Linux platform. # # It totally relies on the Redhat function library and works the same # way as other typical Redhat init scripts. # # # Platforms (tested): Linux (Redhat 7.3) # # # Author: Gregor Binder # Changed: October 10, 2000 # # Last Changed: September 27, 2002 # Updated by: Diane Davidowicz # changes: Brought the start script up to snuff as far as compliance # with managing the startup script through chkconfig; # added PATH variable ability to hook in path to syslog-ng (if # its necessary); converted init script format to the # standard init script format in Red Hat (7.3 to be exact) # including using the /etc/sysconfig/syslog-ng file to # managed the arguments to syslog-ng without changing this # script, and disabled klogd but noted where and under what # conditions it should be enabled. HAPPY LOGGING. # # Copyright (c) 2000 by sysfive.com GmbH, All rights reserved. # # ################################################################################ # # configuration # INIT_PROG=syslog-ng # # Source Redhat function library. # . /etc/rc.d/init.d/functions # Tack on path to syslog-ng if not already in PATH SYSLOGNG_PATH=":/usr/local/sbin" PATH=$PATH$SYSLOGNG_PATH export PATH # /etc/sysconfig/ is the standard way to pull in options for a daemon to use. # Source config if [ -f /etc/sysconfig/syslog-ng ] ; then . /etc/sysconfig/syslog-ng else SYSLOGNG_OPTIONS= fi RETVAL=0 umask 077 ulimit -c 0 # See how we were called. start() { echo -n "Starting $INIT_PROG: " daemon $INIT_PROG $SYSLOGNG_OPTIONS RETVAL=$? echo # syslog-ng can handle kernel messages. If you do this, don't # run klogd. Consult the following FAQ question to find out why. # # http://www.campin.net/syslog-ng/faq.html#klogd # # If you still prefer to run klogd without syslog-ng handling # kernel messages, uncomment the following block of lines #echo -n $"Starting kernel logger: " #daemon klogd $KLOGD_OPTIONS #echo [ $RETVAL -eq 0 ] && touch "/var/lock/subsys/${INIT_PROG}" return $RETVAL } stop() { # Same here concerning klogd. Uncomment the following block of # code if you are needing to run it #echo -n $"Shutting down kernel logger: " #killproc klogd #echo echo -n "Stopping $INIT_PROG: " killproc $INIT_PROG RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f "/var/lock/subsys/${INIT_PROG}" return $RETVAL } rhstatus() { status $INIT_PROG } restart() { stop start } case "$1" in start) start ;; stop) stop ;; status) rhstatus ;; restart|reload) restart ;; condrestart) [ -f /var/lock/subsys/syslog-ng ] && restart || : ;; *) echo $"Usage: $0 {start|stop|status|restart|reload}" exit 1 esac exit $? syslog-ng-syslog-ng-4.4.0/contrib/init.d.SuSE000066400000000000000000000060271450431004300207460ustar00rootroot00000000000000#! /bin/sh # # original Authors of /etc/init.d/syslog: # Florian La Roche , 1996 # Werner Fink , 1998 # # hacked for syslog-ng from above dudes' syslog script # Darth Elmo , 13 Sept 2001 # # updated for OpenSuse 10 by # Tamas Pal , 3, Nov 2006 # NOTES: # # Add the new variable SYSLOGNG_PARAMS to /etc/rc.config. Set it equal to # any syslog-ng startup flags/options you need (for most users it may be # left empty, but it's good to have it there anyhow. :-) # # Also, if you haven't already, copy the sample syslog-ng.config # files from $syslog-ng-source-dir/contrib and $syslog-ng-src-dir/doc # to /etc/syslog-ng/ (you'll need to "mkdir /etc/syslog-ng" first). Editing # one of these to meet your needs is less work than starting from scratch. # Just make sure that one is named "syslog-ng.conf", or that you point a # symbolic link called "syslog-ng.conf" to the one you want to use. # # Finally, add symbolic links to this script in /etc/rc.2, /etc/rc.3, # and /etc/rc.5. Rename init.d/syslog to something like init.d/syslog.use-ng # (easier than removing *its* symlinks from rc.2 et al, and easier to reenable # should you foolishly abandon syslog-ng later on). # # Have a whole butt-load o' fun, # Darth Elmo # # /sbin/init.d/syslog-ng # ### BEGIN INIT INFO # Provides: syslog-ng # Required-Start: $network # Required-Stop: $network # Default-Start: 2 3 5 # Default-Stop: 0 1 6 # Description: Start the system logging daemons ### END INIT INFO . /etc/rc.status || exit 1 NGBINDIR=/sbin BINDIR=/sbin test -x ${NGBINDIR}/syslog-ng || exit 0 test -x ${BINDIR}/klogd || exit 0 return=$rc_done case "$1" in start) checkproc ${BINDIR}/klogd && \ killproc ${BINDIR}/klogd 2> /dev/null checkproc ${NGBINDIR}/syslog-ng && { killproc ${NGBINDIR}/syslog-ng 2> /dev/null echo -n "Re-" } echo -n "Starting syslog-ng services" test -z "$KERNEL_LOGLEVEL" && KERNEL_LOGLEVEL=1 startproc ${NGBINDIR}/syslog-ng $SYSLOGNG_PARAMS || return=$rc_failed sleep 1 startproc ${BINDIR}/klogd -c $KERNEL_LOGLEVEL || return=$rc_failed echo -e "$return" ;; stop) echo -n "Shutting down syslog-ng services" killproc -TERM ${BINDIR}/klogd || return=$rc_failed killproc -TERM ${NGBINDIR}/syslog-ng || return=$rc_failed echo -e "$return" ;; restart) $0 stop && $0 start || return=$rc_failed ;; reload) echo -n "Reload syslog service" killproc -TSTP ${BINDIR}/klogd || return=$rc_failed killproc -HUP ${NGBINDIR}/syslog-ng || return=$rc_failed killproc -CONT ${BINDIR}/klogd || return=$rc_failed killproc -USR2 ${BINDIR}/klogd || return=$rc_failed echo -e "$return" ;; status) echo -n "Checking for service syslog-ng:" checkproc ${NGBINDIR}/syslog-ng && echo OK || echo No process ;; probe) test /etc/syslog-ng/syslog-ng.conf -nt /var/run/syslog-ng.pid && echo reload ;; *) echo "Usage: $0 {start|stop|restart|reload|probe}" exit 1 ;; esac test "$return" = "$rc_done" || exit 1 exit 0 syslog-ng-syslog-ng-4.4.0/contrib/init.d.SunOS000066400000000000000000000051061450431004300211330ustar00rootroot00000000000000: ################################################################################ # # Program: syslog-ng init script # # Description: # # This is an init script for syslog-ng on the Solaris platform. # # To start the service, we check if the config file exists and the daemon # program is executable. Accordingly, the preferred way to disable the # service PERMANENTLY is to rename the binary and/or configuration file # to filename.OFF. This avoids accidental execution. # # The lowest PID of a running instance of the executable is logged to a # file. This PID is used for killing the daemon. This is a best guess of # course, it is much better to use built-in shutdown functions if the # daemon has those. # # # Platforms (tested): SunOS (Solaris 2.6) # # # Author: Gregor Binder # # Last Changed: October 10, 2000 # # Copyright (c) 2000 by sysfive.com GmbH, All rights reserved. # ################################################################################ ################################################################################ # configuration # INIT_CONF="/etc/syslog-ng/syslog-ng.conf" # this file has to exist INIT_PROG="/path_to/syslog-ng" # FULL path to daemon required (fuser) INIT_OPTS="" # options passed to daemon INIT_NAME=`basename "$0"` INIT_RDIR="/var/run" INIT_RPID="${INIT_RDIR}/${INIT_NAME}.pid" PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt//bin:/opt//sbin ################################################################################ # init # INIT_RETURN=0 umask 077 ulimit -c 0 [ -d "$INIT_RDIR" ] || mkdir -p "$INIT_RDIR" || \ echo "Cannot make directory: $INIT_RDIR" INIT_RETURN=$? ################################################################################ # arguments processing # case "$1" in start) test -f "$INIT_CONF" -a -x "$INIT_PROG" || exit 0 "$INIT_PROG" "$INIT_OPTS" INIT_RETURN=$? ;; stop) [ -r "$INIT_RPID" ] && INIT_CPID=`cat "$INIT_RPID"` [ -z "$INIT_CPID" ] || \ INIT_CPRG="`ps -ef | awk '$2 == '"$INIT_CPID"' { print $9 }'`" INIT_RETURN=$? set ${INIT_CPRG:="unknown"} [ "$INIT_CPRG" = "$INIT_PROG" ] || { \ echo "process ID mismatch: [$INIT_CPID] is $INIT_CPRG" INIT_RETURN=1 } [ $INIT_RETURN -eq 0 ] && kill ${INIT_SIG:="-TERM"} $INIT_CPID INIT_RETURN=$? [ $INIT_RETURN -eq 0 ] && rm -f "$INIT_RPID" INIT_RETURN=$? ;; restart) INIT_SIG="-HUP" $0 stop $0 start INIT_RETURN=$? ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit $INIT_RETURN syslog-ng-syslog-ng-4.4.0/contrib/init.d.solaris000066400000000000000000000025241450431004300216010ustar00rootroot00000000000000#!/bin/sh # # $Id: init.d.solaris,v 1.3 2003/04/11 13:37:47 bazsi Exp $ # # adapted to syslog-ng by BJ, Aug, 7th 2000 # cleaned up by Bazsi, Oct, 12th 2000 # minor fix by Bojan Zdrnja, Apr, 11th 2003 # added nicer options field # DAEMON=/usr/local/sbin/syslog-ng OPTIONS="-f /etc/syslog-ng/syslog-ng.conf" case "$1" in start) if [ -f /etc/syslog-ng/syslog-ng.conf -a -f /usr/local/sbin/syslog-ng ]; then echo 'syslog-ng service starting.' # # Before syslog-ng starts, save any messages from previous # crash dumps so that messages appear in chronological order. # /usr/bin/savecore -m if [ -r /etc/dumpadm.conf ]; then . /etc/dumpadm.conf [ "x$DUMPADM_DEVICE" != xswap ] && \ /usr/bin/savecore -m -f $DUMPADM_DEVICE fi $DAEMON $OPTIONS -p /etc/syslog-ng/syslog-ng.pid fi ;; stop) if [ -f /etc/syslog-ng/syslog-ng.pid ]; then syspid=`/usr/bin/cat /etc/syslog-ng/syslog-ng.pid` [ "$syspid" -gt 0 ] && kill -15 $syspid && rm /etc/syslog-ng/syslog-ng.pid fi ;; *) echo "Usage: $0 { start | stop }" exit 1 ;; esac syslog-ng-syslog-ng-4.4.0/contrib/lfs-packaging/000077500000000000000000000000001450431004300215215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/lfs-packaging/Makefile.lfs000066400000000000000000000057061450431004300237540ustar00rootroot00000000000000# makefile to handle Syslog-NG install/uninstall on a LFS Linux system. # # INSTALL/UNINSTALL: # Use make -f Makefile.lfs install|uninstall to install and register or # uninstall Syslog-NG's init scripts. # # START/STOP Sysklogd or Syslog-NG # Starting Syslog-NG: make -f Makefile.lfs slng-start # Stopping Syslog-NG: make -f Makefile.lfs slng-stop # # Starting sysklogd: make -f Makefile.lfs sysklogd-start # Stopping sysklogd: make -f Makefile.lfs sysklogd-stop # ETCDIR=/etc EXTDIR=${DESTDIR}${ETCDIR} MODE=754 DIRMODE=755 CONFMODE=644 all: install create-dirs: install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc0.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc1.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc2.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc3.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc4.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc5.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rc6.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/rcsysinit.d install -d -m ${DIRMODE} ${EXTDIR}/rc.d/init.d install -d -m ${DIRMODE} ${EXTDIR}/sysconfig install: create-dirs install -m ${MODE} syslog-ng.init.lfs ${EXTDIR}/rc.d/init.d/syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc0.d/K90syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc1.d/K90syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc2.d/K90syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc3.d/S10syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc4.d/S10syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc5.d/S10syslog-ng ln -sf ../init.d/syslog-ng ${EXTDIR}/rc.d/rc6.d/K90syslog-ng rm -rf ${EXTDIR}/rc.d/rc0.d/K90sysklogd rm -rf ${EXTDIR}/rc.d/rc1.d/K90sysklogd rm -rf ${EXTDIR}/rc.d/rc2.d/K90sysklogd rm -rf ${EXTDIR}/rc.d/rc3.d/S10sysklogd rm -rf ${EXTDIR}/rc.d/rc4.d/S10sysklogd rm -rf ${EXTDIR}/rc.d/rc5.d/S10sysklogd rm -rf ${EXTDIR}/rc.d/rc6.d/K90sysklogd uninstall: slng-stop ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc0.d/K90sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc1.d/K90sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc2.d/K90sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc3.d/S10sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc4.d/S10sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc5.d/S10sysklogd ln -sf ../init.d/sysklogd ${EXTDIR}/rc.d/rc6.d/K90sysklogd rm -rf ${EXTDIR}/rc.d/rc0.d/K90syslog-ng rm -rf ${EXTDIR}/rc.d/rc1.d/K90syslog-ng rm -rf ${EXTDIR}/rc.d/rc2.d/K90syslog-ng rm -rf ${EXTDIR}/rc.d/rc3.d/S10syslog-ng rm -rf ${EXTDIR}/rc.d/rc4.d/S10syslog-ng rm -rf ${EXTDIR}/rc.d/rc5.d/S10syslog-ng rm -rf ${EXTDIR}/rc.d/rc6.d/K90syslog-ng rm -rf ${EXTDIR}/rc.d/init.d/syslog-ng sysklogd-stop: ${EXTDIR}/rc.d/init.d/sysklogd stop || true sysklogd-start: ${EXTDIR}/rc.d/init.d/sysklogd start || true slng-stop: ${EXTDIR}/rc.d/init.d/syslog-ng stop || true slng-start: ${EXTDIR}/rc.d/init.d/syslog-ng start || true .PHONY: all create-dirs install \ slng-stop slng-start \ sysklogd-stop sysklogd-start syslog-ng-syslog-ng-4.4.0/contrib/lfs-packaging/README.lfs000066400000000000000000000007711450431004300231710ustar00rootroot00000000000000Installation instructions for Syslog-NG on an Linux From Scratch system. ======================================================================== Installing/uninstalling Syslog-NG's init script use the Makefile.lfs makefile. Further instruction could be found in the said makefile. Before starting Syslog-NG, create or modify a syslog-ng.conf file in /opt/syslog-ng/etc. The syslog-ng.conf files in /opt/syslog-ng/contrib/fedora and /opt/syslog-ng/contrib/redhat-el could be used as a starting pint. syslog-ng-syslog-ng-4.4.0/contrib/lfs-packaging/syslog-ng.init.lfs000077500000000000000000000024461450431004300251240ustar00rootroot00000000000000#!/bin/sh # Inintscript for LFS (Linux From Scratch) systems. # # syslog-ng This starts and stops syslog-ng # # description: reads and logs messages to the system console, log \ # files, other machines and/or users as specified by \ # its configuration file. # processname: /sbin/syslog-ng # config: /etc/syslog-ng/syslog-ng.conf # config: /etc/sysconfig/syslog-ng # pidfile: /var/run/syslog-ng.pid # # Source function library. . /etc/sysconfig/rc . ${rc_functions} root="/opt/syslog-ng" exec="$root/sbin/syslog-ng" conf="$root/etc/syslog-ng.conf" prog=$(basename $exec) export LD_LIBRARY_PATH=$root/lib:$LD_LIBRARY_PATH [ -f $exec ] || exit 0 # Source config [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog umask 077 start() { boot_mesg "Starting $prog: " loadproc $exec -f $conf $SYSLOGNG_OPTIONS } stop() { boot_mesg "Stopping $prog: " killproc $prog } restart() { stop start } reload() { echo -n $"Reloading syslog-ng.conf file: " reloadproc $prog } case "$1" in start|stop|restart|reload) $1 ;; force-reload) restart ;; status) statusproc $exec ;; *) echo $"Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload}" exit 2 esac syslog-ng-syslog-ng-4.4.0/contrib/openbsd-packaging/000077500000000000000000000000001450431004300223675ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/openbsd-packaging/syslog-ng.conf000066400000000000000000000104421450431004300251610ustar00rootroot00000000000000# syslog-ng configuration file for OpenBSD. # This should provide behavior similar to OpenBSD's syslog.conf(5). # 2021-05-24 millert@openbsd.org @version: 4.4 @requires openbsd options { use_dns(no); dns_cache(no); create_dirs(no); keep_hostname(yes); }; source s_local { openbsd(); unix-dgram ("/dev/log"); internal(); }; #source s_net { # udp(port(514)); #}; destination d_console { file("/dev/console"); }; destination d_messages { file("/var/log/messages" owner(root) group(wheel) perm(0644)); }; destination d_authlog { file("/var/log/authlog" owner(root) group(wheel) perm(0640)); }; destination d_secure { file("/var/log/secure" owner(root) group(wheel) perm(0600)); }; destination d_cronlog { file("/var/cron/log" owner(root) group(wheel) perm(0600)); }; destination d_daemon { file("/var/log/daemon" owner(root) group(wheel) perm(0640)); }; destination d_xferlog { file("/var/log/xferlog" owner(root) group(wheel) perm(0640)); }; destination d_lpderrs { file("/var/log/lpd-errs" owner(root) group(wheel) perm(0640)); }; destination d_maillog { file("/var/log/maillog" owner(root) group(wheel) perm(0600)); }; destination d_doaslog { file("/var/log/doas"); }; destination d_ttyall { usertty("*"); }; destination d_ttyroot { usertty("root"); }; destination d_loghost { udp("loghost" port(514)); }; filter f_notice { level(notice .. emerg) and not(facility(auth,authpriv,cron,ftp,kern,lpr,mail,user)); }; filter f_kerndebug { level(debug .. emerg) and facility(kern); }; filter f_msginfo { level(info .. emerg) and facility(syslog,user); }; filter f_authinfo { level(info .. emerg) and facility(auth); }; filter f_authprivdebug { level(debug .. emerg) and facility(authpriv); }; filter f_croninfo { level(info .. emerg) and facility(cron); }; filter f_daemoninfo { level(info .. emerg) and facility(daemon); }; filter f_ftpinfo { level(info .. emerg) and facility(ftp); }; filter f_lprdebug { level(debug .. emerg) and facility(lpr); }; filter f_mailinfo { level(info .. emerg) and facility(mail); }; filter f_emerg { level(emerg); }; filter f_to_console { not (facility(authpriv)) and ((level(notice .. emerg) and facility(auth)) or (level(debug .. emerg) and facility(kern)) or (level(crit .. emerg) and facility(mail)) or level(err .. emerg)); }; filter f_to_root { (level(debug .. emerg) and facility(auth)) or (level(notice .. emerg)); }; filter f_to_loghost { (level(notice .. emerg) and not (facility(auth,authpriv,cron,ftp,kern,lpr,mail,user))) or (level(info .. emerg) and facility(auth,daemon,syslog,user)) or (level(debug .. emerg) and facility(authpriv,kern)); }; filter f_prog_doas { program("doas"); }; log { source(s_local); filter(f_notice); destination(d_messages);}; log { source(s_local); filter(f_kerndebug); destination(d_messages);}; log { source(s_local); filter(f_msginfo); destination(d_messages);}; log { source(s_local); filter(f_authinfo); destination(d_authlog); }; log { source(s_local); filter(f_authprivdebug); destination(d_secure); }; log { source(s_local); filter(f_croninfo); destination(d_cronlog); }; log { source(s_local); filter(f_daemoninfo); destination(d_daemon); }; log { source(s_local); filter(f_ftpinfo); destination(d_xferlog); }; log { source(s_local); filter(f_lprdebug); destination(d_lpderrs); }; log { source(s_local); filter(f_mailinfo); destination(d_maillog); }; # Uncomment this line to send "important" messages to the system # console: be aware that this could create lots of output. #log { source(s_local); filter(f_to_console); destination(d_console); }; # Uncomment this to have all messages of notice level and higher # as well as all authentication messages sent to root. #log { source(s_local); filter(f_to_root); destination(d_ttyroot); }; # Uncomment if you want everyone to get emergency messages. #log { source(s_local); filter(f_emerg); destination(d_ttyall); }; # Uncomment to log to a central host named "loghost". #log { source(s_local); filter(f_to_loghost); destination(d_loghost); }; # Uncomment to log messages from doas(1) to its own log file. Matches are done # based on the program name. # Program-specific logs: #log { source(s_local); filter(f_prog_doas); destination(d_doaslog); }; # Uncomment to log messages from the network. # Note: it is recommended to specify a different destination here. #log { source(s_net); destination(d_messages); }; syslog-ng-syslog-ng-4.4.0/contrib/relogger.pl000066400000000000000000000115231450431004300211600ustar00rootroot00000000000000#!/usr/local/bin/perl -w # take syslog messages from stdin - push them through syslog again # by Ed Ravin . Made available to the # public courtesy of PANIX (http://www.panix.com). # This script is licensed under the GPL. # Requires Date::Parse and Time::HiRes modules my $usage= "relogger.pl [--facility fac] [--priority pri] [--replayspeed factor]\n"; use strict; use Sys::Syslog qw(:DEFAULT setlogsock); use Getopt::Long; use Date::Parse; # for str2time use Time::HiRes qw ( sleep ); my %opt; die $usage unless GetOptions (\%opt, "debug", "facility=s", "priority=s", "replayspeed=s"); setlogsock('unix') if grep /^ $^O $/xo, ("linux", "openbsd", "freebsd", "netbsd"); my $facility= $opt{'facility'} || "mail"; my $priority= $opt{'priority'} || "info"; my $replayspeed= $opt{'replayspeed'} || 0; my $debug= $opt{'debug'} || 0; die "$0: Option 'replayspeed' must be a valid floating point number\n" unless $replayspeed =~ /^[0-9]*\.?[0-9]*$/; my $progname= ""; # Aug 5 20:28:17 grand-central postfix/qmgr[4389]: AC2BB7F9A: removed # my $thistime= str2time($date); # warn "$0: cannot parse date '$date'\n" if !$thistime; my $lasttimestamp= 0; my $timestamp; my $timestep= 0; while(<>) { if ( ((my ($timestr, $process, $msg))= /^(.*) \S+ ([^ []*)\[\d+\]: (.*)$/ ) == 3) { $timestamp= str2time($timestr) || warn "$0: cannot parse timestamp '$timestr'\n"; if ($progname ne $process) { closelog; openlog "$process", 'ndelay,pid', $facility or die "$0: openlog: $!\n"; $progname= $process; } $timestep= $timestamp - $lasttimestamp; if ($replayspeed and $timestep > 0 and $lasttimestamp > 0) { warn "sleeping for " . $timestep * $replayspeed . " seconds...\n" if $debug; sleep( $timestep * $replayspeed); } syslog $priority, "%s", $msg unless $debug; warn "$process $facility/$priority $msg\n" if $debug; $lasttimestamp= $timestamp; } else { warn "$0: cannot parse input line $.: $_\n"; } } __END__ =head1 NAME relogger.pl - re-inject syslog log files back into syslog =head1 SYNOPSIS B [I<--facility fac>] [I<--priority pri>] [I<--replayspeed factor>] [I<--debug]>] =head1 DESCRIPTION B takes syslog-formatted messages on standard input and re-sends them via the default syslog mechanism. The existing timestamps are stripped off the message before it is re-sent. Delays between messages can be enabled with the I<--replayseed> option (see B below to simulate the arrival times of the original messages. was written to help test configurations for programs like B or B that parse log output and take actions based on what messages appear in the logs. =head1 OPTIONS =item B<--facility> I specify the syslog facility to log the messages to. Standard syslog messages do not store the facility the message was logged on, so this cannot be determined from the input. The default is the B facility. =item B<--priority> I specify the syslog priority to log the messages to. The default is the B priority. As with B<--facility>, this information cannot be discovered from the input. =item B<--replayspeed> I attempt to parse the timestamps of the input messages, and simulate the original arrival times by sleeping between each message. The sleep time is multiplied by I. To send simulated log events with time spacing at the same time as the original arrival times, use a I of 1. To send simulated log events at twice the speed of the original logs, use a I of 0.5 (i.e. sleep only half the original time between log messages). =item B<--debug> send all output to standard error, rather than to syslog. Also prints an extra diagnostic message or two. =head1 BUGS B is a beta-quality tool for testing logging configurations. It is not yet recommended for production use. It would be nice to be able to specify the input filename on the command line, instead of requiring it to be on standard input. It would be nice to be able to control the syslog mechanism on the command line (i.e. specify whether to use a local or remote host) rather than just using the system default. The original PID in the message is replaced by the current PID of B in the simulated message. Also, the PID of B will appear in the simulated message even if the original one did not supply a PID. In spite of using Time::HiRes to enable sleeping in fractional seconds, some environments seem to still round off to seconds. This needs a bit more investigation. =head1 AUTHOR B was written by Ed Ravin , and is made available to the public by courtesy of PANIX (http://www.panix.com). This script is licensed under the GPL. B requires the Date::Parse and the Time::HiRes Perl modules. syslog-ng-syslog-ng-4.4.0/contrib/rhel-packaging/000077500000000000000000000000001450431004300216675ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/rhel-packaging/syslog-ng.conf000066400000000000000000000040361450431004300244630ustar00rootroot00000000000000# # configuration file for syslog-ng, customized for remote logging # source s_internal { internal(); }; destination d_syslognglog { file("/var/log/syslog-ng.log"); }; log { source(s_internal); destination(d_syslognglog); }; # Local sources, filters and destinations are commented out # If you want to replace sysklogd simply uncomment the following # parts and disable sysklogd # # Local sources # #source s_local { # unix-dgram("/dev/log"); # file("/proc/kmsg" program_override("kernel")); #}; # # Local filters # #filter f_messages { level(info..emerg); }; #filter f_secure { facility(authpriv); }; #filter f_mail { facility(mail); }; #filter f_cron { facility(cron); }; #filter f_emerg { level(emerg); }; #filter f_spooler { level(crit..emerg) and facility(uucp, news); }; #filter f_local7 { facility(local7); }; # # Local destinations # #destination d_messages { file("/var/log/messages"); }; #destination d_secure { file("/var/log/secure"); }; #destination d_maillog { file("/var/log/maillog"); }; #destination d_cron { file("/var/log/cron"); }; #destination d_console { usertty("root"); }; #destination d_spooler { file("/var/log/spooler"); }; #destination d_bootlog { file("/var/log/boot.log"); }; # # Local logs - order DOES matter ! # #log { source(s_local); filter(f_emerg); destination(d_console); }; #log { source(s_local); filter(f_secure); destination(d_secure); flags(final); }; #log { source(s_local); filter(f_mail); destination(d_maillog); flags(final); }; #log { source(s_local); filter(f_cron); destination(d_cron); flags(final); }; #log { source(s_local); filter(f_spooler); destination(d_spooler); }; #log { source(s_local); filter(f_local7); destination(d_bootlog); }; #log { source(s_local); filter(f_messages); destination(d_messages); }; # Remote logging source s_remote { tcp(ip(0.0.0.0) port(514)); udp(ip(0.0.0.0) port(514)); }; destination d_separatedbyhosts { file("/var/log/syslog-ng/$HOST/messages" owner("root") group("root") perm(0640) dir_perm(0750) create_dirs(yes)); }; log { source(s_remote); destination(d_separatedbyhosts); }; syslog-ng-syslog-ng-4.4.0/contrib/rhel-packaging/syslog-ng.init000066400000000000000000000023501450431004300244760ustar00rootroot00000000000000#!/bin/bash # # syslog-ng This starts and stops syslog-ng # # chkconfig: 2345 12 88 # description: syslog-ng is an alternative system logger # processname: syslog-ng # pidfile: /var/run/syslog-ng.pid ### BEGIN INIT INFO # Provides: $syslog-ng ### END INIT INFO # Source function library. . /etc/init.d/functions binary="/sbin/syslog-ng" [ -x $binary ] || exit 0 RETVAL=0 start() { echo -n "Starting syslog-ng: " daemon $binary RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/syslog-ng } stop() { echo -n "Shutting down syslog-ng: " killproc syslog-ng RETVAL=$? echo if [ $RETVAL -eq 0 ]; then rm -f /var/lock/subsys/syslog-ng rm -f /var/run/syslog-ng.pid fi } restart() { echo -n "Restarting syslog-ng: " $binary --syntax-only RETVAL=$? echo if [ $RETVAL -eq 0 ]; then stop sleep 2 start fi } reload() { echo -n "Reloading syslog-ng: " $binary --syntax-only RETVAL=$? if [ $RETVAL -eq 0 ]; then killproc syslog-ng -1 fi } case "$1" in start) start ;; stop) stop ;; status) status syslog-ng ;; restart) restart ;; reload) reload ;; condrestart) [ -f /var/lock/subsys/syslog-ng ] && restart ;; *) echo "Usage: $0 {start|stop|status|restart|reload|condrestart}" ;; esac syslog-ng-syslog-ng-4.4.0/contrib/rhel-packaging/syslog-ng.logrotate000066400000000000000000000001771450431004300255400ustar00rootroot00000000000000/var/log/syslog-ng.log { weekly rotate 52 compress postrotate /etc/rc.d/init.d/syslog-ng reload 2>/dev/null endscript } syslog-ng-syslog-ng-4.4.0/contrib/scripts/000077500000000000000000000000001450431004300205025ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/scripts/config-graph-json-to-dot.py000077500000000000000000000010051450431004300255720ustar00rootroot00000000000000#!/usr/bin/env python3 import json, sys j = None if len(sys.argv) == 1: j = json.loads(sys.stdin.read()) else: file_name = sys.argv[1] with open(file_name) as f: j = json.loads(f.read()) nodes = j["nodes"] arcs = j["arcs"] print("digraph D {") for node in nodes: print(" Node{} [label=\"{} {}\", shape=box]".format(node["node"], node["node"], ", ".join(node["info"]))) for arc in arcs: print(" Node{} -> Node{} [label=\"{}\"]".format(arc["from"], arc["to"], arc["type"])) print("}") syslog-ng-syslog-ng-4.4.0/contrib/selinux/000077500000000000000000000000001450431004300205025ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/selinux/README000066400000000000000000000057761450431004300214010ustar00rootroot00000000000000SELINUX SUPPORT FOR SYSLOG-NG This directory contains syslog-ng's and additional plugins' SELinux policy files. By compiling and loading them into your kernel, your syslog-ng instance will be able to work with its default configuration in a SELinux enabled environment. SELinux support was added in syslog-ng 5.2 for the following platforms: Red Hat Enterprise Linux/CentOS/Oracle Linux 5 Red Hat Enterprise Linux/CentOS/Oracle Linux 6 Since then, support for the following platformas were added: Red Hat Enterprise Linux/CentOS/Oracle Linux 7 Red Hat Enterprise Linux/CentOS/Oracle Linux 8 Red Hat Enterprise Linux/CentOS/Oracle Linux 9 PRE-REQUISITES The installation steps may differ on these operating systems, so you will find RHEL version specific information, too. Root privileges are needed to run most commands. You need the following RPM packages pre-installed to be able to compile and load SELinux policy modules: policycoreutils policycoreutils-python policycoreutils-devel (only available on RHEL/CentOS/Oracle Linux 7) policycoreutils-python-utils (only available on RHEL/CentOS/Oracle Linux 8) selinux-policy-devel (only available on RHEL/CentOS/Oracle Linux 8) If they are not installed on your system, you can install them with the following command: # yum install policycoreutils policycoreutils-devel policycoreutils-python policycoreutils-python-utils selinux-policy-devel The SELinux policy is only checked/applied to the syslog-ng process if it is started by the init daemon or systemd (depending on the OS version). INSTALLATION To compile and load this module, you have to run the 'syslog_ng.sh' script. It compiles and loads the syslog_ng SELinux policy module and policy modules for various other components depending on your choice. It also restores the right SELinux file contexts in syslog-ng's install directory. The changes will take effect after restarting syslog-ng: # cd /opt/syslog-ng/share/doc/selinux # ./syslog_ng.sh For information about restarting syslog-ng, please read the RESTARTING SYSLOG-NG section. UNINSTALL The module will be active, until you remove it. After that you have to restart syslog-ng. # ./syslog_ng.sh --remove For information about restarting syslog-ng, please read the RESTARTING SYSLOG-NG section. RESTARTING SYSLOG-NG You can restart syslog-ng on RHEL/CentOS/Oracle 5 and 6 by: # service syslog-ng restart On RHEL/CentOS/Oracle Linux 7, 8 and 9 you have to run: # systemctl restart syslog-ng ADDITIONAL INFORMATION Syslog-ng is able to create coredumps and it's disabled by default. You can enable coredumps by # setsebool -P daemons_dump_core 1 Please note, that this command enables core dumping for all daemons on your system, not only for syslog-ng. There is no way to enable core dumps in SELinux on a per-application basis. If you have problems with SELinux and syslog-ng, you can turn to One Identity's support team. syslog-ng-syslog-ng-4.4.0/contrib/selinux/labels.txt000066400000000000000000000057371450431004300225210ustar00rootroot00000000000000FILE CONTEXTS FOR SYSLOG-NG: /dev/log: devlog_t /opt/syslog-ng: usr_t /opt/syslog-ng/bin: bin_t /opt/syslog-ng/etc: etc_t /opt/syslog-ng/etc/syslog-ng.conf* syslog_conf_t /opt/syslog-ng/include: usr_t /opt/syslog-ng/lib: lib_t /opt/syslog-ng/libexec: bin_t /opt/syslog-ng/libexec/syslog-ng: syslogd_exec_t /opt/syslog-ng/libexec/syslog-ng-wrapper.sh syslogd_exec_t /opt/syslog-ng/sbin: usr_t /opt/syslog-ng/share: usr_t /opt/syslog-ng/share/man: man_t /opt/syslog-ng/share/include/scl/system/generate-system-source.sh: bin_t /opt/syslog-ng/var: syslogd_var_lib_t /opt/syslog-ng/var/run: syslogd_var_run_t /opt/syslog-ng/var/syslog-ng.persist: syslogd_var_lib_t /etc/rc.d/init.d/syslog-ng: syslogd_initrc_exec_t PROCESS LABEL (RHEL9): when syslog-ng was started by systemd (by systemctl or during boot): system_u:system_r:syslogd_t:s0 when syslog-ng was started manually (/opt/syslog-ng/sbin/syslog-ng -Fevd): unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023 PROCESS LABEL (RHEL8): when syslog-ng was started by systemd (by systemctl or during boot): system_u:system_r:syslogd_t:s0 when syslog-ng was started manually (/opt/syslog-ng/sbin/syslog-ng -Fevd): unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023 PROCESS LABEL (RHEL7): when syslog-ng was started by systemd (by systemctl or during boot): system_u:system_r:syslogd_t:s0 when syslog-ng was started manually (/opt/syslog-ng/sbin/syslog-ng -Fevd): unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023 PROCESS LABEL (RHEL6): when syslog-ng was started by init during boot: system_u:system_r:syslogd_t:s0 when syslog-ng was started by init, but manually (service syslog-ng start) unconfined_u:system_r:syslogd_t:s0 when syslog-ng was started manually (/opt/syslog-ng/sbin/syslog-ng -Fevd) unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 PROCESS LABEL (RHEL5): when syslog-ng was started by init during boot: system_u:system_r:syslogd_t:s0 when syslog-ng was started by init, but manually (service syslog-ng start) root:system_r:syslogd_t:s0 when syslog-ng was started manually (/opt/syslog-ng/sbin/syslog-ng -Fevd) root:system_r:unconfined_t:s0-s0:c0.c1023 syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/000077500000000000000000000000001450431004300212715ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_safe/000077500000000000000000000000001450431004300232525ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_safe/syslog_ng.el5.fc.in000066400000000000000000000007601450431004300266640ustar00rootroot00000000000000$PATH$/etc/syslog-ng.conf(.*)? -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/etc/conf.d/.*.conf -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/var/syslog-ng.* -- gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec/syslog-ng -- gen_context(system_u:object_r:syslogd_exec_t,s0) /etc/rc\.d/init\.d/syslog-ng -- gen_context(system_u:object_r:initrc_exec_t,s0) $PATH$/share/include/scl/system/generate-system-source.sh -- gen_context(system_u:object_r:bin_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_safe/syslog_ng.el6.fc.in000066400000000000000000000007701450431004300266660ustar00rootroot00000000000000$PATH$/etc/syslog-ng.conf(.*)? -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/etc/conf.d/.*.conf -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/var/syslog-ng.* -- gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec/syslog-ng -- gen_context(system_u:object_r:syslogd_exec_t,s0) /etc/rc\.d/init\.d/syslog-ng -- gen_context(system_u:object_r:syslogd_initrc_exec_t,s0) $PATH$/share/include/scl/system/generate-system-source.sh -- gen_context(system_u:object_r:bin_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_safe/syslog_ng.el789.fc.in000066400000000000000000000007711450431004300270510ustar00rootroot00000000000000$PATH$/etc/syslog-ng.conf(.*)? -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/etc/conf.d/.*.conf -- gen_context(system_u:object_r:syslog_conf_t,s0) $PATH$/var/syslog-ng.* -- gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec/syslog-ng -- gen_context(system_u:object_r:syslogd_exec_t,s0) $PATH$/libexec/syslog-ng-wrapper.sh -- gen_context(system_u:object_r:syslogd_exec_t,s0) $PATH$/share/include/scl/system/generate-system-source.sh -- gen_context(system_u:object_r:bin_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_unsafe/000077500000000000000000000000001450431004300236155ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_unsafe/syslog_ng.el5.fc.in000066400000000000000000000010611450431004300272220ustar00rootroot00000000000000$PATH$ -d gen_context(system_u:object_r:usr_t,s0) $PATH$/bin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/sbin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/etc(/.*)? gen_context(system_u:object_r:etc_t,s0) $PATH$/lib(/.*)? gen_context(system_u:object_r:lib_t,s0) $PATH$/var -d gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/var/run(/.*)? gen_context(system_u:object_r:syslogd_var_run_t,s0) $PATH$/share/man(/.*)? gen_context(system_u:object_r:man_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_unsafe/syslog_ng.el6.fc.in000066400000000000000000000010611450431004300272230ustar00rootroot00000000000000$PATH$ -d gen_context(system_u:object_r:usr_t,s0) $PATH$/bin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/sbin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/etc(/.*)? gen_context(system_u:object_r:etc_t,s0) $PATH$/lib(/.*)? gen_context(system_u:object_r:lib_t,s0) $PATH$/var -d gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/var/run(/.*)? gen_context(system_u:object_r:syslogd_var_run_t,s0) $PATH$/share/man(/.*)? gen_context(system_u:object_r:man_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/root_unsafe/syslog_ng.el789.fc.in000066400000000000000000000010621450431004300274060ustar00rootroot00000000000000$PATH$ -d gen_context(system_u:object_r:usr_t,s0) $PATH$/bin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/sbin(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/etc(/.*)? gen_context(system_u:object_r:etc_t,s0) $PATH$/lib(/.*)? gen_context(system_u:object_r:lib_t,s0) $PATH$/var -d gen_context(system_u:object_r:syslogd_var_lib_t,s0) $PATH$/libexec(/.*)? gen_context(system_u:object_r:bin_t,s0) $PATH$/var/run(/.*)? gen_context(system_u:object_r:syslogd_var_run_t,s0) $PATH$/share/man(/.*)? gen_context(system_u:object_r:man_t,s0) syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el5.te.in000066400000000000000000000010221450431004300247130ustar00rootroot00000000000000require { type syslogd_t, syslogd_var_run_t, shell_exec_t, bin_t; class file { ioctl read getattr lock execute execute_no_trans }; class sock_file { ioctl read write create getattr setattr lock append unlink link rename }; } allow syslogd_t syslogd_var_run_t:sock_file { ioctl read write create getattr setattr lock append unlink link rename }; allow syslogd_t bin_t:file { ioctl read getattr lock execute execute_no_trans }; allow syslogd_t shell_exec_t:file { read execute getattr execute_no_trans }; syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el6.0to4.te.in000066400000000000000000000020001450431004300254760ustar00rootroot00000000000000require { type syslogd_t, shell_exec_t, bin_t, kmsg_device_t, anon_inodefs_t, tmpfs_t; class file { ioctl read write getattr lock execute execute_no_trans open create unlink }; class dir { add_name remove_name }; class chr_file { open read }; class lnk_file { read getattr }; class process { fork sigchld sigkill sigstop signull signal getsched setsched setpgid getcap setcap setrlimit }; } allow syslogd_t shell_exec_t:file { read execute getattr execute_no_trans open }; allow syslogd_t bin_t:file { ioctl read getattr lock execute execute_no_trans open }; allow syslogd_t bin_t:lnk_file { read getattr }; allow syslogd_t kmsg_device_t:chr_file { open read }; allow syslogd_t anon_inodefs_t:file { read write }; allow syslogd_t tmpfs_t:dir { add_name remove_name write }; allow syslogd_t tmpfs_t:file { create unlink open read write }; allow syslogd_t syslogd_t:process { fork sigchld sigkill sigstop signull signal getsched setsched setpgid getcap setcap setrlimit }; syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el6.5up.te.in000066400000000000000000000005701450431004300254330ustar00rootroot00000000000000require { type kmsg_device_t, tmpfs_t, syslogd_t; class chr_file { open read }; class dir { add_name remove_name }; class file { create unlink open read write }; } allow syslogd_t kmsg_device_t:chr_file { open read }; allow syslogd_t tmpfs_t:dir { add_name remove_name write }; allow syslogd_t tmpfs_t:file { create unlink open read write }; syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el7.te.in000066400000000000000000000000011450431004300247110ustar00rootroot00000000000000 syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el8.te.in000066400000000000000000000001541450431004300247230ustar00rootroot00000000000000require { type syslogd_t, syslogd_exec_t; } allow syslogd_t syslogd_exec_t:file execute_no_trans; syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.el9.te.in000066400000000000000000000001541450431004300247240ustar00rootroot00000000000000require { type syslogd_t, syslogd_exec_t; } allow syslogd_t syslogd_exec_t:file execute_no_trans; syslog-ng-syslog-ng-4.4.0/contrib/selinux/src/syslog_ng.module.version000066400000000000000000000000421450431004300261640ustar00rootroot00000000000000policy_module(syslog_ng, 1.0.10) syslog-ng-syslog-ng-4.4.0/contrib/selinux/syslog_ng.sh000077500000000000000000000212331450431004300230460ustar00rootroot00000000000000#!/bin/bash ### Exit error codes # # 0: everything went fine # 255: invalid command line-option # 254: no root privileges # 253: file or directory does not exist # 252: policy build failed # 251: policy install failed # 250: unsupported os/distribution/version # 249: conflicting parameters # 248: internal error at task selection # 246: syslog-ng not installed # 244: tty not available EL_FC= EL_TE= OS_VERSION= INSTALL_PATH="/opt/syslog-ng" # RHEL8 note: ports 10514/tcp, 10514/udp, 20514/tcp and 20514/udp have been # allowed by default # # Post-RHEL6.5 note: ports 514/udp, 6514/udp and 6514/tcp are allowed by default # if you wish to add further ports, just add them to the end of the list SYSLOG_NG_TCP_PORTS="601" SYSLOG_NG_UDP_PORTS="601" TASK_SELECTED="install_default" INPUT= get_console_tty() { if is_available tty; then CONSOLE_TTY=$( tty ) else echo "The 'tty' binary is not available!" >&2 exit 244 fi } query_install_path() { echo -n "Please enter your installation path for Syslog-ng PE: [${INSTALL_PATH}] " read INPUT <"${CONSOLE_TTY}" } check_dir() { if [ -d "${1}" ]; then return 0 else echo "The directory you specified does not exist!" >&2 return 1 fi } verify_input() { INPUT="${INPUT:-${INSTALL_PATH}}" echo -n "You have entered '${INPUT}'. Is this correct? [y/N] " read ACCEPT <"${CONSOLE_TTY}" if [ "x${ACCEPT}x" != "xyx" ]; then return 0; fi check_dir "${INPUT}" && return 1 || return 0 } is_available () { which "$1" >/dev/null 2>&1; } syslog_ng_is_not_installed() { if is_available syslog-ng; then return 1 elif [ -x "${INSTALL_PATH}/sbin/syslog-ng" ]; then return 1 else return 0 fi } install_precheck() { if syslog_ng_is_not_installed; then echo "Syslog-ng does not seem to be installed!" >&2 exit 246 fi } extract_version_string() { sed -n 's:^[a-zA-Z ]\+\([0-9]\+\.[0-9]\+\)\(.[0-9]\+\)\?[a-zA-Z ()]\+$:\1:p' } detect_os_version() { echo "Detecting RHEL/CentOS/Oracle Linux version..." if [ -x "/usr/bin/lsb_release" ]; then if lsb_release -d | grep -qE "Description:[[:space:]]+(CentOS|Red Hat Enterprise|Oracle|Enterprise Linux Enterprise)( Linux)?( Server)? release"; then OS_VERSION=$( lsb_release -r | cut -f 2 ) else echo "You don't seem to be running a supported Linux distribution!" >&2 exit 250 fi else # The package redhat-lsb-core is most likely not installed... if [ -f "/etc/redhat-release" ]; then OS_VERSION=$( extract_version_string < "/etc/redhat-release" ) else echo "You don't seem to be running a supported OS!" >&2 exit 250 fi fi } omit_allowed_tcp_ports() { sed -e 's:^601::g' } omit_allowed_udp_ports() { sed -e 's:^601::g' } omit_allowed_ports() { SYSLOG_NG_TCP_PORTS=$( omit_allowed_tcp_ports <<<"${SYSLOG_NG_TCP_PORTS}" ) SYSLOG_NG_UDP_PORTS=$( omit_allowed_udp_ports <<<"${SYSLOG_NG_UDP_PORTS}" ) } setup_vars() { echo "Detected RHEL/CentOS/Oracle Linux ${OS_VERSION}." case "${OS_VERSION}" in 5.*) EL_FC="syslog_ng.el5.fc.in" EL_TE="syslog_ng.el5.te.in" ;; 6.*) EL_FC="syslog_ng.el6.fc.in" local MINORVER MINORVER=$( cut -d. -f 2 <<<"${OS_VERSION}" ) if [ "${MINORVER}" -lt 5 ]; then EL_TE="syslog_ng.el6.0to4.te.in" else EL_TE="syslog_ng.el6.5up.te.in" # 601/tcp and 601/udp are allowed by default on RHEL6.5+, so there is no need to enable them omit_allowed_ports fi ;; 7.*) EL_FC="syslog_ng.el789.fc.in" EL_TE="syslog_ng.el7.te.in" # 601/tcp and 601/udp are allowed by default on RHEL7, so there is no need to enable them omit_allowed_ports ;; 8.*) EL_FC="syslog_ng.el789.fc.in" EL_TE="syslog_ng.el8.te.in" # 601/tcp and 601/udp are allowed by default on RHEL8, so there is no need to enable them omit_allowed_ports ;; 9.*) EL_FC="syslog_ng.el789.fc.in" EL_TE="syslog_ng.el9.te.in" # 601/tcp and 601/udp are allowed by default on RHEL9, so there is no need to enable them omit_allowed_ports ;; *) echo "You don't seem to be running a supported version of RHEL!" >&2 exit 250 ;; esac } substitute_install_path() { sed -e "s:^\\\$PATH\\\$:${INSTALL_PATH}:g" "src/root_unsafe/${EL_FC}" sed -e "s:^\\\$PATH\\\$:${INSTALL_PATH}:g" "src/root_safe/${EL_FC}" } omit_install_path() { sed -e "s:^\\\$PATH\\\$::g" "src/root_safe/${EL_FC}" } prepare_files() { echo "Using '${INSTALL_PATH}'..." if [ "${INSTALL_PATH}" != "/" ]; then substitute_install_path > "syslog_ng.fc" else omit_install_path > "syslog_ng.fc" fi cat "src/syslog_ng.module.version" "src/${EL_TE}" > "syslog_ng.te" } remove_trainling_slash() { # the trailing slash in the install path (if present) breaks file context rules # thus it needs to be removed (provided that the install path is not "/" itself) sed -e 's:^\(.\+\)/$:\1:' } filter_bogus_build_output() { #filter misleading output caused by RHEL bug 1861968 fgrep -v /usr/share/selinux/devel/include/services/container.if } build_module() { echo "Building and Loading Policy" build_output=$( make -f /usr/share/selinux/devel/Makefile syslog_ng.pp 2>&1 ) retval=${?} filter_bogus_build_output <<<"${build_output}" [ ${retval} -eq 0 ] || exit 252 } add_ports() { for entry in ${@}; do port=${entry%/*} proto=${entry#*/} semanage port -a -t syslogd_port_t -p ${proto} ${port} 2>/dev/null || \ semanage port -m -t syslogd_port_t -p ${proto} ${port} 2>/dev/null done } install_module() { if /usr/sbin/semodule -l | grep -qw syslog_ng; then echo "The Syslog-ng SELinux policy module is already installed. Nothing to do..." echo "If it belongs to a previous version, then you will have to remove it first." else /usr/sbin/semodule -i syslog_ng.pp -v || exit 251 # set up syslog-ng specific ports PORTS= for port in ${SYSLOG_NG_TCP_PORTS}; do PORTS="${PORTS} ${port}/tcp"; done for port in ${SYSLOG_NG_UDP_PORTS}; do PORTS="${PORTS} ${port}/udp"; done add_ports "${PORTS}" # Fixing the file context /sbin/restorecon -F -Rv "${INSTALL_PATH}" [ -f /etc/init.d/syslog-ng ] && /sbin/restorecon -F -v /etc/init.d/syslog-ng [ -f /etc/rc.d/init.d/syslog-ng ] && /sbin/restorecon -F -v /etc/rc.d/init.d/syslog-ng /sbin/restorecon -F -Rv /dev/log echo -e "\nInstallation of the Syslog-ng SELinux policy module finished.\nPlease restart syslog-ng. You can find more information about this in the README file." fi } remove_ports() { for entry in ${@}; do port=${entry%/*} proto=${entry#*/} semanage port -d -t syslogd_port_t -p ${proto} ${port} 2>/dev/null done } remove_module() { if /usr/sbin/semodule -l | grep -q syslog_ng; then echo -n "Removing Syslog-ng SELinux policy module... " /usr/sbin/semodule --remove=syslog_ng # unconfigure syslog-ng specific ports PORTS= for port in ${SYSLOG_NG_TCP_PORTS}; do PORTS="${PORTS} ${port}/tcp"; done for port in ${SYSLOG_NG_UDP_PORTS}; do PORTS="${PORTS} ${port}/udp"; done remove_ports "${PORTS}" [ -f syslog_ng.pp ] && rm -f syslog_ng.pp [ -f syslog_ng.te ] && rm -f syslog_ng.te [ -f syslog_ng.fc ] && rm -f syslog_ng.fc [ -f syslog_ng.if ] && rm -f syslog_ng.if [ -d tmp ] && rm -Rf tmp echo "done." else echo "No installed Syslog-ng SELinux policy module was found. No removal is necessary. Skipping..." fi } DIRNAME=$( dirname "${0}" ) cd "${DIRNAME}" USAGE="Usage: $0\t[ --install-dir | --remove | --help ]\n\n$0:\tA tool for building and managing the SELinux policy for the\n\t\tdefault syslog-ng installation." while [ -n "${1}" ]; do case "${1}" in --help) # if --help is supplied, the help message will be printed independently of any other options being specified TASK_SELECTED="showhelp" break ;; --install-dir) [ "${TASK_SELECTED}" = "remove" ] && echo -e "ERROR: Conflicting options!\n\n${USAGE}" >&2 && exit 249 TASK_SELECTED="install" check_dir "${2}" || exit 253 INPUT="${2}" shift 2 ;; --remove) [ "${TASK_SELECTED}" = "install" ] && echo -e "ERROR: Conflicting options!\n\n${USAGE}" >&2 && exit 249 TASK_SELECTED="remove" shift ;; *) echo -e "ERROR: Invalid option: '${1}'\n${USAGE}" >&2 exit 255 ;; esac done case "${TASK_SELECTED}" in showhelp) echo -e "${USAGE}" exit 0 ;; remove) detect_os_version setup_vars remove_module exit 0 ;; install|install_default) if [ $( id -u ) != 0 ]; then echo 'You must be root to run this script!' >&2 exit 254 fi get_console_tty if [ -z "${INPUT}" ]; then query_install_path while verify_input; do query_install_path done fi INSTALL_PATH=$( remove_trainling_slash <<<"${INPUT}" ) detect_os_version install_precheck setup_vars prepare_files build_module install_module ;; *) echo -e "ERROR: Invalid task: '${TASK_SELECTED}'!" >&2 exit 248 ;; esac syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/000077500000000000000000000000001450431004300224115ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/solaris10_install.txt000066400000000000000000000120101450431004300265070ustar00rootroot00000000000000Installing syslog-ng on Sun Solaris 10 To successfully install syslog-ng, complete the following simple procedure. Lines starting with # are commands that have to be executed from a command line console. Procedure 4.5. Installing syslog-ng on Sun Solaris 10 1. Use the your username and password received together with your syslog-ng Premium Edition license to download the following binaries. Make sure to download the package specific for the processor architecture of the host. * The syslog-ng Premium Edition package (syslog-ng-premium-edition_) from http://www.balabit.com/downloads/files/syslog-ng/binaries/premium-edition/pool/s/syslog-ng-premium-edition/ * The libdbi8 package from http://www.balabit.com/downloads/files/syslog-ng/binaries/premium-edition/pool/l/libdbi8/ * If you plan to use an SQL destination, download the package corresponding to your database from http://www.balabit.com/downloads/files/syslog-ng/binaries/premium-edition/pool/l/libdbi8-drivers/ Also download the package corresponding to the database, architecture, and Solaris version you plan to use from http://www.sunfreeware.com. The Sunfreeware.com website includes details on installing the database, and any required dependencies. Note The database packages contain the full database applications, but syslog-ng does not use the databases, only the .so file. Installing the database packages does not start the database services. 2. Download or copy the syslog-ng__sparc.pkg.gz package to your computer running Solaris. Download the following packages from the nearest sunfreeware.com mirrors(solaris9 packages): libiconv-1.11-sol9-sparc-local.gz libgcc-3.4.6-sol9-sparc-local.gz 3. Unpack and install the syslog-ng Premium Edition and the libdbi8 package by issuing the following commands from the command line: # libiconv-1.11-sol9-sparc-local.gz # libgcc-3.4.6-sol9-sparc-local.gz # gunzip syslog-ng__sparc.pkg.gz # gunzip libdbi8__.gz # pkgadd -d libiconv-1.11-sol9-sparc-local # pkgadd -d libgcc-3.4.6-sol9-sparc-local # pkgadd -d syslog-ng__sparc.pkg # pkgadd -d libdbi8__.pkg 4. If you use an SQL destination, issue the commands corresponding to the database: * For MySQL: Download and install the following packages from sunfreeware.com: - mysql-5.0.41-sol9-sparc-local - openssl-0.9.8e-sol9-sparc-local # gunzip .gz; pkgadd -d # gunzip libdbd8-mysql__.gz # pkgadd -d libdbd8-mysql__.pkg * For PostgreSQL: Make sure that the SUNWpostgr-libs package has been installed. It's on the Solaris 10 install DVD. # gunzip libdbd8-pgsql__.gz # pkgadd -d libdbd8-pgsql__.pkg * For SQLite: Download and install the sqlite-3.3.6-sol9-sparc-local package from sunfreeware.com. # gunzip sqlite-3.3.6-sol9-sparc-local.gz # pkgadd -d sqlite-3.3.6-sol9-sparc-local # gunzip libdbd8-sqlite__.gz # pkgadd -d libdbd8-sqlite__.pkg 5. Rename the syslog-ng.conf.sample file (located under /opt/syslog-ng/etc/) to syslog-ng.conf. # mv /opt/syslog-ng/etc/syslog-ng.conf.sample \ /opt/syslog-ng/etc/syslog-ng.conf 6. Modify the syslog-ng.conf to suit your needs. For details on how to configure syslog-ng, see The syslog-ng Administrator Guide, Chapter 3, Configuring syslog-ng. 7. Disable the original syslogd application. # svcadm -v disable svc:/system/system-log 8. Copy the following files to their proper places by issuing the following commands and modify them if needed. # cp /contrib/solaris-packaging/syslog-ng.example.xml /var/svc/manifest/system/syslog-ng.xml # cp /contrib/solaris-packaging/syslog-ng.method /lib/svc/method/syslog-ng # cp /contrib/solaris-packaging/syslog-ng@default /etc/default/syslog-ng@default 9. Validate and import the syslog-ng.xml file using svccfg. # svccfg svc:> validate /var/svc/manifest/system/syslog-ng.xml svc:> import /var/svc/manifest/system/syslog-ng.xml svc:> quit 10. Enable and start syslog-ng. # svcadm enable -t svc:/system/syslog-ng:default 11. Verify that syslog-ng is running. # svcs -a | grep syslog You should receive a similar output: online 10:15:01 svc:/system/syslog-ng:default syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/syslog-ng-sol11-smf.example.xml000066400000000000000000000060711450431004300302330ustar00rootroot00000000000000 syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/syslog-ng.example.xml000066400000000000000000000061531450431004300265140ustar00rootroot00000000000000 syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/syslog-ng.method000077500000000000000000000135241450431004300255450ustar00rootroot00000000000000#!/sbin/sh # # $Id: syslog-ng.init.d,v 1.1.2.2 2006/03/02 18:35:45 folti Exp $ # # adapted to syslog-ng by BJ, Aug, 7th 2000 # cleaned up by Bazsi, Oct, 12th 2000 # minor fix by Bojan Zdrnja, Apr, 11th 2003 # added nicer options field # Modified for BalaBit Ltd's syslog-ng package by Tamas Pal Mar, 1st 2006 # Modified for BalaBit's syslog-ng package to make it multi-instance-able by György Pásztor Mar, 21th 2016 # Minor modifications for Syslog-ng OSE by Janos Szigetvari Aug, 15th 2017 . /lib/svc/share/smf_include.sh result=${SMF_EXIT_OK} # Read command line arguments method="$1" # %m instance="$2" # %i # Set defaults; SMF_FMRI should have been set, but just in case. if [ -z "$SMF_FMRI" ]; then SMF_FMRI="svc:/system/syslog-ng:${instance}" fi SYSLOGPID_FILE=/var/run/syslog.pid OTHER_OPTIONS="--enable-core" MAXWAIT=30 DEFAULTFILE=/etc/default/syslog-ng [ -f ${DEFAULTFILE} ] && . ${DEFAULTFILE} [ -f ${DEFAULTFILE}@${instance} ] && . ${DEFAULTFILE}@${instance} SYSLOGNG_PREFIX=${SYSLOGNG_PREFIX:-/usr/local} SYSLOGNG="${SYSLOGNG_PREFIX}/sbin/syslog-ng" if [ "$instance" = "default" ]; then CONFIG_FILE=${CONFIG_FILE:-${SYSLOGNG_PREFIX}/etc/syslog-ng.conf} VAR_DIR=${VAR_DIR:-${SYSLOGNG_PREFIX}/var/lib/syslog-ng} PID_FILE=${PID_FILE:-${SYSLOGPID_FILE}} else CONFIG_FILE=${CONFIG_FILE:-${SYSLOGNG_PREFIX}/etc/syslog-ng@${instance}.conf} VAR_DIR=${VAR_DIR:-${SYSLOGNG_PREFIX}/var/lib/syslog-ng@${instance}} [ -d "${VAR_DIR}" ] || mkdir "${VAR_DIR}" [ -d "${VAR_DIR}/run" ] || mkdir "${VAR_DIR}/run" fi PID_FILE=${PID_FILE:-${VAR_DIR}/run/syslog-ng.pid} PERSIST_FILE=${PERSIST_FILE:-${VAR_DIR}/syslog-ng.persist} CONTROL_FILE=${CONTROL_FILE:-${VAR_DIR}/run/syslog-ng.ctl} METHOD_OPTIONS="--cfgfile=${CONFIG_FILE} --pidfile=${PID_FILE} --persist-file=${PERSIST_FILE} --control=${CONTROL_FILE}" export SYSLOGNG_PREFIX test -x ${SYSLOGNG} || exit $SMF_EXIT_ERR_FATAL test -r ${CONFIG_FILE} || exit $SMF_EXIT_ERR_CONFIG check_syntax() { ${SYSLOGNG} --syntax-only --cfgfile=${CONFIG_FILE} _rval=$? [ $_rval -eq 0 ] || exit $SMF_EXIT_ERR_CONFIG } slng_waitforpid() { _cnt=$MAXWAIT _process=$1 _pid=$2 while [ $_cnt -gt 0 ]; do pgrep $_process | grep $_pid > /dev/null 2>&1 [ $? -ne 0 ] && break _cnt=`expr $_cnt - 1` sleep 1 done return $_cnt } slng_clean_pidfile() { if [ -h $SYSLOGPID_FILE ];then rm -f $SYSLOGPID_FILE fi rm -f $PID_FILE } slng_stop() { # if we have a contract, we should simply use smf_kill_contract to terminate the process contract=`/usr/bin/svcprop -p restarter/contract ${SMF_FMRI}` if [ -n "${contract}" ]; then smf_kill_contract ${contract} TERM 1 $MAXWAIT [ $? -ne 0 ] && exit $SMF_EXIT_ERR_FATAL slng_clean_pidfile return $SMF_EXIT_OK fi [ -f $PID_FILE ] || return $SMF_EXIT_ERR_FATAL syspid=`head -1 $PID_FILE` [ -z "$syspid" ] && return $SMF_EXIT_OK kill -0 $syspid >/dev/null 2>&1 if [ $? -ne 0 ];then return $SMF_EXIT_OK fi kill -TERM $syspid _process=`basename $SYSLOGNG` slng_waitforpid "$_process" $syspid _ret=$? if [ $_ret -eq 0 ]; then kill -KILL $syspid $_ret=$? fi if [ $_ret -eq 0 ] ;then slng_clean_pidfile return $SMF_EXIT_OK fi return $SMF_EXIT_ERR_FATAL } slng_start () { if [ -f $PID_FILE ];then _process=`basename $SYSLOGNG` _pid=`head -1 $PID_FILE` pgrep $_process | grep $_pid > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "syslog-ng already running." exit 1 fi echo "syslog-ng is not running, removing $PID_FILE." /usr/bin/rm -f $PID_FILE fi if [ -f $CONFIG_FILE -a -x $SYSLOGNG ]; then echo 'syslog-ng service starting.' # # Before syslog-ng starts, save any messages from previous # crash dumps so that messages appear in chronological order. # if [ -r /dev/dump ]; then /usr/bin/savecore -m fi if [ -r /etc/dumpadm.conf ]; then . /etc/dumpadm.conf if [ -n "$DUMPADM_DEVICE" ] && [ -r "$DUMPADM_DEVICE" ] && \ [ "x$DUMPADM_DEVICE" != xswap ]; then /usr/bin/savecore -m -f $DUMPADM_DEVICE fi fi check_syntax $SYSLOGNG $OTHER_OPTIONS $METHOD_OPTIONS # remove symlinks if [ -h $SYSLOGPID_FILE ];then rm -f $SYSLOGPID_FILE fi if [ ! -f $SYSLOGPID_FILE ];then ln -s $PID_FILE $SYSLOGPID_FILE fi return $SMF_EXIT_OK fi return $SMF_EXIT_ERR_FATAL } case "$method" in start) slng_start ;; stop) slng_stop ;; refresh) if [ -f $PID_FILE ]; then syspid=`head -1 $PID_FILE` [ "$syspid" -gt 0 ] && kill -1 $syspid && echo "syslog-ng service reloaded" fi ;; restart) slng_stop retval=$? [ $retval -ne 0 ] && exit $retval slng_start ;; *) echo "Usage: $0 { start | stop | restart | refresh }" exit 1 ;; esac exit $? # vim: expandtab ts=8 syslog-ng-syslog-ng-4.4.0/contrib/solaris-packaging/syslog-ng@default000066400000000000000000000004351450431004300257250ustar00rootroot00000000000000SYSLOGNG_PREFIX=/usr/local CONFIG_FILE=/usr/local/etc/syslog-ng.conf VAR_DIR=/usr/local/var/lib/syslog-ng PERSIST_FILE=/usr/local/var/lib/syslog-ng/syslog-ng.persist CONTROL_FILE=/usr/local/var/lib/syslog-ng/run/syslog-ng.ctl PID_FILE=/var/run/syslog.pid OTHER_OPTIONS="--enable-core" syslog-ng-syslog-ng-4.4.0/contrib/syslog-mc000066400000000000000000000135261450431004300206620ustar00rootroot00000000000000#!/usr/bin/perl # # syslog-mc: # This perl script is to be used in conjuction with syslog-ng and it's # multicast feature. # # All you need to do is run the program, pass an IPv4 or IPv6 multicast # address as the first parameter and the script will 'tune in' to the syslog # multicast group and display the syslog lines. # # This helps no end if you want to write local trigger scripts or have a live # view of some daemon without actually having to be logged into the central # syslog server cluster. # # One note to bear in mind is that if you send you logs in the multicast group # to a port number below 1024 then you will need root privileges to run this # script. It's probably a good idea to send your logs to a port number above # 1024 so that you do not need to run things as root. Another recommendation # is to remember to 'seperate' your group addresses by thirty two IP's (for # IPv4) so that you do not receive any unwanted, although it's harmless and # filtered, extra traffic. # # When using the script, you can run it standalone and it will simply print the # syslog messages to STDOUT however you might prefer to pipe it into grep or # some other tool, so to print all the lines containing the word 'cheese': # # $ ./syslog-mc 239.194.253.8 5514 | grep cheese # # -- # Maintained by Alexander Clouter # Written/Copyright 2006 by Alexander Clouter # # This software may be used and distributed according to the terms # of the version two of the GNU General Public License, incorporated herein by # reference. # use strict; use warnings; my $running = 1; use sigtrap 'handler' => sub { $running = 0 }, qw( INT ); # under debian all these dependencies can be met with: # aptitude install libnet-ip-perl libsocket6-perl libio-socket-inet6-perl libparse-syslog-perl use Net::IP; use Socket; use Socket6; use IO::Socket::INET6; # we use IO::Select to avoid the nasty blocking nature of Parse::Syslog use IO::Select; use Parse::Syslog; use POSIX; # enable debugging? use constant DEBUG => 0; if ( DEBUG ) { use Data::Dumper; } my ( $mcGroup, $port ) = ( $ARGV[0], $ARGV[1] ); unless ( $mcGroup ) { print < [port] EOF exit 0; } $mcGroup =~ s/\s*(.+)\s*/$1/; my $ip = Net::IP->new($mcGroup) || die 'First parameter is not a valid IP address'; if ( $ip->version == 4 ) { unless ( Net::IP->new('224.0.0.0/4')->overlaps($ip) != $Net::IP::IP_NO_OVERLAP ) { print STDERR "IPv4 address given is not a multicast address\n"; exit 1; } } elsif ( $ip->version == 6 ) { unless ( Net::IP->new('ff::/120')->overlaps($ip) != $Net::IP::IP_NO_OVERLAP ) { print STDERR "IPv6 address given is not a multicast address\n"; exit 1; } } else { print STDERR "Unknown IP Version\n"; exit 1; } if ( $port ) { $port =~ s/\s*(.+)\s*/$1/; if ( $port =~ /^\d+$/ ) { unless ( $port > 0 && $port < 65536 ) { print STDERR "Invalid port number\n"; exit 1; } } } else { $port = 514; print STDERR "No port number given, assuming 514\n" if ( DEBUG ); } my $sock = &subscribe($mcGroup, $port); unless ( $sock ) { print STDERR "Unable to open socket so bombing out\n"; exit 1; } my $parser = Parse::Syslog->new($sock, arrayref => 1); my $selectPoll = IO::Select->new; $selectPoll->add($sock); while ( $running ) { my ( $select_set ) = IO::Select->select($selectPoll, undef, undef); foreach my $fh ( @$select_set ) { if ( $fh == $sock ) { if ( $sock->eof ) { $running = 0; next; } my $sl = $parser->next; my $timestamp = POSIX::strftime '%b %e %T', gmtime($sl->[0]); my $pid = ( $sl->[3] ) ? $sl->[3] : 'na'; print "$timestamp " . $sl->[1] . ' ' . $sl->[2] . "[$pid]: " . $sl->[4] . "\n"; } } } $selectPoll->remove($sock); &unsubscribe($sock); exit 0; sub subscribe { my $mcGroup = shift; my $port = shift; print STDERR "Trying to join group $mcGroup: " if ( DEBUG ); my @res = getaddrinfo $mcGroup, $port, AF_UNSPEC, SOCK_DGRAM; my $sock = IO::Socket::INET6->new( Domain => $res[0], LocalAddr => $mcGroup, Proto => 'udp', Type => SOCK_DGRAM, LocalPort => $port, ReuseAddr => 1 ) || print STDERR "Can't bind : $@\n"; unless ( $sock && ref $sock eq 'IO::Socket::INET6' ) { print STDERR "Unable to open socket! If using a port number below 1024 you need to be root\n"; return; } my $joinStatus; if ( $sock->sockdomain == AF_INET ) { # struct ip_mreq my $mreq = pack 'a4 a4', inet_pton(AF_INET, $mcGroup), INADDR_ANY; # IP_ADD_MEMBERSHIP = 35 $joinStatus = setsockopt $sock, IPPROTO_IP, 35, $mreq; } elsif ( $sock->sockdomain == AF_INET6 ) { # struct ipv6_mreq my $mreq6 = pack 'a16 N', inet_pton(AF_INET6, $mcGroup), 0; # IPV6_ADD_MEMBERSHIP = 20 $joinStatus = setsockopt $sock, IPPROTO_IPV6, 20, $mreq6; } else { print STDERR "unknown IP version, " if ( DEBUG ); $joinStatus = -1; } if ( $joinStatus == -1 ) { print STDERR "unable to ADD_MEMBERSHIP for $mcGroup\n" if ( DEBUG ); close $sock; return; } print STDERR "successful\n" if ( DEBUG ); return $sock; } sub unsubscribe { my $sock = shift; my $mcGroup = $sock->sockhost; print STDERR "Leaving group $mcGroup: " if ( DEBUG ); my $leaveStatus; if ( $sock->sockdomain == AF_INET ) { my $mreq = pack 'a4 a4', inet_pton(AF_INET, $mcGroup), INADDR_ANY; # IP_DROP_MEMBERSHIP = 36 $leaveStatus = setsockopt $sock, IPPROTO_IP, 36, $mreq; } else { my $mreq6 = pack 'a16 N', inet_pton(AF_INET6, $mcGroup), 0; # IPV6_DROP_MEMBERSHIP = 21 $leaveStatus = setsockopt $sock, IPPROTO_IPV6, 21, $mreq6; } if ( $leaveStatus == -1 ) { print STDERR "warning, unable to DROP_MEMBERSHIP for $mcGroup..." if ( DEBUG ); } close $sock; print STDERR "done\n" if ( DEBUG ); } syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-debun000077500000000000000000001452171450431004300217700ustar00rootroot00000000000000#!/bin/sh #!/bin/bash ### syslog-ng-debun: syslog debug bundle generator ### Written/Copyright: Gyorgy Pasztor , (c) 2014-2016. ### Further enhancements: Janos Szigetvari - jszigetvari at gmail dot com, (c) 2016-2022. ### This software may be used and distributed according to the terms of GNU GPLv2 ### http://www.gnu.org/licenses/gpl-2.0.html unalias -a LANG=en_US LC_ALL=C export LANG LC_ALL version="0.3.20.20220117" ### Check for "local" variable support if type local | grep builtin >/dev/null; then : elif type bash >/dev/null; then exec bash $0 "$@" else printf "No local variable support on this system\n" >&2 exit 1 fi ### ### Global defaults ### Do not overwrite them, parameters or distro / OS specific detections will do that if neccessary ### argv_backup="${@}" engage=0 os="none" dist="none" default_debug_params="-Fedv --enable-core" default_ldebug_params="-Fev" default_pcap_params="port 514 or port 601 or port 53" extras="" sngallpids="" wecpid="" debugpid=none debugtailpid=none pcappid=none tracepids="" ipconfig="ip addr" routeconfig () { netstat -nr ; } netstatnlp () { netstat -nlp ; } netstatlunp () { netstat -lunp ; } netstatpunt () { netstat -punt ; } netstatpn () { netstat -pn ; } netstatsu="netstat -su" binprefix=/opt/syslog-ng absscldirs="/usr/share/syslog-ng/include/scl" relscldirs="share/include/scl share/syslog-ng/include/scl" workdir=/tmp lsof="lsof -p" no_lsof_fallback() { echo "No lsof in path."; } pscmd="ps auxwwwwwf" pseao="ps -eao" cpiopdL="cpio -pdL" findL () { find -L "$@" ; } dfk="df -k" dfh="df -h" dfi="df -i" duks="du -ks" grepq="fgrep -q" lddcmd="ldd" topcmd () { top -b -n 1 -c >"${1}"; } opensslcmd="openssl" sed_equivalent_cmd="sed -Ee" mount=mount varlimit=1000 myplimit () { echo "Plimit query is not supported on this platform" >&3 ; } distpkgoffile () { echo "Package file search is not supported (yet) on this platform" >&3 ; } distpkgstatus () { echo "Package status query is not (yet) supported on this platform" >&3 ; } selftar="tar cf - ." gzipcmd="gzip -9" showdep="dpkg -S" pcapifparm=-i w=w vmstat=vmstat dmesg=dmesg timestamp () { date +%s ; } tcpdumpcmd="tcpdump" tcpdumpopts="-p -s 1500 -w" opensslmajor=0 getsyslogpids () { pidof syslog-ng ; } os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -print0 | xargs -0 md5sum ; } dfk_parser () { tail -1 | while read FS ALL USED AVAIL UPERC MP; do if echo ${AVAIL} | ${grepq} '%'; then echo ${USED} ; else echo ${AVAIL} ; fi done ; } trace="strace -s256 -ff -ttT -f" initfile="/etc/init.d/syslog-ng" service_stop="${initfile} stop" service_start="${initfile} start" service_status="${initfile} status" #checkpid () { [ -d /proc/"$1" ]; } #some old Unix versions did not have procfs, and kill -0 allows to check whether a PID exists #for reference: http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html checkpid () { [ -n "$1" ] && kill -0 "$1" 2>/dev/null ; } #mywait () { jobs -p >${tmpdir}/sdn.jobs ; for i in `grep -v "\<$tailpid\>" ${tmpdir}/sdn.jobs` ; do wait $i ; done ; } mywait () { jobs -p >${tmpdir}/sdn.jobs ; for i in $( grep -v "^$tailpid\$" ${tmpdir}/sdn.jobs ) ; do wait $i ; done ; } is_available () { which "$1" >/dev/null 2>&1; } distpkgoffile_cleanup () { : ; } ### ### Show Usage ### debun_usage () { cat <&2 ; exit 1 ; } [ -z "$tmpdir" ] && { printf "Could not create a temp directory\n" >&2 ; exit 1 ; } # Start redirections #exec 3>&1 >${tmpdir}/syslog-ng.debun.txt 2>${tmpdir}/syslog-ng.debun.txt exec 3>&1 >${tmpdir}/syslog-ng.debun.txt 2>&1 echo "Syslog-NG DEBUg buNdle generator" sync while [ ! -f ${tmpdir}/syslog-ng.debun.txt ] ; do sleep 1 ; done #nohup tail -f ${tmpdir}/syslog-ng.debun.txt >&3 & tail -f ${tmpdir}/syslog-ng.debun.txt >&3 & tailpid=$! #disown } debun_finish_debug () { if [ -n "$debug_mode" ]; then printf 'Generating second batch of statistics\n' acquire_syslog_stats fi if [ "${debugpid}" != "none" ]; then if checkpid ${debugpid} ; then kill -INT $debugpid checkpid ${debugpid} && sleep 1 checkpid ${debugpid} && kill -9 $debugpid checkpid ${debugpid} && sleep 1 checkpid ${debugpid} && echo "I gave up... debugger pid doesn't die" fi printf 'Debugpid: "%s"\n' "${debugpid}" ( exec 3>&- ; $service_start ; ) fi if checkpid ${debugtailpid} ; then kill $debugtailpid fi if checkpid ${pcappid} ; then kill -INT $pcappid fi if [ -n "$tracing" ]; then for i in ${tracepids} ; do checkpid $i && kill -INT $i done sleep 2 for i in ${tracepids} ; do checkpid $i && kill -9 $i 2>/dev/null done fi mywait } debun_do_tarball () { cd ${tmpdir} touch ${tmpdir}.tgz chmod 600 ${tmpdir}.tgz ${selftar} | ${gzipcmd} >${tmpdir}.tgz cd .. rm -r "${tmpdir}" printf "Terminating live message watcher: " sync kill ${tailpid} sync sleep 1 } debun_generate_hashes () { cd ${tmpdir} os_hash_helper > debun.manifest } debun_final() { debun_finish_debug [ -n "$service_status" ] && $service_status >${tmpdir}/svc.post # Generating stats again for the EPS counter if [ -z "$debug_mode" ]; then printf 'Generating second batch of statistics\n' acquire_syslog_stats fi printf "\nGenerating hashes..." debun_generate_hashes printf " done.\nDebug Bundle generation: Done.\n" exec >&3 2>&1 debun_do_tarball printf "\n\nYour debug bundle will be stored at %s.tgz\n" "$tmpdir" } add_extra () { extras="${extras}${extras:+ }$@" } ### ###PROCESS HANDLING FUNCTIONS ### getparent () { local self local parent local ret local tmpfile=${tmpdir}/getparent.$$.txt $pseao pid,ppid >$tmpfile # Default value, learned after getchilds()'s forkbomb case unset ret while read self parent ; do [ "$1" = "$self" ] || continue ret=$parent done < $tmpfile rm $tmpfile echo $ret } getchilds () { local childs local dummy local child local tmpfile=${tmpdir}/getchilds.$$.txt $pseao ppid,pid >$tmpfile # Need to initialize it with a default value, since dash allows to inherit the caller's value, even if it's a local variable unset childs while read dummy child ; do [ "$1" = "$dummy" ] || continue childs="${childs}${childs:+ }$child" done < $tmpfile rm $tmpfile echo ${childs} } getallchilds () { local childs local subchilds childs=$( getchilds ${1} ) local i # Default value, learned after getchilds()'s forkbomb case unset subchilds for i in ${childs} ; do subchilds="${subchilds}${subchilds:+ }$(getallchilds $i)" done echo ${childs} ${subchilds} } acquire_debun_info () { pwd > ${tmpdir}/debun.pwd echo "${0} ${argv_backup}" > ${tmpdir}/debun.argv echo "${version}" > ${tmpdir}/debun.version id > ${tmpdir}/debun.runas echo $PATH > ${tmpdir}/debun.path } acquire_system_info () { printf "System's full uname: " uname -a | tee "${tmpdir}/sys.uname" free >${tmpdir}/sys.free vmstat >${tmpdir}/sys.vmstat topcmd "${tmpdir}/sys.top" if is_available ${opensslcmd}; then ${opensslcmd} version >${tmpdir}/sys.openssl.version fi if is_available java; then java -version >${tmpdir}/sys.java.version 2>&1 fi } acquire_network_info () { printf "Getting network-interface information: " if $ipconfig >${tmpdir}/net.ip ; then printf "Success\n" else printf "Failed\n" fi printf "Getting network routes: " if routeconfig >${tmpdir}/net.route ; then printf "Success\n" else printf "Failed\n" fi printf "Getting DNS resolution-related information: " [ -f /etc/nsswitch.conf ] && cp /etc/nsswitch.conf ${tmpdir}/sys.nsswitch.conf [ -f /etc/resolv.conf ] && cp /etc/resolv.conf ${tmpdir}/sys.resolv.conf [ -f /etc/hosts ] && cp /etc/hosts ${tmpdir}/sys.hosts printf "Done\n" } acquire_system_process_info () { echo "List all processes" $pscmd >${tmpdir}/sys.ps } acquire_filesystem_info () { echo "Mount and disk free info collection" $dfk >${tmpdir}/sys.df_k $dfh >${tmpdir}/sys.df_h $dfi >${tmpdir}/sys.df_i 2>/dev/null $mount >${tmpdir}/sys.mount } acquire_system_other_info () { $w >${tmpdir}/sys.w $dmesg >${tmpdir}/sys.dmesg netstatnlp >${tmpdir}/sys.netstat.ltn netstatlunp >${tmpdir}/sys.netstat.lunp netstatpunt >${tmpdir}/sys.netstat.est netstatpn >${tmpdir}/sys.netstat.pn $netstatsu >${tmpdir}/sys.netstat.su [ -f /proc/net/udp ] && cp /proc/net/udp ${tmpdir}/sys.proc.net.udp } ### Here comes the general info acquiring parts acquire_general_info () { printf "\nStart general info collection\n" acquire_debun_info acquire_system_info [ -n "$privacy_mode" ] && return acquire_network_info acquire_system_process_info acquire_filesystem_info acquire_system_other_info } pki_is_certificate () { grep "BEGIN CERTIFICATE" "${1}" 2>/dev/null | ${grepq} -v "REQUEST" } pki_count_certificates () { grep -c "BEGIN CERTIFICATE" "${1}" 2>/dev/null } pki_is_private_key () { ${grepq} "PRIVATE KEY" "${1}" 2>/dev/null } pki_is_public_key () { ${grepq} "PUBLIC KEY" "${1}" 2>/dev/null } pki_is_rsa () { ${grepq} "RSA " "${1}" 2>/dev/null } pki_is_dsa () { ${grepq} "DSA " "${1}" 2>/dev/null } pki_is_ecdsa () { ${grepq} " EC " "${1}" 2>/dev/null } pki_is_encrypted () { if ${grepq} "ENCRYPTED" "${1}"; then return 0 else local buffer_error buffer_error=$( ${opensslcmd} rsa -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "problems getting password"; then return 0 else return 1 fi fi } pki_parse_public_key () { oneline_cert=$( tr -d '\n' | tr -d ' ' ) [ -z "${oneline_cert}" ] && printf "NO_PUBLIC_KEY_COULD_BE_EXTRACTED;" && return if echo "${oneline_cert}" | $grepq "UnabletoloadPublicKey"; then printf "OPENSSL_TOO_OLD|NO_ECDSA_SUPPORT_IN_OPENSSL;" else if echo "${oneline_cert}" | $grepq "PublicKey:X509v3extensions"; then printf "NO_PUBLIC_KEY_COULD_BE_EXTRACTED;" else echo "${oneline_cert}" | ${sed_equivalent_cmd} 's/^.*(Modulus|modulus|pub)(\([0-9]+bit\))?:([a-f0-9:]+).*$/Public Key=\3;/' fi fi } pki_guess_certificate () { local header fsize buffer_pubkey buffer_rest hashopts hashnum fsize=$( wc -c "${1}" | ${sed_equivalent_cmd} 's:^ *([0-9]+) .*$:\1:' ) if [ ${opensslmajor} -gt 0 ]; then hashopts="-subject_hash -subject_hash_old" hashnum="2;" else hashopts="-hash" hashnum="1;" fi certcount=$( pki_count_certificates "${1}" ) [ "${certcount}" -gt 1 ] && header="STACKED_CERTIFICATE(${certcount});${1};" || header="CERTIFICATE;${1};" buffer_pubkey=$( ${opensslcmd} x509 -in "${1}" -text -noout 2>/dev/null | pki_parse_public_key ) buffer_rest=$( ${opensslcmd} x509 -in "${1}" -noout ${hashopts} -serial -dates -fingerprint -subject -issuer | tr '\n' ';' ) printf "${header}${fsize};${buffer_pubkey}${hashnum}${buffer_rest}" } pki_guess_private_key () { local header fsize buffer_pubkey buffer_error fsize=$( wc -c "${1}" | ${sed_equivalent_cmd} 's:^ *([0-9]+) .*$:\1:' ) if pki_is_encrypted "${1}"; then header="PRIVATE_ENCRYPTED;${1};" else if pki_is_rsa "${1}"; then header="PRIVATE_RSA;${1};" buffer_pubkey=$( ${opensslcmd} rsa -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) elif pki_is_dsa "${1}"; then header="PRIVATE_DSA;${1};" buffer_pubkey=$( ${opensslcmd} dsa -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) elif pki_is_ecdsa "${1}"; then header="PRIVATE_EC;${1};" buffer_error=$( ${opensslcmd} ec -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "'ec' is an invalid command"; then buffer_pubkey="NO_ECDSA_SUPPORT_IN_OPENSSL;" elif echo "${buffer_error}" | $grepq "unable to load"; then buffer_pubkey="OPENSSL_TOO_OLD;" else buffer_pubkey=$( ${opensslcmd} ec -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) fi else header="UNKNOWN_PRIVATE;${1};" buffer_pubkey=";" fi fi printf "${header}${fsize};${buffer_pubkey}" } pki_guess_public_key () { # Public keys do not have their type in the PEM header/footer local header fsize buffer_pubkey buffer_error header="PUBLIC;${1};" fsize=$( wc -c "${1}" | ${sed_equivalent_cmd} 's:^ *([0-9]+) .*$:\1:' ) if [ ${opensslmajor} -gt 0 ]; then buffer_error=$( ${opensslcmd} pkey -pubin -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "unable to load"; then header="UNKNOWN_PUBLIC;${1};" buffer_pubkey="OPENSSL_TOO_OLD|NO_ECDSA_SUPPORT_IN_OPENSSL;" else buffer_pubkey=$( ${opensslcmd} pkey -pubin -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) fi else buffer_error=$( ${opensslcmd} rsa -pubin -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "expecting an rsa key"; then buffer_error=$( ${opensslcmd} dsa -pubin -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "expecting a dsa key"; then buffer_error=$( ${opensslcmd} ec -pubin -in "${1}" -noout -text 2>&1 >/dev/null ) if echo "${buffer_error}" | ${grepq} "expecting a ec key"; then header="UNKNOWN_PUBLIC;${1};" buffer_pubkey=";" elif echo "${buffer_error}" | ${grepq} "'ec' is an invalid command"; then header="UNKNOWN_PUBLIC;${1};" buffer_pubkey="NO_ECDSA_SUPPORT_IN_OPENSSL;" else buffer_pubkey=$( ${opensslcmd} ec -pubin -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) fi else buffer_pubkey=$( ${opensslcmd} dsa -pubin -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) fi elif echo "${buffer_error}" | ${grepq} "unable to load"; then header="UNKNOWN_PUBLIC;${1};" buffer_pubkey="OPENSSL_TOO_OLD|NO_ECDSA_SUPPORT_IN_OPENSSL;" else buffer_pubkey=$( ${opensslcmd} rsa -pubin -in "${1}" -noout -text 2>/dev/null | pki_parse_public_key ) fi fi printf "${header}${fsize};${buffer_pubkey}" } pki_other_file () { local fsize fsize=$( wc -c "${1}" | ${sed_equivalent_cmd} 's:^ *([0-9]+) .*$:\1:' ) printf "OTHER_FILE;${1};${fsize};" } pki_process_file () { local output_buffer if pki_is_certificate "${1}"; then output_buffer=$( pki_guess_certificate "${1}" ) else if pki_is_private_key "${1}"; then output_buffer=$( pki_guess_private_key "${1}" ) elif pki_is_public_key "${1}"; then output_buffer=$( pki_guess_public_key "${1}" ) else output_buffer=$( pki_other_file "${1}" ) fi fi echo "${output_buffer}" } acquire_syslog_pki_info () { printf "Gathering PKI information... " if is_available ${opensslcmd}; then local OPENSSL OPENSSLVER OPENSSLDAY OPENSSLMONTH OPENSSLYEAR REST read OPENSSL OPENSSLVER OPENSSLDAY OPENSSLMONTH OPENSSLYEAR REST <${tmpdir}/sys.openssl.version opensslmajor=${OPENSSLVER%%.*} cd "${confdir}" findL . -name '*.0' -o -name '*.1' -o -name '*.key' -o -name '*.crt' -o -name '*.pem' >${tmpdir}/syslog.etc.pki.files 2>/dev/null while read FILE; do pki_process_file "${FILE}" >>${tmpdir}/syslog.etc.pki.info.csv done <${tmpdir}/syslog.etc.pki.files printf "done.\n" else printf "no openssl found in PATH.\n" fi } remove_passwords_from_file () { # # Double quotes are used because escaping single quotes within a single quoted string is ugly. # [ \t\r\n\v\f] class is used for matching whitespaces, because \s is unavailable. # The goal is matching substrings that look like this, to replace the password string, and preserve original formatting: # password ( 'password-string' ) --> password ( '___PASSWORD_REMOVED___' ) ### ${sed_equivalent_cmd} "s|password([ \t\r\n\v\f]*)\(([ \t\r\n\v\f]*)([\"']?)[^)\"']+\3([ \t\r\n\v\f]*)\)|password\1(\2\3___PASSWORD_REMOVED___\3\4)|g" <"${1}" | \ ${sed_equivalent_cmd} "s|token([ \t\r\n\v\f]*)\(([ \t\r\n\v\f]*)([\"']?)[^)\"']+\3([ \t\r\n\v\f]*)\)|token\1(\2\3___AUTH_TOKEN_REMOVED___\3\4)|g" | \ ${sed_equivalent_cmd} "s|Authorization: [^\"']+|Authorization: ___AUTH_TOKEN_REMOVED___|g" >"${1}.bak" [ -s "${1}.bak" ] && mv "${1}.bak" "${1}" } acquire_syslog_config () { echo "Copy configuration files from $confdir" cd "${confdir}" mkdir ${tmpdir}/config findL . > ${tmpdir}/syslog.etc.files touch ${tmpdir}/syslog.etc.files.removed if [ -z "$saveprivatekeys" ]; then grep '\.key$' ${tmpdir}/syslog.etc.files >> ${tmpdir}/syslog.etc.files.removed grep '\.jks$' ${tmpdir}/syslog.etc.files >> ${tmpdir}/syslog.etc.files.removed grep '\.keytab$' ${tmpdir}/syslog.etc.files >> ${tmpdir}/syslog.etc.files.removed grep -v '\.key$' ${tmpdir}/syslog.etc.files | grep -v '\.jks$' | grep -v '\.keytab$' | \ while read FILE; do \ if pki_is_private_key "${FILE}" 2>/dev/null; then echo "${FILE}" >> ${tmpdir}/syslog.etc.files.removed else echo "${FILE}" fi done > ${tmpdir}/syslog.etc.files.saved else cp ${tmpdir}/syslog.etc.files ${tmpdir}/syslog.etc.files.saved fi $cpiopdL ${tmpdir}/config < ${tmpdir}/syslog.etc.files.saved findL ${tmpdir}/config -name "*.conf*" | \ while read FILE; do \ remove_passwords_from_file "${FILE}" done echo "Copy SCL configuration files" mkdir ${tmpdir}/scl for dir in ${absscldirs}; do if [ -d "${dir}" ]; then cd "${dir}" local dirname=$( echo "${dir}" | ${sed_equivalent_cmd} 's/\//_/g' ) mkdir "${tmpdir}/scl/${dirname}" findL . | $cpiopdL "${tmpdir}/scl/${dirname}" fi done for dir in ${relscldirs}; do if [ -d "${binprefix}/${dir}" ]; then cd "${binprefix}/${dir}" local dirname=$( echo "${binprefix}/${dir}" | ${sed_equivalent_cmd} 's/\//_/g' ) mkdir "${tmpdir}/scl/${dirname}" findL . | $cpiopdL "${tmpdir}/scl/${dirname}" fi done } acquire_syslog_pids () { echo 'Old "getsyslogpids":' >${tmpdir}/syslog.pids getsyslogpids >>${tmpdir}/syslog.pids if [ -r "${piddir}/syslog-ng.pid" ]; then sngpid=$( cat ${piddir}/syslog-ng.pid ) else # Handle when fhs is "linux"-like sngpid=$( $pseao pid,args | grep "[s]yslog-ng " | head -1 | while read PID CMD; do echo $PID; done ) fi ppid=$( getparent $sngpid ) sngallpids="$( getallchilds $sngpid )" echo "SVpid: $ppid SNGpid: $sngpid Chpids: ${sngallpids}" >>${tmpdir}/syslog.pids tail -1 ${tmpdir}/syslog.pids if [ -n "$ppid" ]; then sngallpids="$ppid $sngpid ${sngallpids}" else sngallpids="$( getsyslogpids )" fi # drop out the unneeded white spaces, since that disturb the ps command sngallpids=$( echo ${sngallpids} ) if [ -n "${sngallpids}" ]; then printf 'ps -l -f -p "%s"\n' "${sngallpids}" >>${tmpdir}/syslog.pids ps -l -f -p "${sngallpids}" >>${tmpdir}/syslog.pids fi wecpid=$( $pseao pid,args | grep "[w]ec " | while read PID CMD; do echo $PID; done ) [ -n "$wecpid" ] && echo $wecpid >${tmpdir}/wec.pid || echo "No wec was found running." >${tmpdir}/wec.pid [ -n "$service_status" ] && $service_status >${tmpdir}/svc.pre } acquire_syslog_stats () { local tsdata tsdata=$( timestamp ) #handy-dandy delay magic, triggered when we'd step on our own foot [ -f ${tmpdir}/syslog.stats.${tsdata} ] && sleep 5 && tsdata=$( timestamp ) ${syslogngctlbin} stats > ${tmpdir}/syslog.stats.${tsdata} 2>&1 echo ${syslogngctlbin} stats tsdata=$( timestamp ) ${syslogngctlbin} query get "*" > ${tmpdir}/syslog.query.all.${tsdata} 2>/dev/null echo ${syslogngctlbin} query get "*" if [ -x ${syslogngquerybin} ]; then #if we reach this brach, then syslog.query.all - as generated above - will not contain any meaningful data rm ${tmpdir}/syslog.query.all.${tsdata} tsdata=$( timestamp ) ${syslogngquerybin} sum "*" > ${tmpdir}/syslog.query.all.${tsdata} 2>/dev/null echo ${syslogngquerybin} sum "*" fi } acquire_syslog_info () { ls -la "${binprefix}" > ${tmpdir}/syslog.lsl.install_dir 2>&1 printf "Syslog-ng's exact version: " $syslogbin --version > ${tmpdir}/syslog.version head -1 ${tmpdir}/syslog.version [ -x ${binprefix}/sbin/wec ] && ${binprefix}/sbin/wec -v 2>&1 > ${tmpdir}/wec.version if [ -z "$debug_mode" ]; then acquire_syslog_stats fi if ${syslogngctlbin} show-license-info > ${tmpdir}/syslog.license-usage 2>&1; then ${syslogngctlbin} show-license-info --json > ${tmpdir}/syslog.license-usage.json 2>/dev/null fi echo ${syslogngctlbin} show-license-info ${syslogngctlbin} credentials status > ${tmpdir}/syslog.credentials.status 2>&1 echo ${syslogngctlbin} credentials status for i in ${sngallpids} ; do is_available ${lsof%% *} && $lsof $i >${tmpdir}/syslog.$i.lsof 2>/dev/null || no_lsof_fallback $i >${tmpdir}/syslog.$i.lsof myplimit $i >${tmpdir}/syslog.$i.limits done if [ -n "$wecpid" ]; then while read i; do is_available ${lsof%% *} && $lsof $i >${tmpdir}/wec.$i.lsof || no_lsof_fallback $i >${tmpdir}/wec.$i.lsof done < ${tmpdir}/wec.pid fi $syslogbin -s --preprocess-into "${tmpdir}/syslog.pp.conf" [ -f "${tmpdir}/syslog.pp.conf" ] && remove_passwords_from_file "${tmpdir}/syslog.pp.conf" } acquire_syslog_var () { ls -laR "${vardir}" >${tmpdir}/syslog.lslR.var 2>&1 $duks "${vardir}/" >${tmpdir}/syslog.duks.var read vardu dir <${tmpdir}/syslog.duks.var mkdir ${tmpdir}/var cd "${vardir}" freek_tmp=$( ${dfk} ${tmpdir} | dfk_parser ) # # low disk-space => only copy the persist file and the pid file ### if [ "${freek_tmp}" -gt "${vardu}" ] ; then if [ "$vardu" -lt "$varlimit" ] ; then findL . | grep -v run\\/syslog-ng.ctl$ | $cpiopdL ${tmpdir}/var else printf "Size of ${vardir} is larger than $varlimit kilobytes.\n" printf "Do you really want to copy all of its contents? Type 'YES' with all capitals: " read ans if [ "$ans" = "YES" ]; then findL . | grep -v "syslog-ng*\.ctl" | $cpiopdL ${tmpdir}/var else printf "Only copying most important files on user request.\n" findL . \( -name "*.persist" -o -name "*.state" -o -name "*.pid" -o -path "*/reports/*" \) | grep -v "syslog-ng.*\.ctl" | $cpiopdL ${tmpdir}/var fi fi else printf "TOO LOW free disk space on the filesystem holding ${tmpdir}\n" printf "to create a full copy of ${vardir}!\nOnly copying most important files.\n" findL . \( -name "*.persist" -o -name "*.state" -o -name "*.pid" -o -path "*/reports/*" \) | grep -v "syslog-ng.*\.ctl" | $cpiopdL ${tmpdir}/var fi } format_ldd_output () { while read x ; do # libsyslog-ng-5.0.5.so => /opt/syslog-ng/lib/libsyslog-ng-5.0.5.so (0x00007f9b42990000) #/opt/syslog-ng/lib/libsyslog-ng-5.0.5.so (0x00007f9b42990000) x="/${x#*/}" #/opt/syslog-ng/lib/libsyslog-ng-6.0.2.so (0x00007f034c8c0000) #/opt/syslog-ng/lib/libsyslog-ng-6.0.2.so x="${x%% (*}" #AIX: #/opt/syslog-ng/lib/libsyslog-ng.a(libsyslog-ng-5.0.14.so) #/opt/syslog-ng/lib/libsyslog-ng.a x="${x%%(*}" [ "${x}" != "/ " ] && [ -f "${x}" ] && echo "$x" done } acquire_syslog_ldinfo () { $lddcmd $syslogrealbin |grep -v needs >${tmpdir}/syslog.ldd format_ldd_output <${tmpdir}/syslog.ldd >${tmpdir}/syslog.ldfiles for i in $( cat ${tmpdir}/syslog.ldfiles ) ; do distpkgoffile $i >>${tmpdir}/syslog.ldpkg done distpkgoffile_cleanup sort <${tmpdir}/syslog.ldpkg | uniq >${tmpdir}/syslog.ldpkg.u mv ${tmpdir}/syslog.ldpkg.u ${tmpdir}/syslog.ldpkg for i in $( cat ${tmpdir}/syslog.ldpkg ) ; do distpkgstatus $i >>${tmpdir}/syslog.ldinfos done } acquire_syslog_startup_method () { printf "Detecting init system: " if [ -d "/run/systemd/system" ]; then acquire_syslog_startup_systemdunit elif [ -d "/lib/svc/method" ]; then acquire_syslog_startup_smf else acquire_syslog_startup_initscript fi for i in /etc/default/syslog-ng* ; do [ -f "${i}" ] && cp "${i}" "${tmpdir}/sys.startup.default.${i##*/}" done for i in /etc/sysconfig/syslog-ng* ; do [ -f "${i}" ] && cp "${i}" "${tmpdir}/sys.startup.sysconfig.${i##*/}" done } acquire_syslog_startup_initscript () { if [ -n "${initfile}" ]; then printf "falling back to SystemV init style...\n" cp "${initfile}" "${tmpdir}/sys.startup.init.syslog-ng" chmod 0660 "${tmpdir}/sys.startup.init.syslog-ng" else printf "none.\n" fi } acquire_syslog_startup_systemdunit () { printf "systemd detected...\n" systemctl list-units --type=service --plain --no-legend --no-pager --all | grep syslog | grep -vE '(not-found|masked)' | tee "${tmpdir}/sys.startup.systemd-instances" | \ while read SERVICE LOAD ACTIVE SUB DESCRIPTION ; do output_buffer=$( systemctl show -p FragmentPath ${SERVICE} ) ; echo "${output_buffer##FragmentPath=}" ; done | \ while read UNITFILE; do SUFFIX=$( echo "${UNITFILE}" | tr / . ); cp "${UNITFILE}" "${tmpdir}/sys.startup.systemd-service${SUFFIX}" ; done } acquire_syslog_startup_smf () { printf "Solaris SMF detected...\n" cp "/lib/svc/method/syslog-ng" "${tmpdir}/sys.startup.svc-method.syslog-ng" chmod 0660 "${tmpdir}/sys.startup.svc-method.syslog-ng" cp "/var/svc/manifest/system/syslog-ng.xml" "${tmpdir}/sys.startup.svc-manifest.syslog-ng.xml" svcs -H system/syslog* >"${tmpdir}/sys.startup.svc-instances" } acquire_syslog_all () { printf "\nStart Syslog-specific info collection\n" acquire_syslog_config acquire_running_syslog_config acquire_syslog_pki_info acquire_syslog_pids acquire_syslog_info acquire_syslog_var acquire_syslog_ldinfo acquire_syslog_startup_method } acquire_syslog_nprv () { printf "\nStart Syslog-specific info collection (light)\n" acquire_running_syslog_config acquire_syslog_pids acquire_syslog_info acquire_syslog_ldinfo acquire_syslog_startup_method } acquire_running_syslog_config() { if ${syslogngctlbin} config >/dev/null 2>&1; then ${syslogngctlbin} config -p > "${tmpdir}/syslog-ng.ctl.running.conf" 2>&1 [ -z "$saveprivatekeys" ] && remove_passwords_from_file "${tmpdir}/syslog-ng.ctl.running.conf" fi } fhs_set_linux () { confdir=/etc/syslog-ng vardir=/var/lib/syslog-ng piddir=/var/lib/syslog-ng syslogbin=/usr/sbin/syslog-ng syslogngctlbin=/usr/sbin/syslog-ng-ctl syslogngquerybin=/usr/sbin/syslog-ng-query syslogrealbin=/usr/sbin/syslog-ng } fhs_set_unix () { : } rpm_verify () { local found=0 for pkg in "${@}"; do if rpm -q "${pkg}" ; then rpm -V "${pkg}" && echo "${pkg}: Package files are intact" ((found+=1)) fi done [ ${found} -eq 0 ] && return 1 || return 0 } ### Here comes the linux & distro specific parts debun_extra_debian () { printf "\nDebian specific checks\n" printf "Check package files integrity\n" cd / for package in $(dpkg -l syslog-ng\* | grep "ii" | awk -F " " '{print $2}') do dpkg --verify ${package} && printf "Package ${package} files are intact\n" done printf "list syslog-related packages\n" dpkg -l |grep syslog > ${tmpdir}/deb.packages } debun_extra_redhat () { printf "\nRedhat specific checks\n" printf "Check package files integrity\n" rpm_verify syslog-ng-premium-edition syslog-ng-premium-edition-client syslog-ng-premium-edition-compact || \ printf "No syslog-ng RPM packages have been found!\n" printf "list syslog-related packages\n" rpm -qa |grep syslog > ${tmpdir}/rpm.packages } debun_extra_slackware () { printf "\nSlackware Linux specific checks\n" printf "list syslog-related packages\n" find /var/log/packages -name "*sys*log*" | while read -r FILE; do echo "${FILE##*/}"; done > ${tmpdir}/pkg.packages } debun_extra_suse() { printf "\nSuSE specific checks\n" printf "Check package files integrity\n" rpm_verify syslog-ng-premium-edition syslog-ng-premium-edition-client syslog-ng-premium-edition-compact || \ printf "No syslog-ng RPM packages have been found!\n" printf "list syslog-related packages\n" rpm -qa | grep syslog > ${tmpdir}/rpm.packages #on opensuse "ss utility, iproute2-ss071016" crashes when run with the -punt CLI options if is_available netstat; then #this info should only be collected if the user has not requested privacy mode #we value our customer's sense of privacy if [ -z "$privacy_mode" ]; then netstat -punt >${tmpdir}/sys.netstat.est.noss netstat -pn >${tmpdir}/sys.netstat.pn.noss fi fi } debun_extra_genlinux () { if is_available getenforce; then getenforce >"${tmpdir}/sys.selinux" if ${grepq} Enforcing "${tmpdir}/sys.selinux"; then echo "SELinux is in Enforcing mode! If you encounter any problems with debug bundle collection, consider temporarily switching to Permissive mode!" fi ${pscmd}Z >"${tmpdir}/sys.ps.selinux" semodule -l >"${tmpdir}/sys.selinux.modules" else echo "No getenforce in path." >"${tmpdir}/sys.selinux" fi if is_available sysstat ; then sysstat -P ALL 1 5 >${tmpdir}/sys.sar.cpu sysstat -d 1 5 >${tmpdir}/sys.sar.disk elif is_available sar ; then sar -P ALL 1 5 >${tmpdir}/sys.sar.cpu sar -d 1 5 >${tmpdir}/sys.sar.disk fi if is_available top; then top -b -H -n 1 -c >${tmpdir}/sys.top.threads fi [ -n "$privacy_mode" ] && return if is_available dmidecode; then dmidecode >"${tmpdir}/sys.dmidecode" fi if is_available lspci; then lspci >"${tmpdir}/sys.lspci" else echo "No lspci in path." >"${tmpdir}/sys.lspci" fi sysctl -a >"${tmpdir}/sys.sysctl.all" 2>/dev/null cp /proc/cpuinfo "${tmpdir}/sys.cpuinfo" } debun_linux () { case "${dist}" in "Debian"|"Ubuntu") add_extra debun_extra_debian ;; "CentOS"|"RedHatEnterprise"|"RedHatEnterpriseServer"|"RHEL"|"OracleServer"|"EnterpriseEnterpriseServer") add_extra debun_extra_redhat ;; "SUSE LINUX") add_extra debun_extra_suse ;; "Slackware") add_extra debun_extra_slackware ;; *) echo "Unknown Distro, perhaps unsupported" ;; esac add_extra debun_extra_genlinux } debun_extra_gensolaris () { sysdef >${tmpdir}/sys.sysdef kstat >${tmpdir}/sys.kstat cp /etc/release ${tmpdir}/sys.release if is_available showrev ; then showrev >${tmpdir}/sys.showrev fi if is_available sar ; then sar -u 1 5 >${tmpdir}/sys.sar.cpu sar -d 1 5 >${tmpdir}/sys.sar.disk fi if is_available top; then top -b -t -n 1 -c >${tmpdir}/sys.top.threads fi [ -x "/usr/platform/$( uname -i )/sbin/prtdiag" ] && /usr/platform/$(uname -i)/sbin/prtdiag -v &>${tmpdir}/sys.prtdiag } ### Here comes solaris specific parts debun_solaris () { add_extra debun_extra_gensolaris pkginfo | grep -i syslog > ${tmpdir}/pkg.packages } debun_extra_freebsd() { if is_available top; then top -b -d1 -H >${tmpdir}/sys.top.threads fi } debun_freebsd() { add_extra debun_extra_freebsd } debun_extra_hpux () { sysdef >${tmpdir}/sys.sysdef swlist >${tmpdir}/sys.swlist if is_available sar ; then sar -u 1 5 >${tmpdir}/sys.sar.cpu sar -d 1 5 >${tmpdir}/sys.sar.disk fi } debun_hpux () { add_extra debun_extra_hpux } debun_extra_aix () { alog -o -t console >${tmpdir}/sys.console-log oslevel -s >${tmpdir}/sys.aix.oslevel-s oslevel -sq >${tmpdir}/sys.aix.oslevel-sq if is_available sar ; then sar -u 1 5 >${tmpdir}/sys.sar.cpu 2>/dev/null sar -b 1 5 >${tmpdir}/sys.sar.disk 2>/dev/null1 fi } debun_aix () { add_extra debun_extra_aix echo "Check package files integrity" rpm_verify syslog-ng-premium-edition syslog-ng-premium-edition-client syslog-ng-premium-edition-compact || \ echo "No syslog-ng RPM packages have been found!" echo "list syslog-related packages" rpm -qa |grep syslog > ${tmpdir}/rpm.packages } detect_env_linux () { if is_available lsb_release ; then lsb_release -a | tee ${tmpdir}/sys.linux.lsb-all dist=$( lsb_release -si ) fi if [ -r /etc/debian_version ]; then cat /etc/debian_version >${tmpdir}/sys.linux.os-release dist="Debian" elif [ -r /etc/redhat-release ]; then cat /etc/redhat-release >${tmpdir}/sys.linux.os-release dist="RHEL" elif [ -r /etc/slackware-version ]; then cat /etc/slackware-version >${tmpdir}/sys.linux.os-release dist="Slackware" elif [ -r /etc/SuSE-release ]; then cat /etc/SuSE-release >${tmpdir}/sys.linux.os-release dist="SUSE LINUX" else echo "Unknown or unsupported Linux distribution!" cat /etc/*release /etc/*version >${tmpdir}/sys.linux.os-release 2>/dev/null fi } detect_env () { ### ### Detecting syslog-ng ver: ose or pe ### echo "Start environment detection" if [ -x /opt/syslog-ng/bin/loggen ] ; then syslogfhs=unix echo "Unix-like FHS detected" elif [ -d /etc/syslog-ng/ ]; then syslogfhs=linux echo "Linux-type FHS detected" else syslogfhs=unknown confdir=/nonexistent echo "No syslog-ng detected" fi os=$( uname -s ) if [ "$os" = "Linux" ]; then detect_env_linux fi } setup_env_debian () { unset distpkgoffile unset distpkgstatus distpkgoffile () { local tmpfile=${tmpdir}/distpkgoffile.$$.tmp dpkg -S $1 >$tmpfile read x < $tmpfile rm $tmpfile echo "${x%: /*}" } distpkgstatus () { echo "@@@Package info for: ${1}" dpkg -s ${1} echo "" } } setup_env_redhat () { unset distpkgoffile unset distpkgstatus distpkgoffile () { local tmpfile=${tmpdir}/distpkgoffile.$$.tmp rpm -qf $1 >$tmpfile read x < $tmpfile rm $tmpfile echo "$x" } distpkgstatus () { echo "@@@Package info for: ${1}" rpm -qi ${1} echo "" } } setup_env_suse () { unset distpkgoffile unset distpkgstatus distpkgoffile () { local tmpfile=${tmpdir}/distpkgoffile.$$.tmp rpm -qf $1 >$tmpfile read x < $tmpfile rm $tmpfile echo "$x" } distpkgstatus () { echo "@@@Package info for: ${1}" rpm -qi $1 echo "" } } setup_env_slackware () { initfile="/etc/rc.d/rc.syslog" service_start="${initfile} start" service_stop="${initfile} stop" if [ -f "/var/run/syslog-ng.pid" ]; then piddir="/var/run" fi unset service_status unset distpkgoffile unset distpkgstatus distpkgoffile () { local LINKTARGET local PKGLOGFILENAMES local SEARCHSTRING PKGLOGFILE= LINKTARGET=$( readlink -f "${1}" 2>/dev/null ) SEARCHSTRING="${LINKTARGET##/}" PKGLOGFILENAMES=$( \ ( grep -r -m 1 -E "^${SEARCHSTRING}\$" /var/log/packages ; \ [ "${SEARCHSTRING%%/*}" = "lib" ] && grep -r -m 1 -E "^lib/incoming/${SEARCHSTRING#*/}\$" /var/log/packages ; \ [ "${SEARCHSTRING%%/*}" = "lib64" ] && grep -r -m 1 -E "^lib64/incoming/${SEARCHSTRING#*/}\$" /var/log/packages ) | \ while read -r RESULT; do RESULT="${RESULT%%:*}" echo "${RESULT##*/}" done ) if [ -n "${PKGLOGFILENAMES}" ]; then echo "${PKGLOGFILENAMES}" else echo "No installed package for '$1' found!" >&2 fi } distpkgstatus () { local PIVOT local LASTLINE local PKGINFO echo "@@@Package info for: ${1}" PKGINFO=$( \ ( find /var/log/packages/ -name "${1}*" ) | \ while read -r PKGLOGFILE; do PIVOT=$( fgrep -n "FILE LIST:" "${PKGLOGFILE}" ) LASTLINE=$(( ${PIVOT%%:*} - 1 )) 2>/dev/null head -n ${LASTLINE:-16} "${PKGLOGFILE}" echo "" done ) if [ -n "${PKGINFO}" ]; then echo "${PKGINFO}" else echo "The package '${1}' is not installed, or does not exist!" >&2 fi } } setup_env_genlinux () { unset myplimit no_lsof_fallback myplimit () { [ -f "/proc/$1/limits" ] && cat /proc/$1/limits ; } no_lsof_fallback() { ls -l /proc/${1}/fd ; } if is_available systemctl ; then service_stop="systemctl stop syslog-ng" service_start="systemctl start syslog-ng" service_status="systemctl status syslog-ng" fi # sed -E uses extended regexes, and normally works on Linux and BSD, where perl is not present by default. # -e and -E patterns use different syntax, but the great thing is that the -E format also works with perl. # However older GNU sed versions do not support the -E option, so we have no other choice but perl in # these cases. if echo "eee" | sed -E 's/eee/fff/g' >/dev/null 2>/dev/null ; then : else sed_equivalent_cmd="perl -p -e" fi } setup_env_linux () { case "${dist}" in "Debian"|"Ubuntu") setup_env_debian ;; "CentOS"|"RedHatEnterprise"|"RedHatEnterpriseServer"|"RHEL"|"OracleServer"|"EnterpriseEnterpriseServer") setup_env_redhat ;; "SUSE LINUX") setup_env_suse ;; "Slackware") setup_env_slackware ;; *) echo "Unknown Distro, perhaps unsupported" ;; esac setup_env_genlinux } setup_env_solaris () { dfi="df -o i" lsof=pfiles ipconfig="ifconfig -a" pscmd="ps -eaf" tcpdumpcmd="snoop" tcpdumpopts="-P -q -o" pcapifparm="-d" trace="truss -r all -w all -u libc:: -f" netstatpunt() { netstat -n ; } netstatpn() { netstat -n ; } netstatsu="netstat -s" grepq="/usr/xpg4/bin/grep -q" sed_equivalent_cmd="perl -p -e" unset -f mypidof unset -f getsyslogpids unset -f netstatlunp unset -f netstatnlp unset -f myplimit unset -f topcmd unset -f free unset -f distpkgoffile unset -f distpkgstatus unset -f is_available unset -f os_hash_helper unset -f timestamp unset -f findL is_available () { which "$1" | $grepq "no $1 in" && return 1 || return 0 ; } mypidof () { $pseao pid,comm | while read pid bin ; do [ "$bin" = "$1" ] && echo $pid ; done ; } getsyslogpids () { mypidof "${syslogrealbin}" ; } netstatnlp () { netstat -na ; } netstatlunp () { netstat -P udp -na ; } myplimit () { plimit $1 ; } free () { prtconf | grep Mem ; printf Pagesize:\ ; pagesize -a ; } timestamp () { perl -e 'print time, "\n";' ; } distpkgoffile () { FILE="$1" if [ -L "/lib/64" ]; then FILE=$( perl -sae '$libarch=readlink("/lib/64"); $filename =~ s/lib\/64/lib\/$libarch/; print "$filename\n";' -- -filename="$1" ) fi pkgchk -l -p $FILE | \ perl -ne 'if ( /^Referenced by the/ ) { $p=1; } elsif (/:/ or /^$/ ) { $p=0; } elsif ($p) { s/^\s+//; print ; } else { print "FAIL:".$_; }' } distpkgstatus () { echo "@@@Package info for: ${1}" pkginfo -l $1 echo "" } if find -L /bin >/dev/null 2>&1 ; then findL() { find -L "$@" ; } else findL() { dir="$1"; shift; find "$dir" -follow "$@" ; } fi if is_available top; then topcmd () { top -b -n 1 -c > "${1}" ; } else topcmd () { ( uptime ; echo ; echo "::memstat" | mdb -k ; sar -u 1 1 ; echo ; ps -eao user,pid,ppid,pcpu,pmem,vsz,rss,tty,s,stime,args | head -n 1; ps -eao user,pid,ppid,pcpu,pmem,vsz,rss,tty,s,stime,args | grep -v COMMAND | sort -rn +3 ) >"${1}" 2>/dev/null ; } fi if is_available md5sum; then os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -print0 | xargs -0 md5sum ; } elif is_available digest; then os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -exec digest -a md5 -v '{}' \; | ${sed_equivalent_cmd} 's:^md5 (\(.*\)) = \([a-z0-9]\{32\}\)$:\2 \1:' } else os_hash_helper () { : ; } fi if is_available svcadm ; then service_stop="svcadm disable system/syslog-ng:default" service_start="svcadm enable system/syslog-ng:default" service_status="svcs system/syslog-ng:default" fi if is_available ${opensslcmd}; then : else [ -x /usr/sfw/bin/openssl ] && opensslcmd="/usr/sfw/bin/openssl" fi } setup_env_freebsd () { netstatpunt() { netstat -n ; } netstatpn() { netstat -n ; } netstatsu="netstat -s" ipconfig="ifconfig -a" pseao="ps xao" trace="truss -a -d -f -s 256" initfile="/etc/rc.d/syslog-ng" service_stop="${initfile} stop" service_start="${initfile} start" service_status="${initfile} status" unset -f free unset -f netstatnlp unset -f netstatlunp unset -f mypidof unset -f topcmd unset -f getsyslogpids unset -f distpkgoffile unset -f distpkgstatus unset -f os_hash_helper free () { top -bt 0 ; } netstatnlp () { sockstat ; } netstatlunp () { netstat -na | grep -E "(Internet|Proto|udp)" ; } topcmd () { top -b -d1 > "${1}" ; } mypidof () { $pseao pid,comm | while read pid bin ; do [ "$bin" = "$1" ] && echo $pid ; done; } getsyslogpids () { mypidof syslog-ng ; } distpkgoffile () { : ; } distpkgstatus () { : ; } os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -exec md5 '{}' \; | ${sed_equivalent_cmd} 's:^MD5 (\(.*\)) = \([a-z0-9]\{32\}\)$:\2 \1:' } } setup_env_hpux () { gzipcmd="/usr/contrib/bin/gzip -9" lddcmd="/usr/ccs/bin/ldd" trace="/usr/local/bin/tusc -p -l -u -f" netstatsu="netstat -s" netstatpunt() { netstat -n ; } netstatpn() { netstat -n ; } ipconfig="netstat -ni" pscmd="ps -eaf" dfh="df" initfile="/sbin/init.d/syslog-ng" service_stop="${initfile} stop" service_start="${initfile} start" service_status="${initfile} status" sed_equivalent_cmd="perl -p -e" cpiopdL="cpio -pdh" unset -f free unset -f netstatnlp unset -f netstatlunp unset -f mypidof unset -f topcmd unset -f os_hash_helper unset -f getsyslogpids unset -f getparent unset -f getchilds unset -f is_available unset -f dfk_parser unset -f distpkgoffile unset -f distpkgstatus unset -f distpkgoffile_cleanup unset -f findL export UNIX95=1 is_available () { which "$1" | $grepq "no $1 in" && return 1 || return 0 ; } free () { swapinfo -tam ; } netstatnlp () { netstat -na | grep -E "(Internet|Proto|LISTEN)" ; } netstatlunp () { netstat -na | grep -E "(Internet|Proto|udp)" ; } topcmd () { top -d 1 -f "${1}" ; } dfk_parser () { grep free | while read AVAIL REST_TEXT; do echo ${AVAIL}; done } findL() { dir="$1"; shift; find "$dir" -follow "$@" ; } os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -exec md5sum '{}' \; } mypidof () { ps -e -f | while read uid pid ppid c stime tty time command extra ; do if [ "${stime%%:*}" = "${stime}" ] then [ "${extra%% *}" = "$1" ] && echo $pid else [ "${command%% *}" = "$1" ] && echo $pid fi ; done ; } getsyslogpids () { mypidof "${syslogrealbin}" ; } getparent () { local self local parent local ret local tmpfile=${tmpdir}/getparent.$$.txt ps -ef >$tmpfile while read user pid ppid dummy ; do [ "$1" = "$pid" ] || continue ret=$ppid done < $tmpfile rm $tmpfile echo $ret } getchilds () { local childs local dummy local child local tmpfile=${tmpdir}/getchilds.$$.txt ps -ef >$tmpfile while read user pid ppid dummy ; do [ "$1" = "$ppid" ] || continue childs="${childs}${childs:+ }$pid" done < $tmpfile rm $tmpfile echo ${childs} } distpkgoffile () { local tmpfile=${tmpdir}/distpkgoffile.tmp if [ ! -f $tmpfile ]; then swlist -l file > "$tmpfile" fi grep $1 $tmpfile | cut -d : -f 1 | while read x; do echo "$x" done } distpkgstatus () { printf "@@@Package info for fileset/patch: %s\n" "$1" swlist -l fileset -a title -a description $1 | grep -v "^#" | grep -v "^\"" printf "\n" } distpkgoffile_cleanup () { if [ -f "${tmpdir}/distpkgoffile.tmp" ]; then echo "Removing package list cache" rm "${tmpdir}/distpkgoffile.tmp" fi } } setup_env_aix () { ipconfig="ifconfig -a" pscmd="ps -eaf" dfh="df -k" netstatsu="netstat -s" netstatpunt() { netstat -n ; } netstatpn() { netstat -n ; } dmesg="alog -o -t boot" trace="truss -r all -w all -u libc:: -f" initfile= service_stop="/usr/bin/stopsrc -s syslog-ng" service_start="/usr/bin/startsrc -s syslog-ng" service_status="/usr/bin/lssrc -s syslog-ng" sed_equivalent_cmd="perl -p -e" cpiopdL="/usr/sysv/bin/cpio -pdL" unset -f initfile unset -f netstatnlp unset -f netstatlunp unset -f routeconfig unset -f free unset -f dfk_parser unset -f getsyslogpids unset -f mypidof unset -f topcmd unset -f format_ldd_output unset -f os_hash_helper format_ldd_output () { ${sed_equivalent_cmd} 's:^[^/]*\(.*\)$:\1:' -e 's:^\(.*\)(.*)$:\1:'; } netstatnlp () { netstat -na | grep -E "(Active|Proto|LISTEN)" ; } netstatlunp () { netstat -na | grep -E "(Internet|Proto|udp)" ; } dfk_parser () { tail -1 | while read FS ALL AVAIL UPERC IUPERC MP; do echo ${AVAIL}; done } routeconfig () { if netstat -nr 2>&1 | $grepq 'Permission error' ; then echo 'WPAR without its own routing table.' ; else netstat -nr ; fi ; } free () { svmon -G -O unit=KB ; } topcmd () { ( uptime ; svmon -G | head -n 3 ; sar -u 1 1 ; echo ; ps auxwww | head -n 1; ps auxwww | grep -v COMMAND | sort -rn +2 ) >"${1}" 2>/dev/null ; } mypidof () { ps -eaf | while read user pid ppid c stime tty time cmd extra; do if [ "${stime%%:*}" = "${stime}" ] then [ "${extra%% *}" = "$1" ] && echo $pid else [ "${cmd%% *}" = "$1" ] && echo $pid fi ; done ; } getsyslogpids () { mypidof "${syslogrealbin}" ; } unset distpkgoffile unset distpkgstatus distpkgoffile () { local tmpfile=${tmpdir}/distpkgoffile.$$.tmp rpm -qf $1 >$tmpfile read x < $tmpfile rm $tmpfile echo "$x" } distpkgstatus () { printf "@@@Package info for: %s\n" "$1" rpm -qi $1 printf "\n" } os_hash_helper () { find . '!' \( -name debun.manifest -o -name syslog-ng.debun.txt \) -type f -exec csum -h MD5 '{}' \; } } setup_env_generic_pre () { : } setup_env_generic_post () { ### Check if ss is available (should only be present on Linux) if is_available ss ; then unset -f routeconfig unset -f netstatnlp unset -f netstatlunp routeconfig () { ip route show ; } netstatnlp () { ss -nlp ; } netstatlunp () { ss -lunp ; } netstatpunt() { ss -punt ; } netstatpn() { ss -pn ; } fi if is_available netstat; then : else is_available nstat && netstatsu="nstat" fi } setup_env() { setup_env_generic_pre ### ### Decide OS (switch-like) ### printf "\nOperating System Name: %s\n" "$os" if [ "$os" = "Linux" ]; then setup_env_linux elif [ "$os" = "SunOS" ]; then setup_env_solaris elif [ "$os" = "FreeBSD" ]; then setup_env_freebsd elif [ "$os" = "HP-UX" ]; then setup_env_hpux elif [ "$os" = "AIX" ]; then setup_env_aix else printf "Unkonwn or (yet) unhandled system\n" fi setup_env_generic_post } debun_run () { if [ "$os" = "Linux" ]; then debun_linux elif [ "$os" = "SunOS" ]; then debun_solaris elif [ "$os" = "FreeBSD" ]; then debun_freebsd elif [ "$os" = "HP-UX" ]; then debun_hpux elif [ "$os" = "AIX" ]; then debun_aix fi } run_specific_extras () { for i in ${extras}; do $i done } run_debug () { printf "\nStart Debug collection\n" if [ -n "${pcap_params}" ]; then if is_available $tcpdumpcmd ; then echo "Start packet dump in background with filters: ${pcap_params}" ${tcpdumpcmd} ${tcpdumpopts} ${tmpdir}/debug.pcap ${pcap_iface:+$pcapifparm} ${pcap_iface} ${pcap_params} & pcappid=${!} else echo "tcpdump/snoop is not available" >&2 fi fi if [ -n "${tracing}" ] && [ -z "${debug_params}" ]; then if is_available "${trace%% *}"; then for i in ${sngallpids}; do ${trace} -o ${tmpdir}/trace.${i}.txt -p ${i} & tracepids="${tracepids}${tracepids:+ }${!}" done else echo "Tracing was requested but ${trace%% *} was not available!" fi fi if [ -n "${waitforit}" ]; then [ -n "${pcap_params}" ] && sleep 1 echo "Waiting ${waitforit} secs before stop system's syslog-ng, and restart in debug mode." pad='' bs='' for i in $( seq 1 ${#waitforit} ); do pad="${pad} " ; bs="\b${bs}" ; done printf "Start countdown: ${pad}" >&3 for i in $( seq ${waitforit} -1 1 ); do printf "${bs}${pad:${#i}}$i" >&3 ; sleep 1 ; done print "0\n">&3 touch ${tmpdir}/syslog.debug fi if [ -n "${debug_params}" ]; then ${service_stop} # We should implement a better waiting for the system service's shutdown, sleep 1 works for now sleep 1 echo "Start syslog-ng debug with params: ${debug_params}" if [ -n "$tracing" ]; then if is_available "${trace%% *}"; then ${trace} -o ${tmpdir}/trace.dbg.txt ${syslogbin} ${debug_params} >>${tmpdir}/syslog.debug 2>&1 & i=${!} tracepids="${i}" debugpid="$( getchilds ${i} )" echo "Trace: ${i} Debug: ${debugpid}" else echo "Tracing was requested but ${trace%% *} was not available!" ${syslogbin} ${debug_params} >>${tmpdir}/syslog.debug 2>&1 & debugpid=${!} fi else ${syslogbin} ${debug_params} >>${tmpdir}/syslog.debug 2>&1 & debugpid=${!} fi fi if [ -n "$debug_mode" ]; then sleep 1 acquire_syslog_stats fi [ -n "${timeout}" ] || echo "When you want to stop collecting data, press ENTER" >&3 if [ -n "${waitforit}" ]; then sleep 1 # Let's give time the user, to read the message about stopping tail -f ${tmpdir}/syslog.debug >&3 & debugtailpid=${!} #disown fi if [ -n "${timeout}" ]; then sleep "${timeout}" else read line fi } ### ### Main program tasks ### debun_init detect_env setup_env debun_run [ "$syslogfhs" = "linux" ] && fhs_set_linux [ "$syslogfhs" = "unix" ] && fhs_set_unix run_specific_extras acquire_general_info if [ -n "$privacy_mode" ]; then acquire_syslog_nprv else acquire_syslog_all fi [ -n "$debug_mode" ] && run_debug debun_final syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/000077500000000000000000000000001450431004300227575ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/.helmignore000066400000000000000000000005351450431004300251140ustar00rootroot00000000000000# Patterns to ignore when building packages. # This supports shell glob matching, relative path matching, and # negation (prefixed with !). Only one pattern per line. .DS_Store # Common VCS dirs .git/ .gitignore .bzr/ .bzrignore .hg/ .hgignore .svn/ # Common backup files *.swp *.bak *.tmp *.orig *~ # Various IDEs .project .idea/ *.tmproj .vscode/ syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/Chart.yaml000066400000000000000000000003311450431004300247010ustar00rootroot00000000000000apiVersion: v1 name: syslog-ng description: Syslog-ng version: 0.2 appVersion: 3.27.1 maintainers: - name: zakkg3 sources: - https://github.com/syslog-ng/syslog-ng keywords: - Syslog - syslog-ng - logrotate syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/LICENSE000066400000000000000000000005731450431004300237710ustar00rootroot00000000000000Copyright (c) 2020 Nicolas Kowenski The syslog-ng Helm chart contained in this directory is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version (please refer to the file LGPL.txt for more details). syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/000077500000000000000000000000001450431004300247555ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/NOTES.txt000066400000000000000000000026451450431004300264150ustar00rootroot000000000000001. syslog-ng deployment. {{- if contains "NodePort" .Values.service.type }} export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "syslog-ng.fullname" . }}) export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT {{- else if contains "LoadBalancer" .Values.service.type }} NOTE: It may take a few minutes for the LoadBalancer IP to be available. You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "syslog-ng.fullname" . }}' export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "syslog-ng.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "syslog-ng.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") echo "Syslogng watch on tcp 601 and udp 514 port" {{- end }} ######################################################## # Syslogng watch on tcp 601 and udp 514 port # ######################################################## syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/_helpers.tpl000066400000000000000000000034601450431004300273020ustar00rootroot00000000000000{{/* vim: set filetype=mustache: */}} {{/* Expand the name of the chart. */}} {{- define "syslog-ng.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). If release name contains chart name it will be used as a full name. */}} {{- define "syslog-ng.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} {{- $name := default .Chart.Name .Values.nameOverride }} {{- if contains $name .Release.Name }} {{- .Release.Name | trunc 63 | trimSuffix "-" }} {{- else }} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} {{- end }} {{- end }} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "syslog-ng.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} {{- define "syslog-ng.labels" -}} helm.sh/chart: {{ include "syslog-ng.chart" . }} {{ include "syslog-ng.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} {{/* Selector labels */}} {{- define "syslog-ng.selectorLabels" -}} app.kubernetes.io/name: {{ include "syslog-ng.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Create the name of the service account to use */}} {{- define "syslog-ng.serviceAccountName" -}} {{- if .Values.serviceAccount.create }} {{- default (include "syslog-ng.fullname" .) .Values.serviceAccount.name }} {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/compress-job.yaml000066400000000000000000000031701450431004300302450ustar00rootroot00000000000000{{- if .Values.compressor.enabled }} --- apiVersion: v1 kind: ConfigMap metadata: name: job-script data: entrypoint.sh: |- #!/bin/bash ls -lh /var/log/*-syslog for filename in /var/log/*-syslog; do if [[ $(find "$filename" -mtime +{{ .Values.compressor.retention_days }} -print) ]]; then echo "$filename is older than {{ .Values.compressor.retention_days }} days, Compressing." tar -zcvf "$filename"-$(date +%d-%m-%y).tar.gz $filename rm $filename else echo skippig $filename not older than {{ .Values.compressor.retention_days }} days. fi done --- apiVersion: batch/v1beta1 kind: CronJob metadata: name: {{ include "syslog-ng.fullname" . }}-compressor spec: schedule: "{{ .Values.compressor.schedule }}" jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: compress image: "ubuntu:20.10" command: - /bin/entrypoint.sh volumeMounts: - name: configmap-volume mountPath: /bin/entrypoint.sh readOnly: true subPath: entrypoint.sh {{- if .Values.storage.enable }} - mountPath: /var/log name: logs {{- end }} volumes: - name: configmap-volume configMap: defaultMode: 0700 name: job-script {{- if .Values.storage.enable }} - name: logs persistentVolumeClaim: claimName: {{ include "syslog-ng.fullname" . }}-pvc {{- end }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/config.yaml000066400000000000000000000003341450431004300271060ustar00rootroot00000000000000apiVersion: v1 kind: ConfigMap metadata: labels: {{- include "syslog-ng.labels" . | nindent 4 }} name: {{ include "syslog-ng.fullname" . }} data: syslog-ng.conf: {{ tpl (toYaml .Values.config) . | indent 4 }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/deployment.yaml000066400000000000000000000040671450431004300300300ustar00rootroot00000000000000apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "syslog-ng.fullname" . }} labels: {{- include "syslog-ng.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "syslog-ng.selectorLabels" . | nindent 6 }} template: metadata: annotations: checksum/config: {{ tpl (toYaml .Values.config) . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "syslog-ng.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: tcp-port containerPort: 601 protocol: TCP - name: udp-port containerPort: 514 protocol: UDP volumeMounts: - mountPath: /etc/syslog-ng/syslog-ng.conf name: config subPath: syslog-ng.conf {{- if .Values.storage.enable }} - mountPath: /var/log name: logs {{- end }} volumes: - name: config configMap: name: {{ include "syslog-ng.fullname" . }} {{- if .Values.storage.enable }} - name: logs persistentVolumeClaim: claimName: {{ include "syslog-ng.fullname" . }}-pvc {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/hpa.yaml000066400000000000000000000016221450431004300264120ustar00rootroot00000000000000{{- if .Values.autoscaling.enabled }} apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: {{ include "syslog-ng.fullname" . }} labels: {{- include "syslog-ng.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: {{ include "syslog-ng.fullname" . }} minReplicas: {{ .Values.autoscaling.minReplicas }} maxReplicas: {{ .Values.autoscaling.maxReplicas }} metrics: {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - type: Resource resource: name: cpu targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} {{- end }} {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - type: Resource resource: name: memory targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} {{- end }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/pvc.yaml000066400000000000000000000004711450431004300264330ustar00rootroot00000000000000{{- if .Values.storage.enable }} kind: PersistentVolumeClaim apiVersion: v1 metadata: name: {{ include "syslog-ng.fullname" . }}-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: {{ .Values.storage.size }} storageClassName: {{ .Values.storage.storageClass }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/service.yaml000066400000000000000000000011371450431004300273030ustar00rootroot00000000000000apiVersion: v1 kind: Service metadata: name: {{ include "syslog-ng.fullname" . }} labels: {{- include "syslog-ng.labels" . | nindent 4 }} spec: {{- if eq .Values.service.type "externalip" }} {{- with .Values.service.externalIPs }} externalIPs: {{- toYaml . | nindent 3 }} {{- end }} {{- else}} type: {{ .Values.service.type }} {{- end }} ports: - name: udp-port port: 514 targetPort: 514 protocol: UDP - name: tcp-port port: 601 targetPort: 601 protocol: TCP selector: {{- include "syslog-ng.selectorLabels" . | nindent 4 }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/serviceaccount.yaml000066400000000000000000000005041450431004300306550ustar00rootroot00000000000000{{- if .Values.serviceAccount.create -}} apiVersion: v1 kind: ServiceAccount metadata: name: {{ include "syslog-ng.serviceAccountName" . }} labels: {{- include "syslog-ng.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/tests/000077500000000000000000000000001450431004300261175ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/templates/tests/test-connection.yaml000066400000000000000000000006111450431004300321150ustar00rootroot00000000000000apiVersion: v1 kind: Pod metadata: name: "{{ include "syslog-ng.fullname" . }}-test-connection" labels: {{- include "syslog-ng.labels" . | nindent 4 }} annotations: "helm.sh/hook": test-success spec: containers: - name: wget image: busybox command: ['wget'] args: ['{{ include "syslog-ng.fullname" . }}:{{ .Values.service.port }}'] restartPolicy: Never syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng-helm-chart/values.yaml000066400000000000000000000052731450431004300251510ustar00rootroot00000000000000# Default values for syslog-ng. replicaCount: 1 image: repository: balabit/syslog-ng pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "3.27.1" # By default, the network() driver binds to 0.0.0.0, meaning that it listens # on every available IPV4 interface on the TCP/601 port. config: | @version: 3.27 @include "scl.conf" options { # enable or disable directory creation for destination files create_dirs(yes); # keep hostnames from source host keep_hostname(yes); # use ISO8601 timestamps ts_format(iso); }; log { source { network(); }; destination { file("/var/log/${YEAR}-${MONTH}-syslog"); }; }; storage: enable: True storageClass: "" size: 500Gi # Enable compressor to run a cron-job to compress files in /var/log/*-syslog older than retention_days # it also delete the plain-text file in order to keep the folder size as low as possible. # (if changes destination in server.config other than `/var/log/${YEAR}-${MONTH}-syslog` be aware you could breake this) compressor: enabled: True #“At 04:25 on day 1 and 15, every month every year” schedule: "25 4 1,15 * *" retention_days: 120 imagePullSecrets: [] nameOverride: "" fullnameOverride: "" serviceAccount: # Specifies whether a service account should be created create: false # Annotations to add to the service account annotations: {} # The name of the service account to use. # If not set and create is true, a name is generated using the fullname template name: "" podAnnotations: {} podSecurityContext: {} # fsGroup: 2000 # Syslog-ng manages its own capabilities as well, just make sure the two doesn't collide. securityContext: {} # capabilities: # drop: # - ALL # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000 # syslog-ng have fixed ports tcp 601 and udp 514 service: type: ClusterIP # use externalip for a pre routede exter al ip. # TO-DO: LoadBalancer # type: externalip # externalIPs: # - 10.205.212.12 resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 1 targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 nodeSelector: {} tolerations: [] affinity: {} syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng.conf.HP-UX000066400000000000000000000023561450431004300224520ustar00rootroot00000000000000# syslog-ng configuration file. # # This should behave pretty much like the original syslog on HP-UX. But # it could be configured a lot smarter. # # See syslog-ng(8) and syslog-ng.conf(8) for more information. # # 20000925 gb@sysfive.com options { sync (0); time_reopen (10); log_fifo_size (1000); long_hostnames (off); use_dns (no); use_fqdn (no); create_dirs (no); keep_hostname (yes); }; source s_sys { pipe("/dev/log"); internal(); }; destination d_cons { file("/dev/console"); }; destination d_mesg { file("/var/adm/syslog/syslog.log"); }; destination d_mail { file("/var/adm/syslog/mail.log"); }; destination d_mlrt { usertty("root"); }; destination d_mlal { usertty("*"); }; filter f_filter1 { facility(mail) and level(debug); }; filter f_filter2 { (facility(mail) and level(debug)) or level(info); }; filter f_filter3 { level(alert); }; filter f_filter4 { level(emerg); }; log { source(s_sys); filter(f_filter1); destination(d_mail); }; log { source(s_sys); filter(f_filter2); destination(d_mesg); }; log { source(s_sys); filter(f_filter3); destination(d_cons); destination(d_mlrt); }; log { source(s_sys); filter(f_filter4); destination(d_mlal); }; syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng.conf.RedHat000066400000000000000000000052151450431004300227550ustar00rootroot00000000000000# syslog-ng configuration file. # # This should behave pretty much like the original syslog on RedHat. But # it could be configured a lot smarter. # # See syslog-ng(8) and syslog-ng.conf(5) for more information. # # 20000925 gb@sysfive.com # # Updated by Frank Crawford () - 10 Aug 2002 # - for Red Hat 7.3 # - totally do away with klogd # - add message "kernel" as is done with klogd. # # Updated by Frank Crawford () - 22 Aug 2002 # - use the program_override option as per Balazs Scheidler's email # options { sync (0); time_reopen (10); log_fifo_size (1000); long_hostnames (off); use_dns (no); use_fqdn (no); create_dirs (no); keep_hostname (yes); }; # # At around 1999 some distributions have changed from using SOCK_STREAM # to SOCK_DGRAM sockets, see these posts about the issue: # # http://www.security-express.com/archives/bugtraq/1999-q4/0071.html # http://marc.theaimsgroup.com/?l=sysklogd&m=96989685607952&w=2 # # libc and syslog clients generally automatically detect the socket type, # so you are free to decide which of unix-stream or unix-dgram you want to use. # source s_sys { file ("/proc/kmsg" program_override("kernel")); unix-stream ("/dev/log"); internal(); }; destination d_cons { file("/dev/console"); }; destination d_mesg { file("/var/log/messages"); }; destination d_auth { file("/var/log/secure"); }; destination d_mail { file("/var/log/maillog"); }; destination d_spol { file("/var/log/spooler"); }; destination d_boot { file("/var/log/boot.log"); }; destination d_cron { file("/var/log/cron"); }; destination d_mlal { usertty("*"); }; filter f_filter1 { facility(kern); }; filter f_filter2 { level(info) and not (facility(mail) or facility(authpriv) or facility(cron)); }; filter f_filter3 { facility(authpriv); }; filter f_filter4 { facility(mail); }; filter f_filter5 { level(emerg); }; filter f_filter6 { facility(uucp) or (facility(news) and level(crit)); }; filter f_filter7 { facility(local7); }; filter f_filter8 { facility(cron); }; #log { source(s_sys); filter(f_filter1); destination(d_cons); }; log { source(s_sys); filter(f_filter2); destination(d_mesg); }; log { source(s_sys); filter(f_filter3); destination(d_auth); }; log { source(s_sys); filter(f_filter4); destination(d_mail); }; log { source(s_sys); filter(f_filter5); destination(d_mlal); }; log { source(s_sys); filter(f_filter6); destination(d_spol); }; log { source(s_sys); filter(f_filter7); destination(d_boot); }; log { source(s_sys); filter(f_filter8); destination(d_cron); }; syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng.conf.SunOS000066400000000000000000000044241450431004300226160ustar00rootroot00000000000000# syslog-ng configuration file. # # This should behave pretty much like the original syslog on SunOS. But # it could be configured a lot smarter. # # See syslog-ng(8) and syslog-ng.conf(5) for more information. # # 20000925 gb@sysfive.com options { sync (0); time_reopen (10); log_fifo_size (1000); long_hostnames (off); use_dns (no); use_fqdn (no); create_dirs (no); keep_hostname (yes); }; source s_sys { sun-streams ("/dev/log" door("/etc/.syslog_door")); internal(); }; destination d_cons { file("/dev/console"); }; destination d_mesg { file("/var/adm/messages"); }; destination d_mail { file("/var/log/syslog"); }; destination d_auth { file("/var/log/authlog"); }; destination d_mlop { usertty("operator"); }; destination d_mlrt { usertty("root"); }; destination d_mlal { usertty("*"); }; filter f_filter1 { level(err) or (level(notice) and facility (auth, kern)); }; filter f_filter2 { level(err) or (facility(kern) and level(notice)) or (facility(daemon) and level(notice)) or (facility(mail) and level(crit)); }; filter f_filter3 { level(alert) or (facility(kern) and level(err)) or (facility(daemon) and level(err)); }; filter f_filter4 { level(alert); }; filter f_filter5 { level(emerg); }; filter f_filter6 { facility(kern) and level(notice); }; filter f_filter7 { facility(mail) and level(debug); }; filter f_filter8 { facility(user) and level(err); }; filter f_filter9 { facility(user) and level(alert); }; log { source(s_sys); filter(f_filter1); destination(d_cons); }; log { source(s_sys); filter(f_filter2); destination(d_mesg); }; log { source(s_sys); filter(f_filter3); destination(d_mlop); }; log { source(s_sys); filter(f_filter4); destination(d_mlrt); }; log { source(s_sys); filter(f_filter5); destination(d_mlal); }; log { source(s_sys); filter(f_filter6); destination(d_auth); }; log { source(s_sys); filter(f_filter7); destination(d_mail); }; log { source(s_sys); filter(f_filter8); destination(d_cons); destination(d_mesg); }; log { source(s_sys); filter(f_filter9); destination(d_mlop); destination(d_mlrt); }; syslog-ng-syslog-ng-4.4.0/contrib/syslog-ng.conf.doc000066400000000000000000001670711450431004300223640ustar00rootroot00000000000000#---------------------------------------------------------------------- # Program: syslog-ng.conf # Notes: Embedded most of the manual notes within the configuration # file. The original manual can be found at: # # http://www.balabit.com/products/syslog_ng/reference/book1.html # http://www.campin.net/syslog-ng/faq.html # # Many people may find placing all of this information in a # configuration file a bit redundant, but I have found that # with a little bit of extra comments and reference, # maintaining these beasties is much easier. # # This particular log file was taken from the examples that # are given at the different web sites, and made to emulate # the logs of a Mandrake Linux system as much as possible. # Of course, Unix is Unix, is Linux. It should be generic # enough for any Unix system. #---------------------------------------------------------------------- # 16-Mar-03 - REP - Added some extra definitions to the file. # 15-Mar-03 - REP - Added back the comments on filtering. # 27-Feb-03 - REP - Further modified for local environment. # 27-Feb-03 - REP - Updated for new configuration and version 1.6.0 # 12-Dec-02 - REP - Continued updates for writing to databases. # 30-Nov-02 - REP - Initial creation for testing. #---------------------------------------------------------------------- # Options #---------------------------------------------------------------------- # # Name Values Description # ------------------------- ------- ------------------------------------ # bad_hostname reg exp A regexp which matches hostnames # which should not be taken as such. # chain_hostnames y/n Enable or disable the chained # hostname format. # create_dirs y/n Enable or disable directory creation # for destination files. # dir_group groupid # dir_owner userid # dir_perm perm # dns_cache y/n Enable or disable DNS cache usage. # dns_cache_expire num Number of seconds while a successful # lookup is cached. # dns_cache_expire_failed num Number of seconds while a failed # lookup is cached. # dns_cache_size num Number of hostnames in the DNS cache. # gc_busy_threshold num Sets the threshold value for the # garbage collector, when syslog-ng is # busy. GC phase starts when the number # of allocated objects reach this # number. Default: 3000. # gc_idle_threshold num Sets the threshold value for the # garbage collector, when syslog-ng is # idle. GC phase starts when the number # of allocated objects reach this # number. Default: 100. # group groupid # keep_hostname y/n Enable or disable hostname rewriting. # This means that if the log entry had # been passed through at least one other # logging system, the ORIGINAL hostname # will be kept attached to the log. # Otherwise the last logger will be # considered the log entry owner and # the log entry will appear to have # come from that host. # log_fifo_size num The number of lines fitting to the # output queue # log_msg_size num Maximum length of message in bytes. # long_hostnames on/off This options appears to only really # have an affect on the local system. # which removes the source of the log. # As an example, normally the local # logs will state src@hostname, but # with this feature off, the source # is not reported. # mark num The number of seconds between two # MARK lines. NOTE: not implemented # yet. # owner userid # perm perm # stats num The number of seconds between two # STATS. # sync num The number of lines buffered before # written to file # time_reap num The time to wait before an idle # destination file is closed. # time_reopen num The time to wait before a died # connection is reestablished # use_dns y/n Enable or disable DNS usage. # syslog-ng blocks on DNS queries, # so enabling DNS may lead to a # Denial of Service attack. To # prevent DoS, protect your # syslog-ng network endpoint with # firewall rules, and make sure that # all hosts, which may get to # syslog-ng is resolvable. # use_fqdn y/n Add Fully Qualified Domain Name # instead of short hostname. # use_time_recvd y/n Use the time a message is # received instead of the one # specified in the message. #---------------------------------------------------------------------- # 15-Mar-03 - REP - Since some of the clocks are not quite right, we # are going to go ahead and just use the local time # as the master time. # 12-Mar-03 - REP - We have taken a few configuration options from the # newer Solaris configuration because some of the # reasons are valid for us as well. We have increased # the log_msg_size and log_fifo_size to increase the # amount of buffering that we do. While for most # systems this may not have a noticeable affect, it # will for systems that are at the end of a lot of # logging systems. # 20-Dec-02 - REP - Changed the stat() time from the default of 10 # minutes to once an hour. #---------------------------------------------------------------------- options { chain_hostnames(no); create_dirs (no); dir_perm(0755); dns_cache(yes); keep_hostname(yes); log_fifo_size(2048); log_msg_size(8192); long_hostnames(on); perm(0644); stats(3600); sync(0); time_reopen (10); use_dns(yes); use_fqdn(yes); }; #---------------------------------------------------------------------- # Sources #---------------------------------------------------------------------- # # fifo/pipe - The pipe driver opens a named pipe with the # specified name, and listens for messages. It's # used as the native message getting protocol on # HP-UX. # file - Usually the kernel presents its messages in a # special file (/dev/kmsg on BSDs, /proc/kmsg on # Linux), so to read such special files, you'll need # the file() driver. Please note that you can't use # this driver to follow a file like tail -f does. # internal - All internally generated messages "come" from this # special source. If you want warnings, errors and # notices from syslog-ng itself, you have to include # this source in one of your source statements. # sun-streams - Solaris uses its STREAMS API to send messages to # the syslogd process. You'll have to compile # syslog-ng with this driver compiled in (see # ./configure --help). # # Newer versions of Solaris (2.5.1 and above), uses a # new IPC in addition to STREAMS, called door to # confirm delivery of a message. Syslog-ng supports # this new IPC mechanism with the door() option. # # The sun-streams() driver has a single required # argument, specifying the STREAMS device to open and # a single option. # tcp/udp - These drivers let you receive messages from the # network, and as the name of the drivers show, you # can use both UDP and TCP as transport. # # UDP is a simple datagram oriented protocol, which # provides "best effort service" to transfer # messages between hosts. It may lose messages, and # no attempt is made to retransmit such lost # messages at the protocol level. # # TCP provides connection-oriented service, which # basically means a flow-controlled message pipeline. # In this pipeline, each message is acknowledged, and # retransmission is done for lost packets. Generally # it's safer to use TCP, because lost connections can # be detected, and no messages get lost, but # traditionally the syslog protocol uses UDP. # # None of tcp() and udp() drivers require positional # parameters. By default they bind to 0.0.0.0:514, # which means that syslog-ng will listen on all # available interfaces, port 514. To limit accepted # connections to one interface only, use the # localip() parameter as described below. # # Options: # # Name Type Description Default # -------------- ------ -------------------------------- -------- # ip or local ip string The IP address to bind to. Note 0.0.0.0 # that this is not the address # where messages are accepted # from. # keep-alive y/n Available for tcp() only, and yes # specifies whether to close # connections upon the receival # of a SIGHUP signal. # max-connections number Specifies the maximum number of 10 # simultaneous connections. # port or local port number The port number to bind 514 # to. # -------------- ------ -------------------------------- -------- # # unix-stream - unix-dgram - These two drivers behave similarly: # they open the given AF_UNIX socket, and start # listening on them for messages. unix-stream() is # primarily used on Linux, and uses SOCK_STREAM # semantics (connection oriented, no messages are # lost), unix-dgram() is used on BSDs, and uses # SOCK_DGRAM semantics, this may result in lost # local messages, if the system is overloaded. # # To avoid denial of service attacks when using # connection-oriented protocols, the number of # simultaneously accepted connections should be # limited. This can be achieved using the # max-connections() parameter. The default value of # this parameter is quite strict, you might have to # increase it on a busy system. # # Both unix-stream and unix-dgram has a single # required positional argument, specifying the # filename of the socket to create, and several # optional parameters. # # Options: # # Name Type Description Default # -------------- ------ -------------------------------- -------- # group string Set the gid of the socket. root # keep-alive y/n Selects whether to keep yes # connections opened when # syslog-ng is restarted, can be # used only with unix-stream(). # max-connections numb Limits the number of 10 # simultaneously opened # connections. Can be used only # with unix-stream(). # owner string Set the uid of the socket. root # perm num Set the permission mask. For 0666 # octal numbers prefix the number # with '0', e.g. use 0755 for # rwxr-xr-x. #---------------------------------------------------------------------- # Notes: For Linux systems (and especially RedHat derivatives), # they have a second logging process for kernel messages. # This source is /proc/kmsg. If you are running this on a # system that is not Linux, then the source entry for this # should be removed. # # It seems that there is some performance questions related # to what type of source stream should be used for Linux # boxes. The documentation states the /dev/log should use # unix-stream, but from the mailing list it has been # strongly suggested that unix-dgram be used. # # WARNING: TCP wrappers has been enabled for this system, and unless # you also place entries in /etc/hosts.allow for each of the # devices that will be delivering logs via TCP, you will # NOT receive the logs. # # Also note that if there is any form of a local firewall, # this will also need to be altered such that the incoming # and possibly outgoing packets are allowed by the firewall # rules. #---------------------------------------------------------------------- # There has been a lot of debate on whether everything should be put # to a single source, or breakdown all the sources into individual # streams. The greatest flexibility would be in many, but the most # simple is the single. Since we wrote this file, we have chosen the # route of maximum flexibility. # # For those of you that like simplicity, this could have also been # done as the follows: # # source src # { # internal(); # file("/proc/kmsg" program_override("kernel")); # tcp(ip(127.0.0.1) port(4800) keep-alive(yes)); # udp(); # unix-stream("/dev/log"); # }; # # You would also have to change all the log statements to only # reference the now single source stream. #---------------------------------------------------------------------- # 16-Mar-03 - REP - The default number of allowed TCP connects is set # very low for a logserver. This value should only # be set greater than the default for servers that # will actually be serving that many systems. #---------------------------------------------------------------------- source s_dgram { unix-dgram("/dev/log"); }; source s_internal { internal(); }; source s_kernel { file("/proc/kmsg" program_override("kernel")); }; source s_tcp { tcp(port(4800) keep-alive(yes) max_connections(100)); }; #---------------------------------------------------------------------- # Destinations #---------------------------------------------------------------------- # # fifo/pipe - This driver sends messages to a named pipe like # /dev/xconsole # # The pipe driver has a single required parameter, # specifying the filename of the pipe to open, and # no options. # file - The file driver is one of the most important # destination drivers in syslog-ng. It allows you to # output messages to the named file, or as you'll see # to a set of files. # # The destination filename may include macros which # gets expanded when the message is written, thus a # simple file() driver may result in several files # to be created. Macros can be included by prefixing # the macro name with a '$' sign (without the quotes), # just like in Perl/PHP. # # If the expanded filename refers to a directory # which doesn't exist, it will be created depending # on the create_dirs() setting (both global and a per # destination option) # # WARNING: since the state of each created file must # be tracked by syslog-ng, it consumes some memory # for each file. If no new messages are written to a # file within 60 seconds (controlled by the time_reap # global option), it's closed, and its state is freed. # # Exploiting this, a DoS attack can be mounted against # your system. If the number of possible destination # files and its needed memory is more than the amount # your logserver has. # # The most suspicious macro is $PROGRAM, where the # possible variations is quite high, so in untrusted # environments $PROGRAM usage should be avoided. # # Macros: # # Name Description # ----------------- ----------------------------------------------- # DATE Date of the transaction. # DAY The day of month the message was sent. # FACILITY The name of the facility, the message is tagged # as coming from. # FULLDATE Long form of the date of the transaction. # FULLHOST Full hostname of the system that sent the log. # HOST The name of the source host where the message # is originated from. If the message traverses # several hosts, and chain_hostnames() is on, # the first one is used. # HOUR The hour of day the message was sent. # ISODATE Date in ISO format. # MIN The minute the message was sent. # MONTH The month the message was sent. # MSG or MESSAGE Message contents. # PRIORITY or LEVEL The priority of the message. # PROGRAM The name of the program the message was sent by. # SEC The second the message was sent. # TAG The priority and facility encoded as a 2 digit # hexadecimal number. # TZ The time zone or name or abbreviation. e.g. 'PDT' # TZOFFSET The time-zone as hour offset from GMT. e.g. # '-0700' # WEEKDAY The 3-letter name of the day of week the # message was sent, e.g. 'Thu'. # YEAR The year the message was sent. Time expansion # macros can either use the time specified in # the log message, e.g. the time the log message # is sent, or the time the message was received # by the log server. This is controlled by the # use_time_recvd() option. # ----------------- ----------------------------------------------- # # Options: # # Name Type Description Default # -------------- ------ -------------------------------- -------- # compress y/n Compress the resulting logfile global # using zlib. NOTE: this is not setting # implemented as of 1.3.14. # reate_dirs y/n Enable creating non-existing no # directories. # dir_perm num The permission mask of 0600 # directories created by # syslog-ng. Log directories are # only created if a file after # macro expansion refers to a # non-existing directory, and dir # creation is enabled using # create_dirs(). # encrypt y/n Encrypt the resulting file. global # NOTE: this is not implemented as setting # of 1.3.14. # fsync y/n Forces an fsync() call on the # destination fd after each write. # Note: this may degrade # performance seriously # group string Set the group of the created root # filename to the one specified. # log_fifo_size num The number of entries in the global # output fifo. setting # owner string Set the owner of the created root # filename to the one specified. # perm num The permission mask of the file 0600 # if it is created by syslog-ng. # remove_if_older num If set to a value higher than 0, 0 # before writing to a file, # syslog-ng checks whether this # file is older than the specified # amount of time (specified in # seconds). If so, it removes the # existing file and the line to # be written is the first line in # a new file with the same name. # In combination with e.g. the # $WEEKDAY macro, this is can be # used for simple log rotation, # in case not all history need to # be kept. # sync_freq num The logfile is synced when this global # number of messages has been setting # written to it. # template string Specifies a template which # specifies the logformat to be # used in this file. The possible # macros are the same as in # destination filenames. # template_escape y/n Turns on escaping ' and " in yes # templated output files. It is # useful for generating SQL # statements and quoting string # contents so that parts of your # log message don't get # interpreted as commands to the # SQL server. # -------------- ------ -------------------------------- -------- # # program - This driver fork()'s executes the given program with # the given arguments and sends messages down to the # stdin of the child. # # The program driver has a single required parameter, # specifying a program name to start and no options. # The program is executed with the help of the current # shell, so the command may include both file patterns # and I/O redirection, they will be processed. # # NOTE: the program is executed once at startup, and # kept running until SIGHUP or exit. The reason is to # prevent starting up a large number of programs for # messages, which would imply an easy DoS. # tcp/udp - This driver sends messages to another host on the # local intranet or internet using either UDP or TCP # protocol. # # Both drivers have a single required argument # specifying the destination host address, where # messages should be sent, and several optional # parameters. Note that this differs from source # drivers, where local bind address is implied, and # none of the parameters are required. # # Options: # # Name Type Description Default # -------------- ------ -------------------------------- -------- # localip string The IP address to bind to before 0.0.0.0 # connecting to target. # localport num The port number to bind to. 0 # port/destport num The port number to connect to. 514 # -------------- ------ -------------------------------- -------- # usertty - This driver writes messages to the terminal of a # logged-in user. # # The usertty driver has a single required argument, # specifying a username who should receive a copy of # matching messages, and no optional arguments. # unix-dgram - unix-stream - This driver sends messages to a unix # socket in either SOCK_STREAM or SOCK_DGRAM mode. # # Both drivers have a single required argument # specifying the name of the socket to connect to, and # no optional arguments. #---------------------------------------------------------------------- #---------------------------------------------------------------------- # Standard Log file locations #---------------------------------------------------------------------- destination authlog { file("/var/log/auth.log"); }; destination bootlog { file("/var/log/boot.log"); }; destination debug { file("/var/log/debug"); }; destination explan { file("/var/log/explanations"); }; destination messages { file("/var/log/messages"); }; destination routers { file("/var/log/routers.log"); }; destination secure { file("/var/log/secure"); }; destination spooler { file("/var/log/spooler"); }; destination syslog { file("/var/log/syslog"); }; destination user { file("/var/log/user.log"); }; #---------------------------------------------------------------------- # Special catch all destination sorting by host #---------------------------------------------------------------------- destination hosts { file("/var/log/HOSTS/$HOST/$YEAR/$MONTH/$DAY/$FACILITY_$HOST_$YEAR_$MONTH_$DAY" owner(root) group(root) perm(0600) dir_perm(0700) create_dirs(yes)); }; #---------------------------------------------------------------------- # Forward to a loghost server #---------------------------------------------------------------------- #destination loghost { udp("10.1.1.254" port(514)); }; #---------------------------------------------------------------------- # Mail subsystem logs #---------------------------------------------------------------------- destination mail { file("/var/log/mail.log"); }; destination mailerr { file("/var/log/mail/errors"); }; destination mailinfo { file("/var/log/mail/info"); }; destination mailwarn { file("/var/log/mail/warnings"); }; #---------------------------------------------------------------------- # INN news subsystem #---------------------------------------------------------------------- destination newscrit { file("/var/log/news/critical"); }; destination newserr { file("/var/log/news/errors"); }; destination newsnotice { file("/var/log/news/notice"); }; destination newswarn { file("/var/log/news/warnings"); }; #---------------------------------------------------------------------- # Cron subsystem #---------------------------------------------------------------------- destination cron { file("/var/log/cron.log"); }; destination crondebug { file("/var/log/cron/debug"); }; destination cronerr { file("/var/log/cron/errors"); }; destination croninfo { file("/var/log/cron/info"); }; destination cronwarn { file("/var/log/cron/warnings"); }; #---------------------------------------------------------------------- # LPR subsystem #---------------------------------------------------------------------- destination lpr { file("/var/log/lpr.log"); }; destination lprerr { file("/var/log/lpr/errors"); }; destination lprinfo { file("/var/log/lpr/info"); }; destination lprwarn { file("/var/log/lpr/warnings"); }; #---------------------------------------------------------------------- # Kernel messages #---------------------------------------------------------------------- destination kern { file("/var/log/kern.log"); }; destination kernerr { file("/var/log/kernel/errors"); }; destination kerninfo { file("/var/log/kernel/info"); }; destination kernwarn { file("/var/log/kernel/warnings"); }; #---------------------------------------------------------------------- # Daemon messages #---------------------------------------------------------------------- destination daemon { file("/var/log/daemon.log"); }; destination daemonerr { file("/var/log/daemons/errors"); }; destination daemoninfo { file("/var/log/daemons/info"); }; destination daemonwarn { file("/var/log/daemons/warnings"); }; #---------------------------------------------------------------------- # Console warnings #---------------------------------------------------------------------- destination console { file("/dev/tty12"); }; #---------------------------------------------------------------------- # All users #---------------------------------------------------------------------- destination users { usertty("*"); }; #---------------------------------------------------------------------- # Examples of programs that accept syslog messages and do something # programatically with them. #---------------------------------------------------------------------- #destination mail-alert { program("/usr/local/bin/syslog-mail"); }; #destination mail-perl { program("/usr/local/bin/syslog-mail-perl"); }; #---------------------------------------------------------------------- # Piping to Swatch #---------------------------------------------------------------------- #destination swatch { program("/usr/bin/swatch --read-pipe=\"cat /dev/fd/0\""); }; #---------------------------------------------------------------------- # Database notes: # # Overall there seems to be three primary methods of putting data from # syslog-ng into a database. Each of these has certain pros and cons. # # FIFO file: Simply piping the template data into a First In, First # Out file. This will create a stream of data that will # not require any sort of marker or identifier of how # much data has been read. This is the most elegant of # the solutions and probably the most unstable. # # Pros: Very fast data writes and reads. Data being # inserted into a database will be near real # time. # # Cons: Least stable of all the possible solutions, # and could require a lot of custom work to # make function on any particular Unix system. # # Loss of the pipe file will cause complete # data loss, and all following data that would # have been written to the FIFO file. # # Buffer file: While very similar to a FIFO file this is would be a # text file which would buffer all the template # output information. Another program from cron or # similar service would then run and source the buffer # files and process the data into the database. # # Pros: Little chance of losing data since everything # will be written to a physical file much like # the regular logging process. # # This method gives a tremendous amount of # flexibility since there would be yet another # opportunity to filter logs prior to inserting # any data into the database. # # Cons: Because there must be some interval between # the processing of the buffer files, there will # be a lag before the data is inserted in to the # database. # # There is also a slight chance of data corruption # (ie bad insert command) if the system crashes # during a write, although this scenero is very # unlikely. # # Another possible issue is that because multiple # buffer files be written, the previously run # sourcing file could get behind the data # insertion if there is a very large quantity of # logs being written. This will totally depend # on the system that this is running on. # # Program: The least elegant of the solutions. This method is to # send the stream of data through some further interrupter # program such as something in Perl or C. That program # will then take some action based off the data which # could include writing to a database similarly to the # program "sqlsyslogd". # # Pros: Allows complete control of the data, and as much # post processing as required. # # Cons: Slowest of all the forms. Since the data will # have to go through some post processing it will # cause data being written to the database to # remain behind actual log records. This could # cause a race condition in that logging is lost # either due to system crash, or high load on # the logging system. # #---------------------------------------------------------------------- #---------------------------------------------------------------------- # Writing to a MySQL database: # # Assumes a table/database structure of: # # CREATE DATABASE syslog; # USE syslog; # # CREATE TABLE logs ( host varchar(32) default NULL, # facility varchar(10) default NULL, # priority varchar(10) default NULL, # level varchar(10) default NULL, # tag varchar(10) default NULL, # date date default NULL, # time time default NULL, # program varchar(15) default NULL, # msg text, seq int(10) unsigned NOT NULL auto_increment, # PRIMARY KEY (seq), # KEY host (host), # KEY seq (seq), # KEY program (program), # KEY time (time), # KEY date (date), # KEY priority (priority), # KEY facility (facility)) # TYPE=MyISAM; # #---------------------------------------------------------------------- # Piping method #---------------------------------------------------------------------- #destination database { pipe("/tmp/mysql.pipe" # template("INSERT INTO logs (host, facility, # priority, level, tag, date, time, program, # msg) VALUES ( '$HOST', '$FACILITY', '$PRIORITY', # '$LEVEL', '$TAG', '$YEAR-$MONTH-$DAY', # '$HOUR:$MIN:$SEC', '$PROGRAM', '$MSG' );\n") # template-escape(yes)); }; #---------------------------------------------------------------------- # Buffer file method #---------------------------------------------------------------------- destination database { file("/var/log/dblog/fulllog.$YEAR.$MONTH.$DAY.$HOUR.$MIN.$SEC" template("INSERT INTO logs (host, facility, priority, level, tag, date, time, program, msg) VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG', '$YEAR-$MONTH-$DAY', '$HOUR:$MIN:$SEC', '$PROGRAM', '$MSG' );\n") owner(root) group(root) perm(0600) dir_perm(0700) create_dirs(yes) template-escape(yes)); }; #---------------------------------------------------------------------- # Program method (alternate using sqlsyslogd): # # Notes: This is not a bad process, but lacks very much flexibility # unless more changes are made to the source of sqlsyslogd. # This is because sqlsyslogd assumes the data in a larger # object style instead of breaking it down into smaller # columnar pieces. #---------------------------------------------------------------------- #destination database { program("/usr/local/sbin/sqlsyslogd -u # sqlsyslogd -t logs sqlsyslogs2 -p"); }; #---------------------------------------------------------------------- # Since we probably will not be putting ALL of our logs in the database # we better plan on capturing that data that we will be discarding for # later review to insure we did not throw anything away we really # should have captured. #---------------------------------------------------------------------- destination db_discard { file("/var/log/discard.log"); }; #---------------------------------------------------------------------- # Filters #---------------------------------------------------------------------- # # Functions: # # Name Synopsis Description # -------------- ------------------------------ -------------------- # facility facility(facility[,facility]) Match messages # having one of the # listed facility code. # filter Call another filter rule and # evaluate its value # host host(regexp) Match messages by # using a regular # expression against # the hostname field # of log messages. # level/priority level(pri[,pri1..pri2[,pri3]]) Match messages based # on priority. # match Tries to match a regular # expression to the message # itself. # program program(regexp) Match messages by # using a regular # expression against # the program name # field of log messages #---------------------------------------------------------------------- # NOTES: # # Getting filtering to work right can be difficult because while the # syntax is fairly simple, it is not well documented. To illustrate # a brief lesson on filtering and to explain the majority of the # mechanics, we shall use the filter from the PostgreSQL database # how-to page found at: http://www.umialumni.com/~ben/SYSLOG-DOC.html # # This is a perfect and somewhat complex example to use. In its # original form it resembles: # # filter f_postgres { not( # (host("syslogdb") and facility(cron) and level(info)) # or (facility(user) and level(notice) # and ( match(" gethostbyaddr: ") # or match("last message repeated ") # ) # ) # or ( facility(local3) and level(notice) # and match(" SYSMON NORMAL ")) # or ( facility(mail) and level(warning) # and match(" writable directory") # ) # or ( ( host("dbserv1.somecompany.com") # or host("dbserv2.somecompany.com") # ) # and facility(auth) and level(info) # and match("su oracle") and match(" succeeded for root on /dev/") # ) # ); }; # # While in this form, it does not induce a tremendous amount of # insight on what the specific filter is attempting to accomplish. In # reformatting the filter to resemble something a bit more human # readable, it would look like: # # filter f_postgres { not # ( # ( # host("syslogdb") and # facility(cron) and # level(info) # ) or # ( # facility(user) and # level(notice) and # ( # match(" gethostbyaddr: ") or # match("last message repeated ") # ) # ) or # ( # facility(local3) and # level(notice) and # match(" SYSMON NORMAL ") # ) or # ( # facility(mail) and # level(warning) and # match(" writable directory") # ) or # ( # ( # host("dbserv1.somecompany.com") or # host("dbserv2.somecompany.com") # ) and # facility(auth) and # level(info) and # match("su oracle") and # match(" succeeded for root on /dev/") # ) # ); # }; # # Now in this form we can now begin to see what this filter has been # attempting to accomplish. We can now further breakdown each logical # section and explain the different methods: # # [1] As in all statements in syslog-ng, each of the beginnings and # endings must be with a curly bracket "{" "}" to clearly denote # the start and finish. # # In this filter, the entire filter is preferred by a "not" to # indicate that these are the messages that we are NOT interested # in and should be the ones filtered out. All lines of logs that # do not match these lines will be sent to the destination. # # { not # # [2] The first major part of the filter is actually a compound # filter that has two parts. Because the two parts are separated # by an "or", only one of the two parts must be matched for that # line of log to be filtered. # # [2a] In the first part of this filter there are three requirements # to be met for the filter to take affect. These are the host # string "syslogdb". the facility "cron", and the syslog level # of info. # # ( # ( # host("syslogdb") and # facility(cron) and # level(info) # ) or # # [2b] In the second part of the filter, which in itself is a # compound filter, there are three requirements as well. These # are that the facility of "user", and the log level of "notice" # are met in addition to one of the two string matches that are # shown in the example. # # ( # facility(user) and # level(notice) and # ( # match(" gethostbyaddr: ") or # match("last message repeated ") # ) # ) or # # [3] In the section of the filter there are once again three # requirements to fire off a match which are a facility of "level3" # a log level of "notice" and a sting match of " SYSMON NORMAL ". # # ( # facility(local3) and # level(notice) and # match(" SYSMON NORMAL ") # ) or # # [4] This part of the filter is very similar to the previous # filter, but with different search patterns. # # ( # facility(mail) and # level(warning) and # match(" writable directory") # ) or # # [5] The last section of the filter is also a compound filter # that to take affect will require that one of two hosts # are matched, the facility of "auth", and log level of # "info" occur in addition to the two string matches. # # ( # ( # host("dbserv1.somecompany.com") or # host("dbserv2.somecompany.com") # ) and # facility(auth) and # level(info) and # match("su oracle") and # match(" succeeded for root on /dev/") # ) # # [6] As in all command sets in syslog-ng, each of the statements # must be properly closed with the correct ending punctuation # AND a semi-colon. Do not forget both, or you will be faced with # an error. # # ); }; # # While this may not be the most complete example, it does cover the # majority of the options and features that are available within the # current version of syslog-ng. #---------------------------------------------------------------------- #---------------------------------------------------------------------- # Standard filters for the standard destinations. #---------------------------------------------------------------------- filter f_auth { facility(auth, authpriv); }; filter f_authpriv { facility(authpriv); }; filter f_cron { facility(cron); }; filter f_daemon { facility(daemon); }; filter f_kern { facility(kern); }; filter f_local1 { facility(local1); }; filter f_local2 { facility(local2); }; filter f_local3 { facility(local3); }; filter f_local4 { facility(local4); }; filter f_local5 { facility(local5); }; filter f_local6 { facility(local6); }; filter f_local7 { facility(local7); }; filter f_lpr { facility(lpr); }; filter f_mail { facility(mail); }; filter f_messages { facility(daemon, kern, user); }; filter f_news { facility(news); }; filter f_spooler { facility(uucp,news) and level(crit); }; filter f_syslog { not facility(auth, authpriv) and not facility(mail); }; filter f_user { facility(user); }; #---------------------------------------------------------------------- # Other catch-all filters #---------------------------------------------------------------------- filter f_crit { level(crit); }; #filter f_debug { not facility(auth, authpriv, news, mail); }; filter f_debug { level(debug); }; filter f_emergency { level(emerg); }; filter f_err { level(err); }; filter f_info { level(info); }; filter f_notice { level(notice); }; filter f_warn { level(warn); }; #---------------------------------------------------------------------- # Filer for the MySQL database pipe. These are things that we really # do not care to see otherwise they may fill up our database with # garbage. #---------------------------------------------------------------------- #filter f_db { not facility(kern) and level(info, warning) or # not facility(user) and level(notice) or # not facility(local2) and level(debug); }; # #filter f_db { not match("last message repeated ") or # not match("emulate rawmode for keycode"); }; # #filter f_discard { facility(kern) and level(info, warning) or # facility(user) and level(notice) or # facility(local2) and level(debug); }; # #filter f_discard { match("last message repeated ") or # match("emulate rawmode for keycode"); }; #---------------------------------------------------------------------- # Logging #---------------------------------------------------------------------- # # Notes: When applying filters, remember that each subsequent filter # acts as a filter on the previous data flow. This means that # if the first filter limits the flow to only data from the # auth system, a subsequent filter for authpriv will cause # no data to be written. An example of this would be: # # log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); # source(s_udp); filter(f_auth); # filter(f_authpriv); destination(authlog); }; # # So, one can cancel out the other. # # There are also certain flags that can be attached to each of the log # statements: # # Flag Description # -------- ---------------------------------------------------------- # catchall This flag means that the source of the message is ignored, # only the filters are taken into account when matching # messages. # fallback This flag makes a log statement 'fallback'. Being a # fallback statement means that only messages not matching # any 'non-fallback' log statements will be dispatched. # final This flag means that the processing of log statements ends # here. Note that this doesn't necessarily mean that # matching messages will be stored once, as they can be # matching log statements processed prior the current one. #---------------------------------------------------------------------- #---------------------------------------------------------------------- # Standard logging #---------------------------------------------------------------------- log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_auth); destination(authlog); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_local7); destination(bootlog); }; #log{ source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); # source(s_udp); filter(f_debug); destination(debug); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_local1); destination(explan); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_local5); destination(routers); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_messages); destination(messages); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_authpriv); destination(secure); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_spooler); destination(spooler); }; log { source(s_dgram); source(s_internal); source(s_kernel); source(s_tcp); filter(f_syslog); destination(syslog); }; #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); # source(s_udp); destination(syslog); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_user); destination(user); }; #---------------------------------------------------------------------- # Special catch all destination sorting by host #---------------------------------------------------------------------- log { source(s_dgram); source(s_internal); source(s_kernel); source(s_tcp); destination(hosts); }; #---------------------------------------------------------------------- # Send to a loghost #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); destination(loghost); }; #---------------------------------------------------------------------- # Mail subsystem logging #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); # source(s_udp); filter(f_mail); destination(mail); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_mail); filter(f_err); destination(mailerr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_mail); filter(f_info); destination(mailinfo); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_mail); filter(f_notice); destination(mailinfo); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_mail); filter(f_warn); destination(mailwarn); }; #---------------------------------------------------------------------- # INN subsystem logging #---------------------------------------------------------------------- log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_news); filter(f_crit); destination(newscrit); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_news); filter(f_err); destination(newserr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_news); filter(f_notice); destination(newsnotice); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_news); filter(f_warn); destination(newswarn); }; #---------------------------------------------------------------------- # Cron subsystem logging #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_tcp); # source(s_udp); filter(f_cron); destination(crondebug); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_cron); filter(f_err); destination(cronerr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_cron); filter(f_info); destination(croninfo); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_cron); filter(f_warn); destination(cronwarn); }; #---------------------------------------------------------------------- # LPR subsystem logging #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_tcp); # source(s_udp); filter(f_lpr); destination(lpr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_lpr); filter(f_err); destination(lprerr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_lpr); filter(f_info); destination(lprinfo); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_lpr); filter(f_warn); destination(lprwarn); }; #---------------------------------------------------------------------- # Kernel subsystem logging #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); # source(s_udp); filter(f_kern); destination(kern); }; log { source(s_dgram); source(s_internal); source(s_kernel); source(s_tcp); filter(f_kern); filter(f_err); destination(kernerr); }; log { source(s_dgram); source(s_internal); source(s_kernel); source(s_tcp); filter(f_kern); filter(f_info); destination(kerninfo); }; log { source(s_dgram); source(s_internal); source(s_kernel); source(s_tcp); filter(f_kern); filter(f_warn); destination(kernwarn); }; #---------------------------------------------------------------------- # Daemon subsystem logging #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_tcp); # source(s_udp); filter(f_daemon); destination(daemon); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_daemon); filter(f_err); destination(daemonerr); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_daemon); filter(f_info); destination(daemoninfo); }; log { source(s_dgram); source(s_internal); source(s_tcp); filter(f_daemon); filter(f_warn); destination(daemonwarn); }; #---------------------------------------------------------------------- # Console logging #---------------------------------------------------------------------- # 16-Mar-03 - REP - Removed logging to the console for performance # reasons. Since we are not really going to be # looking at the console all the time, why log there # anyway. #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); filter(f_syslog); destination(console); }; #---------------------------------------------------------------------- # Logging to a database #---------------------------------------------------------------------- #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); filter(f_db); destination(database); }; #log { source(s_dgram); # source(s_internal); # source(s_kernel); # source(s_tcp); filter(f_discard); destination(db_discard); }; syslog-ng-syslog-ng-4.4.0/contrib/syslog2ng000077500000000000000000000077531450431004300207040ustar00rootroot00000000000000#!/usr/bin/awk -f # # syslog2ng # # Translator from syslog.conf to syslog-ng.conf # by Jonathan W. Marks # # Rev 2.1 BEGIN { # Handle the various platforms- determine proper log device "uname -s" | getline sysname; close("uname -s"); if (sysname == "SunOS") { LOGDEVTYPE="sun-streams"; LOGDEVPATH="/dev/log"; } else if (sysname == "AIX") { LOGDEVTYPE="unix-dgram"; LOGDEVPATH="/dev/log"; } else if (sysname == "Linux") { LOGDEVTYPE="unix-stream"; LOGDEVPATH="/dev/log"; } else if (sysname == "NetBSD") { LOGDEVTYPE="unix-dgram"; LOGDEVPATH="/var/run/log"; } else { print "!!! Unsupported system: " sysname "."; exit 1; } # Output the basic options and source statement. print \ "options { dir_perm(0755); perm(0644); chain_hostnames(no);\n" \ " keep_hostname(yes); };\n"; print \ "source local {\n" \ " " LOGDEVTYPE "(\"" LOGDEVPATH "\");\n" \ " udp(ip(0.0.0.0) port(514));\n" \ " internal();\n" \ "};\n"; } $1 !~ /^[:space:]*#/ && NF == 2 { # Output a comment with the line being translated. print "# " $0 "\n"; # Output any new filters to be created, saving filter ID numbers # needed by destination requiredFilterNos = make_filters($1); # Output the destination to be used, saving destination ID number destNo = make_destination($2) # Output the log path, connecting the required filters to the # destination. make_log(destNo, requiredFilterNos); } function make_filters(filterstr, filterNumbers) { # Split the components of the filter specifier. For each component, # generate the appropriate filter, and collect the filter numbers. split(filterstr, termlist, ";"); for (termNo in termlist) { newNum = make_filter(termlist[termNo]); filterNumbers = filterNumbers " " newNum; } return filterNumbers; } function make_filter(spec, negate) { # Find the severity and facility list. dot = index(spec, "."); severity = substr(spec, (dot + 1)); split(substr(spec, 1, (dot - 1)), faclist, ","); if (severity == "none") { negate = 1 }; if (severity == "*") { severity = "debug" }; # Create an ID string using severity and facility list to hash # into all_filters. Then we can tell whether weve already built # a filter like this. filterID = severity; for (facno in faclist) { filterID = filterID " " faclist[facno]; } # If this is a new filter, output the syslog-ng directives for it # and save its ID and number in all_filters. if (! (filterID in all_filters)) { all_filters[filterID] = ++filterNum; printf "filter f_" filterNum " {\n\t"; nPrinted = 0; # If using all facilities, no need to include them all in # filter-- its really only a filter based on severity if (faclist[1] != "*") { printf("%sfacility(", (negate ? "not " : "")); for (facno in faclist) { printf("%s" faclist[facno], \ (nPrinted++ > 0 ? "," : "")); } printf(")%s", (severity != "none" ? " and " : "")); } if (severity != "none") { printf("level(" severity "%s)", (severity == "emerg" ? "" : "..emerg")); } printf(";\n};\n\n"); } return all_filters[filterID]; } function make_destination(d, destNo) { # If weve already built this destination, dont do it again. # Just return the ID number. if (d in destinations) { return destinations[d]; } # Remember the destination ID number in case we need it again. destNo = ++dno; destinations[d] = destNo; # Output the syslog-ng directive for the destination. printf "destination d_" destNo " { \n"; if (d ~ /^\//) { printf "\tfile(\"" d "\" create_dirs(yes));\n"; } else if (d ~ /^@/) { printf "\tudp(\"" substr(d, 2) "\" port(514));\n"; } else { printf "\tusertty(\"" d "\");\n"; } print "};\n"; return destNo; } function make_log(destNo, filterNos) { # Note the destination number and filter numbers, then output # a syslog-ng directive connecting them. n_entries = split(filterNos, filters, " "); printf "log { source(local); " ; for (i = 1; i <= n_entries; i++) { printf "filter(f_" filters[i] "); "; } print "destination(d_" destNo "); };\n"; } syslog-ng-syslog-ng-4.4.0/contrib/systemd/000077500000000000000000000000001450431004300205035ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/systemd/syslog-ng@.service000066400000000000000000000011701450431004300241060ustar00rootroot00000000000000[Unit] Description=System Logger Daemon "%i" instance Documentation=man:syslog-ng(8) Conflicts=emergency.service emergency.target Wants=network.target network-online.target After=network.target network-online.target [Service] Type=notify EnvironmentFile=-/etc/default/syslog-ng@%i EnvironmentFile=-/etc/sysconfig/syslog-ng@%i ExecStart=/usr/sbin/syslog-ng -F $OTHER_OPTIONS --cfgfile $CONFIG_FILE --control $CONTROL_FILE --persist-file $PERSIST_FILE --pidfile $PID_FILE ExecReload=/bin/kill -HUP $MAINPID StandardOutput=journal StandardError=journal Restart=on-failure [Install] DefaultInstance=default WantedBy=multi-user.target syslog-ng-syslog-ng-4.4.0/contrib/systemd/syslog-ng@default000066400000000000000000000002761450431004300240220ustar00rootroot00000000000000CONFIG_FILE=/etc/syslog-ng/syslog-ng.conf PERSIST_FILE=/var/lib/syslog-ng/syslog-ng.persist CONTROL_FILE=/var/run/syslog-ng.ctl PID_FILE=/var/run/syslog-ng.pid OTHER_OPTIONS="--enable-core" syslog-ng-syslog-ng-4.4.0/contrib/upstart/000077500000000000000000000000001450431004300205155ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/upstart/syslog-ng.conf.upstart000066400000000000000000000013131450431004300250050ustar00rootroot00000000000000# syslog-ng - system logging daemon # # syslog-ng is an replacement for the traditional syslog daemon, logging messages from applications description "system logging daemon" start on filesystem stop on runlevel [06] expect fork respawn script CONF="/etc/syslog-ng/syslog-ng.conf" CTRL="/var/lib/syslog-ng/syslog-ng.ctl" OPTS="" # Allow override of command/conf and opts by /etc/default/syslog-ng if [ -f /etc/default/$UPSTART_JOB ]; then . /etc/default/$UPSTART_JOB fi if ! [ -r "$CONF" ] ; then echo "Could not read ${CONF}: exiting" exit 1 fi exec /usr/sbin/syslog-ng --process-mode=background \ -f $CONF -c $CTRL \ -p /var/run/syslog-ng.pid $OPTS end script syslog-ng-syslog-ng-4.4.0/contrib/valgrind/000077500000000000000000000000001450431004300206215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/contrib/valgrind/syslog-ng.supp000066400000000000000000000065461450431004300234670ustar00rootroot00000000000000## Valgrind suppressions for syslog-ng ## by Gergely Nagy ## ## Some of these suppressions may shadow actual leaks (especially the ## SSL-related ones at the end), use them with caution! ## dlopen() leaks { suppress_dlopen_leak Memcheck:Leak fun:*alloc ... fun:dlopen } { suppress_dlopen_leak2 Memcheck:Leak fun:*alloc ... fun:dl_open_worker fun:_dl_catch_error } ## Miscellaneous non-leaks and false alarms { suppress_journald_open: see https://github.com/systemd/systemd/issues/6539 Memcheck:Leak ... fun:journald_open ... } { suppress_syslog_ng_set_argv_space Memcheck:Leak fun:*alloc ... fun:g_process_set_argv_space } { suppress_syslog_ng_iv_work_pool_create Memcheck:Leak fun:*alloc fun:iv_work_pool_create fun:main_loop_io_worker_init fun:main_loop_init fun:main } { suppress_syslog_ng_app_startup Memcheck:Leak fun:*alloc ... fun:app_startup fun:main } { suppress_syslog_ng_option_context_parse Memcheck:Leak fun:*alloc ... fun:g_option_context_parse fun:main } { suppress_syslog_ng_dlopen_module Memcheck:Leak fun:*alloc ... fun:plugin_dlopen_module } { suppress_syslog_ng_plugin_load_module Memcheck:Leak fun:*alloc ... fun:plugin_load_module } { suppress_syslog_ng_plugin_discover_candidate_modules Memcheck:Leak fun:*alloc ... fun:plugin_discover_candidate_modules } { suppress_syslog_ng_g_private_set Memcheck:Leak fun:*alloc ... fun:g_private_set ... fun:clone } { suppress_syslog_ng_msg_limit_internal_message Memcheck:Leak fun:*alloc ... fun:msg_limit_internal_message ... fun:main } { suppress_syslog_ng_main_loop_msg_event_create Memcheck:Leak fun:*alloc ... fun:msg_event_create fun:main_loop_run } { supperess_syslog_ng_log_msg_new_internal Memcheck:Leak fun:*alloc ... fun:log_msg_new_internal } { suppress_syslog_ng_g_process_change_limits Memcheck:Leak fun:*alloc ... fun:g_process_change_limits } ################################################################## ### NOTE: These suppressions may shadow actual memory leaks! ### ### Disable them if you wish to debug SSL-related leaks. ### ################################################################## ## libssl/libcrypto leaks we don't care about { suppress_crypto_SSL_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* fun:SSL_* } { suppress_crypto_RSA_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* fun:RSA_* } { suppress_crypto_BIO_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* fun:BIO_* } { suppress_crypto_OCSP_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* fun:OCSP_* } ## TLS/SSL related syslog-ng leaks { suppress_syslog_ng_crypto_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* ... obj:*/libsyslog-ng-crypto.so } { suppress_syslog_ng_afsocket_ssl_leaks Memcheck:Leak fun:*alloc ... obj:*/libssl.so.* ... obj:*/libafsocket-tls.so } { suppress_syslog_ng_afsocket_crypto_leaks Memcheck:Leak fun:*alloc ... obj:*/libcrypto.so.* ... obj:*/libafsocket-tls.so } syslog-ng-syslog-ng-4.4.0/dbld/000077500000000000000000000000001450431004300162605ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dbld/.dockerignore000066400000000000000000000000341450431004300207310ustar00rootroot00000000000000build/ release/ install/ *~ syslog-ng-syslog-ng-4.4.0/dbld/Makefile.am000066400000000000000000000023071450431004300203160ustar00rootroot00000000000000EXTRA_DIST += \ dbld/functions.sh \ dbld/tarball \ dbld/tarball-changes.ignore \ dbld/pkg-tarball \ dbld/package \ dbld/rpm \ dbld/deb \ dbld/generate-rpm-specfile \ dbld/generate-debian-directory \ dbld/prepare-image-build \ dbld/prepare-release \ dbld/builddeps \ dbld/shell \ dbld/rules \ dbld/bootstrap \ dbld/make \ dbld/build.manifest \ dbld/packages.manifest \ dbld/pip_packages.manifest \ dbld/images/entrypoint.sh \ dbld/images/fake-sudo.sh \ dbld/images/gosu.pubkey \ dbld/images/yum-builddep.sha1 \ dbld/images/debian.prepare.sh \ dbld/images/ubuntu.prepare.sh \ dbld/images/centos.prepare.sh \ dbld/images/fedora.prepare.sh \ dbld/images/devshell.dockerfile \ dbld/images/centos-7.dockerfile \ dbld/images/fedora-37.dockerfile \ dbld/images/debian-buster.dockerfile \ dbld/images/debian-bullseye.dockerfile \ dbld/images/debian-bookworm.dockerfile \ dbld/images/debian-sid.dockerfile \ dbld/images/debian-testing.dockerfile \ dbld/images/ubuntu-focal.dockerfile \ dbld/images/ubuntu-jammy.dockerfile \ dbld/images/ubuntu-lunar.dockerfile \ dbld/images/kira.dockerfile \ dbld/images/tarball.dockerfile \ dbld/images/hooks/build \ dbld/images/README.md \ dbld/README.md syslog-ng-syslog-ng-4.4.0/dbld/README.md000066400000000000000000000117401450431004300175420ustar00rootroot00000000000000## Syslog-ng development/release environment powered by Docker With the help of the following tool you can - compile syslog-ng from source code - generate tarball (snapshot / release) - create OS specific packages in an isolated Docker container based environment. ## Usage information ```bash whoami@host:~/syslog-ng$ dbld/rules [help] ``` dbld/rules is the general entrypoint for the tool, specifying multiple targets. For the complete list of the available targets please run the command (without parameters it will run without any side effect), or read the source code on [GitHub](rules). Almost every `dbld/rules` command runs in a Docker container. You can use the pre-built containers from [GitHub](https://github.com/syslog-ng?tab=packages&repo_name=syslog-ng) or build your own images with the `dbld/rules image-` command. The source code and build products are mounted externally in the following locations: - **/source** -> syslog-ng/* - **/dbld** -> syslog-ng/dbld - **/build** -> syslog-ng/dbld/build - **/install** -> syslog-ng/dbld/install ## Examples ### Building syslog-ng from tarball using the 'tarball' image ```bash $ dbld/rules tarball $ Your tarball is in /build, also available on the host in $(top_srcdir)/dbld/build $ cd dbld/build $ tar -xzvf syslog-ng*.tar.gz $ ./syslog-ng-*/configure $ make ``` You can also build a DEB using: ```bash $ dbld/rules deb-ubuntu-focal ``` You can find the resulting debs in `$HOME/syslog-ng/dbld/build`. ### Hacking on syslog-ng itself You can also use the docker based shell to hack on syslog-ng by configuring and building manually. You can use any of the supported OSes as shells (e.g. shell-ubuntu-jammy or shell-centos-7) and there's "devshell" that contains a few extra tools, often needed during development. Steps for the manual build after entering into the containers shell: ```bash $ ./dbld/rules shell-devshell # inside the container $ cd /source/ # autogen.sh generates the configure script using autotools, you could also # use cmake (alternative build system, experimental) here. $ ./autogen.sh $ cd /build/ # run the configure script, there's a wrapper for this in /dbld/bootstrap # that will include extra options exported by dbld/rules. $ /source/configure --enable-debug --prefix=/install $ make $ make check $ make install ``` If the compilation and installation was successful you can run syslog-ng with the following command: ```bash $ /install/syslog-ng/sbin/syslog-ng -Fedv ``` ### Preparing a release The dbld tools also allow to prepare for a syslog-ng release. By default, when you generate a tarball/deb/rpm, dbld would generate a "snapshot" version (including a git commit id) to avoid mismatching it with a "real" release. If you instead want to do an "official-looking" release (e.g. 3.28.1 instead of 3.27.1.34.g83096fa.dirty), this is the procedure you have to follow. The syslog-ng team is using this to perform releases. ### Version bumps First of all, you will need to commit a patch that bumps the version number in a couple of places (e.g. the VERSION file in the root directory). Start with a git commit that you want to release (e.g the master branch), with no local changes. Version bumps are automated using the "prepare-release" target of dbld that can be invoked like this: ```bash $ ./dbld/rules prepare-release VERSION=3.28.1 ``` To see what prepare-release does automatically consult the script `dbld/prepare-release` in the source tree. `prepare-release` does not commit the changes, rather it leaves them for you to review and then commit. ### Performing a release Once the versions are bumped, that change is committed, the source tree is prepared for a release. You can do it via: ```bash $ ./dbld/rules release VERSION=3.28.1 ``` This will build: * a tarball, * automatically generates an up-to-date rpm/debian packaging, * build rpm/deb packages on their default platform * tag the current commit in git All artifacts (tarball, deb/rpm packages) are stored in `./dbld/release/` The script does not undertake publishing the artifacts or the tag in any way. It is expected that some kind of CI system will perform this (jenkins, travis, github-actions). ## sudo The `sudo` command is not available inside this development container. >Short explanation: > >Many of the image maintainers (mostly for security reasons) do not install the sudo package by default. Additionally (to avoid access problems to your repository outside of this container), we >- mount directories >- run commands > >inside this container using your external Username and ID. There are many options to circumvent this limitation (i.e. Create your own image, based on this one.), but probably the easiest way is to start a new privileged shell in the already running container, using `docker exec`. ```bash $ docker exec -it /bin/bash ``` > note: We installed a fake `sudo` command inside the container, which will print out a copy-paste ready version of the `docker exec` command in case someone accidentally calls it. syslog-ng-syslog-ng-4.4.0/dbld/bootstrap000077500000000000000000000002151450431004300202210ustar00rootroot00000000000000#!/bin/bash set -e cd /source ./autogen.sh cd /build echo "Running configure with: ${CONFIGURE_OPTS}" /source/configure ${CONFIGURE_OPTS} syslog-ng-syslog-ng-4.4.0/dbld/build.manifest000066400000000000000000000032541450431004300211130ustar00rootroot00000000000000# # build.manifest # # This file controls package building on various distros when using dbld. # # Syntax: # # OS env-list cmdline-options # # OS -- either Linux distribution name (e.g. ubuntu, centos # etc), or a distro + version combination separated by # a dash (e.g. ubuntu-bionic, centos-7, etc). If used # without version number, it denotes a wildcard (e.g. # applied to any versions of the distro). # # env-list -- comma separated list of environment variables # # cmdline-options -- extra command line options to supply to the build # command. # # The build command depends on the packaging system that specific Linux # distribution uses, e.g. rpmbuild for Fedora/CentOS, dpkg-buildpackage # for Debian based distros). env-list and cmdline-options can be used to # customize a build in cases where an optional feature is not available # there. # # kafka support needs librdkafka >= 1.0.0, which is only available on ubuntu-bionic # on Debian we don't build java and use Python3 _after_ buster # libcriterion-dev is available starting with bullseye debian-buster python3,nocriterion,nojava,nokafka,nomqtt,nogrpc,notzdatalegacy debian-bullseye python3,nojava,notzdatalegacy debian-bookworm python3,nojava,notzdatalegacy debian-testing python3,nojava debian-sid python3,nojava # on ubuntu, we start using Python3 at focal onwards. # libcriterion-dev is available starting with 21.04 ubuntu-focal python3,nocriterion,nomqtt,nogrpc,notzdatalegacy ubuntu-jammy python3,notzdatalegacy ubuntu-lunar python3 centos-7 python3 fedora python3 syslog-ng-syslog-ng-4.4.0/dbld/build/000077500000000000000000000000001450431004300173575ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dbld/build/.gitignore000066400000000000000000000003541450431004300213510ustar00rootroot00000000000000# The directory is kept due to docker creating the directory # if not exists with root permission. If the directory exists, # docker will not change the permission. # Ignore everything in this directory * # Except this file !.gitignore syslog-ng-syslog-ng-4.4.0/dbld/builddeps000077500000000000000000000201041450431004300201560ustar00rootroot00000000000000#!/bin/bash . /dbld/functions.sh DBLD_DIR=/dbld YUM_INSTALL="yum install -y" DNF_INSTALL="dnf install -y" APT_INSTALL="apt-get install -y --no-install-recommends" set -e set -x function workaround_rpm_repos() { MIRROR_URL='https://ftp.halifax.rwth-aachen.de/fedora/linux' case "${OS_DISTRIBUTION}" in fedora) # Workaround for often getting 503 from mirrors.fedoraproject.org. sed -i -e "/baseurl/c\baseurl=${MIRROR_URL}/releases/\$releasever/Everything/\$basearch/os/" /etc/yum.repos.d/fedora.repo sed -i -e "/baseurl/c\baseurl=${MIRROR_URL}/releases/\$releasever/Modular/\$basearch/os/" /etc/yum.repos.d/fedora-modular.repo sed -i -e "/baseurl/c\baseurl=${MIRROR_URL}/updates/\$releasever/Everything/\$basearch/" /etc/yum.repos.d/fedora-updates.repo sed -i -e "/baseurl/c\baseurl=${MIRROR_URL}/updates/\$releasever/Modular/\$basearch/" /etc/yum.repos.d/fedora-updates-modular.repo # we don't need h264 codecs sed -i -e "/enabled/c\enabled=0" /etc/yum.repos.d/fedora-cisco-openh264.repo ;; esac } # this function is run first and is responsible for installing stuff that is # needed by this script _before_ installing packages from packages.manifest. # # NOTE: If at all possible don't put anything here. function install_dbld_dependencies() { case "${OS_DISTRIBUTION}" in centos) $YUM_INSTALL wget yum-utils ;; debian|ubuntu) apt-get update $APT_INSTALL wget gnupg2 ;; fedora) $DNF_INSTALL -y wget dnf-plugins-core ;; esac } function install_cmake() { CMAKE_VERSION=3.12.2 CMAKE_SHORT_VERSION=$(echo ${CMAKE_VERSION} | cut -d"." -f1-2) download_target "https://cmake.org/files/v${CMAKE_SHORT_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.sh" /tmp/cmake.sh chmod +x /tmp/cmake.sh mkdir -p /opt/cmake /tmp/cmake.sh --skip-license --prefix=/opt/cmake/ ln -s /opt/cmake/bin/cmake /usr/bin/cmake rm -rf /tmp/cmake.sh } function install_criterion() { CRITERION_VERSION=2.3.3 download_target "https://github.com/Snaipe/Criterion/releases/download/v${CRITERION_VERSION}/criterion-v${CRITERION_VERSION}.tar.bz2" /tmp/criterion.tar.bz2 cd /tmp/ tar xvf /tmp/criterion.tar.bz2 cd /tmp/criterion-v${CRITERION_VERSION} cmake -DCMAKE_INSTALL_PREFIX=/usr . make install ldconfig rm -rf /tmp/criterion.tar.bz2 /tmp/criterion-v${CRITERION_VERSION} } function install_gosu() { GOSU_VERSION=1.10 ARCHITECTURE=$1 cat $DBLD_DIR/images/gosu.pubkey | gpg --import download_target "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${ARCHITECTURE}" /usr/local/bin/gosu download_target "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${ARCHITECTURE}.asc" /usr/local/bin/gosu.asc gpg --verify /usr/local/bin/gosu.asc rm /usr/local/bin/gosu.asc chmod +x /usr/local/bin/gosu } function set_jvm_paths() { find / -name 'libjvm.so' | sed 's@/libjvm.so@@g' | tee --append /etc/ld.so.conf.d/openjdk-libjvm.conf ldconfig } function install_gradle { GRADLE_VERSION=4.10 download_target "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" /tmp/gradle.zip mkdir -p /opt/gradle unzip -d /opt/gradle /tmp/gradle.zip rm -rf /tmp/gradle.zip ln -s /opt/gradle/gradle-${GRADLE_VERSION}/bin/gradle /usr/bin/gradle find / -name 'libjvm.so' | sed 's@/libjvm.so@@g' | tee --append /etc/ld.so.conf.d/openjdk-libjvm.conf ldconfig } function install_pip2 { download_target "https://bootstrap.pypa.io/pip/2.7/get-pip.py" get-pip.py python2 get-pip.py } function download_target() { target=$1 output=$2 wget --no-check-certificate $target --output-document=$output } function filter_packages_by_platform { FILENAME=$1 grep -v "#" ${FILENAME} | grep -e "${IMAGE_PLATFORM}" -e "${OS_DISTRIBUTION}[^-]" | cut -d"[" -f1 } function filter_pip_packages_by_platform_and_python_version { FILENAME=$1 PYTHON_VERSION=$2 grep -v "#" ${FILENAME} | grep -e "${IMAGE_PLATFORM}" -e "${OS_DISTRIBUTION}[^-]" | grep -e "${PYTHON_VERSION}" | cut -d"[" -f1 } function add_copr_repo { # NOTE: we are removing dnf/yum plugins after enabling copr as they # install a couple of Python dependencies which then conflict with our # PIP installation later. case "${OS_DISTRIBUTION}" in centos) $YUM_INSTALL yum-plugin-copr yum copr enable -y czanik/syslog-ng-githead ;; fedora) $DNF_INSTALL -y dnf-plugins-core dnf copr enable -y czanik/syslog-ng-githead ;; esac } function add_epel_repo { $YUM_INSTALL epel-release } function install_apt_packages { apt-get update -qq -o Acquire::CompressionTypes::Order::=gz filter_packages_by_platform $DBLD_DIR/packages.manifest | xargs -t $APT_INSTALL --yes } function install_debian_build_deps { DEBIAN_CONTROL_FILE="${DBLD_DIR}/extra-files/${IMAGE_PLATFORM}/packaging-debian-control" if ! [ -f ${DEBIAN_CONTROL_FILE} ]; then echo "install_debian_build_deps() called from dockerfile but without a Debian control file, make sure that control file is copied over to ${DEBIAN_CONTROL_FILE} by the prepare step" exit 1 fi deb_run_build_command mk-build-deps -i ${DEBIAN_CONTROL_FILE} -t "apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends" } function install_rpm_build_deps { RPM_SPEC_FILE="${DBLD_DIR}/extra-files/${IMAGE_PLATFORM}/syslog-ng.spec" if ! [ -f ${RPM_SPEC_FILE} ]; then echo "install_rpm_build_deps() called from dockerfile but without a syslog-ng.spec file, make sure that control file is copied over to ${RPM_SPEC_FILE} by the prepare step" exit 1 fi case "${OS_DISTRIBUTION}" in centos) rpm_run_build_command yum-builddep -y ${RPM_SPEC_FILE} ;; fedora) rpm_run_build_command dnf builddep -y ${RPM_SPEC_FILE} ;; esac } function install_yum_packages { $YUM_INSTALL findutils filter_packages_by_platform $DBLD_DIR/packages.manifest | xargs $YUM_INSTALL } function install_pip_packages { local python_executables="python2 python3" for python_executable in ${python_executables}; do local pip_install="${python_executable} -m pip install --ignore-installed --no-cache-dir --upgrade" ${pip_install} "pip" ${pip_install} "setuptools<66.0" filter_pip_packages_by_platform_and_python_version $DBLD_DIR/pip_packages.manifest ${python_executable} | xargs ${pip_install} done } function install_lsb_release { apt-get update && $APT_INSTALL lsb-release } function enable_dbgsyms { install_lsb_release case "${OS_DISTRIBUTION}" in ubuntu) echo "deb http://ddebs.ubuntu.com ${OS_DISTRIBUTION_CODE_NAME} main restricted universe multiverse" | tee -a /etc/apt/sources.list.d/ddebs.list echo "deb http://ddebs.ubuntu.com ${OS_DISTRIBUTION_CODE_NAME}-updates main restricted universe multiverse" | tee -a /etc/apt/sources.list.d/ddebs.list apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 428D7C01 C8CAB6595FDFF622 ;; debian) echo "deb http://deb.debian.org/debian-debug/ ${OS_DISTRIBUTION_CODE_NAME}-debug main" | tee -a /etc/apt/sources.list echo "deb http://deb.debian.org/debian-debug/ ${OS_DISTRIBUTION_CODE_NAME}-proposed-updates-debug main" | tee -a /etc/apt/sources.list ;; esac } function install_perf { case "${OS_DISTRIBUTION}" in ubuntu) apt-cache search linux-tools | grep 'linux-tools-.*-generic' | cut -d" " -f1 | tail -n1 | cut -d"-" -f1-4 | xargs $APT_INSTALL ;; esac } function install_bison_from_source { BISON_VERSION=3.7.6 cd /tmp wget https://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz tar xvfz bison-${BISON_VERSION}.tar.gz cd bison-${BISON_VERSION} ./configure --prefix=/usr/local --disable-nls make && make install } # DO NOT REMOVE! "$@" syslog-ng-syslog-ng-4.4.0/dbld/deb000077500000000000000000000017011450431004300167370ustar00rootroot00000000000000#!/bin/bash . /dbld/functions.sh function setup_dirs() { rm -rf /build/${IMAGE_PLATFORM} && mkdir -p /build/${IMAGE_PLATFORM} } function prepare_source() { cd /build rm -rf syslog-ng-${VERSION} tar xf syslog-ng-${VERSION}.tar.gz # save the tarball as .orig.tar.gz so that dpkg-buildpackage finds it as the original source cp syslog-ng-${VERSION}.tar.gz syslog-ng_${VERSION}.orig.tar.gz } function capture_debs() { mv /build/*.deb /build/${IMAGE_PLATFORM} echo "Your debs are in /build/${IMAGE_PLATFORM}, also available on the host in \$(top_srcdir)/dbld/build/${IMAGE_PLATFORM}" capture_artifacts /build/${IMAGE_PLATFORM}/*.deb } cd /build validate_container setup_dirs prepare_source cd syslog-ng-${VERSION} if [ ! -d debian ]; then echo "You have no Debian packaging in debian/, this should already by in the tarball at this point" exit 1 fi deb_run_build_command dpkg-buildpackage -rfakeroot -d capture_debs syslog-ng-syslog-ng-4.4.0/dbld/distcheck000077500000000000000000000013141450431004300201460ustar00rootroot00000000000000#!/bin/bash -e . /dbld/functions.sh cd /source SYSLOGNG_DIR=syslog-ng-${VERSION} SYSLOGNG_TARBALL=${SYSLOGNG_DIR}.tar.gz ./autogen.sh # dist-build might be set to read-only by distcheck [ -d /build/dist-build ] && chmod +w -R /build/dist-build rm -rf /build/dist-build mkdir /build/dist-build cd /build/dist-build /source/configure --enable-manpages --disable-all-modules rm -rf /install/dist-check export DISTCHECK_CONFIGURE_FLAGS="CFLAGS=-Werror --prefix=/install/dist-check --with-ivykis=internal --with-jsonc=system --enable-tcp-wrapper --enable-linux-caps --enable-manpages --enable-all-modules --disable-java --disable-java-modules --with-python=3" make -j V=1 distcheck || echo "FAILED to run distcheck" syslog-ng-syslog-ng-4.4.0/dbld/functions.sh000066400000000000000000000107351450431004300206320ustar00rootroot00000000000000set -e function get_version() { [ -n "$VERSION" ] && echo $VERSION && return [ -d /source/scripts ] && cd /source && scripts/version.sh || echo "unknown-version" } function _map_cmdline_null() { echo -n "" } function _map_env_null() { echo "_=_" } function run_build_command_with_build_manifest_parameters() { map_environment=$1 map_cmdline=$2 shift 2 # we sort longer strings in front, to make more specific items # first. TMPDIR=$(mktemp -d) IFS=$'\t' egrep -e "^${OS_DISTRIBUTION}([^-]|$)" -e "^${IMAGE_PLATFORM}" /dbld/build.manifest | sort -r | head -1 | while read os featureflags env cmdline; do unset IFS echo $os $featureflags $env $cmdline declare -a env_values if [ "${env}" != "-" -a "${env}" != "" ]; then # xargs processes removes quote characters just like the shell echo "${env}" | tr ',' '\n' | xargs -n1 echo > $TMPDIR/env.list readarray -t env_values < $TMPDIR/env.list fi if [ "`${map_cmdline} ${featureflags}`" = "" ]; then # no extra command line values (e.g. deb), execute # it without them on the env command line. In this # case we supplied an extra, zero-length argument to # dpkg-buildpackage that it errored out on (understandably). # # I couldn't find a way to expand a variable in shell that # 1) was able to handle spaces in arguments # 2) could also represent no extra arguments (not even an empty one) # # that's why we are using this ugly if statement above and the # double evaluation of ${map_cmdline}. # echo "Runnign build as: " env "${env_values[@]}" "`${map_environment} ${featureflags}`" "$@" $cmdline env "${env_values[@]}" "`${map_environment} ${featureflags}`" "$@" $cmdline else ${map_cmdline} ${featureflags} | xargs -n1 echo > $TMPDIR/cmdline.list readarray -t cmdline_values < $TMPDIR/cmdline.list echo "Running build as: " env "${env_values[@]}" "`${map_environment} ${featureflags}`" "$@" $cmdline "${cmdline_values[@]}" env "${env_values[@]}" "`${map_environment} ${featureflags}`" "$@" $cmdline "${cmdline_values[@]}" fi done } function _map_feature_flags_to_deb_build_profiles() { echo -n DEB_BUILD_PROFILES= IFS=, for feature in $1; do case "$feature" in nojava|nopython) # these are standard Debian build profiles, keep them intact echo -n "$feature " ;; *) # everything else is prefixed with "sng-" echo -n "sng-$feature " ;; esac done echo } function deb_run_build_command() { run_build_command_with_build_manifest_parameters _map_feature_flags_to_deb_build_profiles _map_cmdline_null "$@" } function _map_feature_flags_to_rpmbuild_with_and_without_options() { IFS=, echo -n "--define='_dbld 1' " for feature in $1; do case "$feature" in no*) feature_without_no=`echo $feature | sed -e 's/^no//'` echo -n "--define='_without_${feature_without_no} --without-${feature_without_no}' " ;; *) echo -n "--define='_with_${feature} --with-${feature}' " ;; esac done } function rpm_run_build_command() { run_build_command_with_build_manifest_parameters _map_env_null _map_feature_flags_to_rpmbuild_with_and_without_options "$@" } function validate_man_binary() { MAN=`which man` if ! [ -x ${MAN} ]; then return 0 fi set +e man_help=$(${MAN} --help 2>&1) rc=$? set -e if [ "$rc" -ne 0 ]; then cat < | [Gosu](https://github.com/tianon/gosu) | We use gosu to drop root privileges inside the containers. | > Note: These functions can be found in [dbld/builddeps](/dbld/builddeps) ### fake sudo Just a simple `echo` command to make life easier. Reasons are explained in details in [/dbld/README.md](/dbld/README.md) ### volumes Creating the `/source` and `/build` folders for our work. (note: `install` folder will be placed inside the build folder) ### entrypoint Custom entrypoint script will create the user account inside the container, so you will not have any access problem with the mounted folders. # Package lists There are some helper functions to install special packages, but the main source of the dependencies are the `*.manifest` files. Lines started with # are comments, and will be ignored. The platform and/or distribution names inside [] brackets are indicating on which platforms the package will be installed. syslog-ng-syslog-ng-4.4.0/dbld/images/centos-7.dockerfile000066400000000000000000000014221450431004300232140ustar00rootroot00000000000000FROM centos:7 LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=centos ENV OS_DISTRIBUTION_CODE_NAME=7 ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps add_epel_repo RUN /dbld/builddeps add_copr_repo RUN /dbld/builddeps install_yum_packages RUN /dbld/builddeps install_rpm_build_deps RUN /dbld/builddeps install_criterion RUN /dbld/builddeps install_gradle RUN /dbld/builddeps install_gosu amd64 VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/centos.prepare.sh000066400000000000000000000001161450431004300230070ustar00rootroot00000000000000#!/bin/sh cp packaging/rhel/syslog-ng.spec ${EXTRA_FILES_DIR}/syslog-ng.spec syslog-ng-syslog-ng-4.4.0/dbld/images/debian-bookworm.dockerfile000066400000000000000000000013101450431004300246300ustar00rootroot00000000000000FROM debian:bookworm LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=debian ENV OS_DISTRIBUTION_CODE_NAME=bookworm ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/debian-bullseye.dockerfile000066400000000000000000000013101450431004300246150ustar00rootroot00000000000000FROM debian:bullseye LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=debian ENV OS_DISTRIBUTION_CODE_NAME=bullseye ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/debian-buster.dockerfile000066400000000000000000000013531450431004300243040ustar00rootroot00000000000000FROM debian:buster LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=debian ENV OS_DISTRIBUTION_CODE_NAME=buster ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps RUN /dbld/builddeps install_criterion VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/debian-sid.dockerfile000066400000000000000000000012761450431004300235630ustar00rootroot00000000000000FROM debian:sid LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=debian ENV OS_DISTRIBUTION_CODE_NAME=sid ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/debian-testing.dockerfile000066400000000000000000000013061450431004300244530ustar00rootroot00000000000000FROM debian:testing LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=debian ENV OS_DISTRIBUTION_CODE_NAME=testing ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/debian.prepare.sh000066400000000000000000000001231450431004300227340ustar00rootroot00000000000000#!/bin/sh cp packaging/debian/control ${EXTRA_FILES_DIR}/packaging-debian-control syslog-ng-syslog-ng-4.4.0/dbld/images/devshell.dockerfile000066400000000000000000000004271450431004300233670ustar00rootroot00000000000000ARG CONTAINER_REGISTRY FROM $CONTAINER_REGISTRY/dbld-tarball:latest ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} RUN /dbld/builddeps enable_dbgsyms RUN /dbld/builddeps install_perf RUN /dbld/builddeps install_apt_packages syslog-ng-syslog-ng-4.4.0/dbld/images/entrypoint.sh000077500000000000000000000015521450431004300223020ustar00rootroot00000000000000#!/bin/bash set -e SOURCE_DIR=/source USER_NAME=${USER_NAME_ON_HOST:-dockerguest} USER_ID=`stat -c '%u' $SOURCE_DIR` GROUP_NAME=$USER_NAME GROUP_ID=`stat -c '%g' $SOURCE_DIR` if [[ "$USER_ID" -eq 0 ]]; then "$@" else if ! getent passwd $USER_ID > /dev/null then groupadd --gid $GROUP_ID $GROUP_NAME &>/dev/null || \ groupadd --gid $GROUP_ID dockerguest &>/dev/null || \ echo "Failed to add group $GROUP_NAME/$GROUP_ID in docker entrypoint-debian.sh"; useradd $USER_NAME --uid=$USER_ID --gid=$GROUP_ID &>/dev/null || \ useradd dockerguest --uid=$USER_ID --gid=$GROUP_ID &>/dev/null || \ echo "Failed to add user $USER_NAME/$USER_ID in docker entrypoint-debian.sh"; mkdir -p /home/$USER_NAME chown $USER_NAME:$GROUP_ID /home/$USER_NAME fi exec gosu "${USER_NAME}" "$@" fi syslog-ng-syslog-ng-4.4.0/dbld/images/fake-sudo.sh000077500000000000000000000005201450431004300217370ustar00rootroot00000000000000#!/bin/bash CONTAINER_ID=$(cat /proc/self/cgroup | grep "docker" | cut -d'/' -f 3 | cut -c1-12 | sort -u | tail -1) DOCKER_COMMAND="docker exec -it ${CONTAINER_ID} /bin/bash" echo "sudo command is not available, to start a privileged shell inside this container, run the following command in a new terminal:" echo "${DOCKER_COMMAND}" syslog-ng-syslog-ng-4.4.0/dbld/images/fedora-37.dockerfile000066400000000000000000000014141450431004300232450ustar00rootroot00000000000000FROM fedora:37 LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=fedora ENV OS_DISTRIBUTION_CODE_NAME=37 ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps workaround_rpm_repos RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps add_copr_repo RUN /dbld/builddeps install_yum_packages RUN /dbld/builddeps install_rpm_build_deps RUN /dbld/builddeps install_criterion RUN /dbld/builddeps install_gradle RUN /dbld/builddeps install_gosu amd64 VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/fedora.prepare.sh000066400000000000000000000001161450431004300227540ustar00rootroot00000000000000#!/bin/sh cp packaging/rhel/syslog-ng.spec ${EXTRA_FILES_DIR}/syslog-ng.spec syslog-ng-syslog-ng-4.4.0/dbld/images/gosu.pubkey000066400000000000000000002430531450431004300217320ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFMQ+McBEADBj3C5hgBeWgnIeEMOPuFCwbdWZrwjgUYUMf0xkGeNpDIHlR9m leh3pi3yLEmofRtkQWa9cNqn63Zi5wrQLk+DLWUeLDW13SqB5JtY7tZJTpsI2gf4 q9XrUExzAv79+9P8ZieD4WE0mpGkSeIFQDfZ7Agc5wMEhO3xKjihtHgD6g5x6tk3 FLUfQk/YHib9xPr4C05ft3OLEa/FhTSEztvvHecBNgaoZesxdslrAVPrko0Z2BpW 1RNjfc3ow653psL/DOOLkSB8+/bXuRKRyCYhJbTg6BYiDPtRROnb5T3urtm9RflM HyTYf/+VcvdODyb0MPHp73SxVfBYSj2qixjkoA1jc9GTBVcKCTbq7jJtXppA9iaa gOYkq3GGOuO+zOOI4xqyPQDpyaViWGIy5D+4/cdZzqqJL+SnHTT835FsdEv+dg83 u22+8UjZaIBk21zNsjIgpj4JRyh1iFBZygMzfxv2bCb51EnjoPOoo6haj633lCOK pH3emV56AZZ+PTTGdUVDVfeF77FFTSDSb3slWKdsN1HnkusQkVNntJvMFbm5xioM ij65UYMF9LqTxRX7MZZi6RGxvjfWLzQ/sf3nhV/yzF8e3pA7dVKZUpkEXD8aui8A iE1lxC/QzoVLUYTcroEL24Ux+nf2uApGQKb4M17Pryi7F0AxEauTqHhA+QARAQAB tCBUaWFub24gR3JhdmkgPHRpYW5vbkBkZWJpYW4ub3JnPokCHAQQAQIABgUCVjFg qwAKCRC4Q+b9jTf96TLED/9UPIl/DOoPf9O719UJCucAOgs8URTjdDNtzN1mh+BH rwl5DIc9BYaduGg7CHCI9qXyPCZkotTWBwehprOG+nk010lLiBygBMaiD2xjBFbg jXMLnTSx93Pljssit7hIB4b21XJDA9esZ08F09juQLB/jNVzs8MYLUwI3gb5iWAV pm34qZIO123RsxAr0XH9pidPOz4v5Ei9lz/AiQJ/dM/ynS+NlrvBB6EeV88gzOMS WN7pL8HqAnLh93sNS0vmaMEvsq6KESVZgbMXRtJ0MIwi1EyTJHtjENeDFzFHQ1xV ChS0lhRU+bC1A/RwlxDmbgZjNgJ+PWT8+UwYtk89vW5aM7JuVl+7DMeSQJhoPwj0 3bL8H6LghEE8bo5K28rVqCzRCZB/tDZRtpyKTxZP05CjZT/HebKcdlQJIdZaZnZA 3QlsHf2pL+FXrLk8qlz4WsImef3ZPhUHrUvBZFhtO7F2kYUBQ4C22UnhF8cGswJd 1rDo6qkl8Uja9KM8o5rY2hFLryPdRnaVuMtXMdcrF6zKrS4ZDtNf14MoFRz7jf6W E8csqsAQwJMBffJmslidbIH08wX11bsVHThZA/nuPaxJCy/MEE4/e0EMBMNjEPuD V5N1tHU/GKzDPJar1/eh+a7tfO2XjQRB32Gr5ekYkXXnQ7f1gs6Il5wBC/L9xGoA XokCHAQQAQoABgUCVhvNowAKCRCV5kNz8VKUaYxUEADOZ1dCvYTH61kJdfenJmoA WwhqZdpjVQgTNxiX740Q2mLZJaTTup0dEeCCPRsgPQ+LHjji6jBM40xf6k++Hfak CTvLtH8/LAMTBxtN4kHQoPMuSTHwQV6Gj2yvuoMBv+wq8huM/VSENQOweLtwObgg joD22xO5aQNfj2MpVQ0tu2wjMm2VFjcvcHrbIdsS1dYsRLTt+vCf4L9GGXnQFq0m 42g2zCXgjIP0/uRdnkx4XW/xXqLwglK4N8KkPuMmUeUs2BiwA+ykNmWZZ/85ss5x 8ac+J7qsrLfcIexujyOz2srOg0QWeiHrdf7Wa1CCvUZd02lfFhRyNXTaev5HnD2Z N08BnPcNkAtLQD3KEWRgOl2muhWqx7WCcqY6NBujMgFiWSpKe9OFDT2+w1Wv7NQi FAGwqfWND/tJ62Xg0OUP45YJKeVwQ6XcnhYz1Ij+bTGYYLpOEy/EhCd6H3LKSlES 4hd1aqbnPxJRfx1AZcvCvfDKRJF0sNHEu5LqPVoSXN/Gz92HhAkQ4M4uzVv9uJgr TWcxQMGRqYIz161AoRJ9V0ZzkegBI1Uj65bywPTEQ/Oi68Ki4FhHOts5Dqm2ZmI0 Q77Qc1W3aAkraPVUvS4mnneYTT9i0zxkqYuSVKEu6wncjQ78adO9qBn3s1S/b/Q9 u6hS8TLwgG+sDBRty/SewokCHAQQAQoABgUCVus/PQAKCRB8Vqz+lHiX2Dz/D/4+ 47AsZqB9mfpM2KNBDwb7lHsrQ7Vrg+MZ0iq8ODlVgaxJI+PtOOzQs1rvLBnOvPyJ F1qmajUQdoEAUX1BBUSSqtTtHMeZILTIehIXP7LZ1whZG8t3vn2PF0uk2OctbYlT RD+fxsnE8jAXgS5N6P84FqgvnfvqzdRFIhMSrR4QV6Cmss+yYlS+qS1/1wuIzE1U ylQ12Na2TX7DDB4XqDHzZKvD71hU89Wct06+hA0vkwnfwXX7xqsD/lzVsa5BU1RA VseRixz3LV4SxONlAiu2gbESoUySrY+tGx3CXi6Vx9yOM/+5LONGhesnpavdH/a8 C79/ErcwA0thR5aXlUAt530bLeJc5E99PCPNRJE6y/Ldn3QUoSsGauzYfolm34vM g2YBSDec6QX15gm69mxyiMTMRNR5GuDCyjEQ0LdBeW8L53fVi/DGHNQnkHZp1l/S 59mSHwyGKJaP4Pv0yaLSuLxYpIEe9CF6S5xhBcQFWDiRILgjSsBnxonTZZ9fKXqn N8596hYstUyb4Ky9cy44ipVoHvVuffnSrAuXUWoqe/gZVeCrx8zRoSOka+LDJG29 whM5evHRvl0JasjSnWH9OK1jNnrVoPG12RmDK7wYuFtyFgZc4U0wUObgbi7EU6t8 tf8SBJXFNbQnYea96fgDuZTuwriFS4yP/Dzif9QgxokCHAQQAQoABgUCVus/YwAK CRADSALHrKQ1Cm+hD/9XQhWC9ISstV6QytlvKJorBimssHMs3zQkGYBMzIKhYzzO KZgbijCvfwajgJTxGX9yDv5ga6oXO6sgPIekULRshwl6huE1g771qNP1aFB/nXQ7 BxBTNKKtZWhme/gHBOtrbF/b5g8QEM88gQx++Pf89Wgy2gcxIlqNrtuKHXsxM7nM pHlPq71yOQK/bXV15EBAHYF0/PIwbLPA+HDogJ8cpMNa3Sgu3bz9Qt5W75fBhz83 0WXqptJ/s/bktFw5zTm8oDQ9JEg9N3GqXlmCfg+fYxT1klzkQkIyuqYTJhOh2OP/ rguA2aLgxDWbIXAHZuAiimVWhEJY2tSFIwChPUrj4RisJ/6zaXjWDYAx9so913rC Lrpher4iS2lKz7IkKja34L0Le+tubaBDtxqQYNkzzGUpIPw+VNUWbWWYUSMiQIsP 4bOMEuFrX/Xm0CNsFrm9fPnJToTYhIfZtacg5jx41vtyjw1M3fzSZYkfC94Qlp4h pDTunVsiA/KblrS9Q2gfo3JV1pV8AWEdT3Ncm+OkHHBnnkyUbBWcn4wpPAjS1TCP uPbYwp0nWYMJbsVqlF1Bj8NiMkTxl+QNHc4SR85Oy7Ks9RO4fFqGP9HMVZ5Wzwzq jxlkdv6eONz9ex5O7GNrcTw8f31zU+MPdenhqrlAUUfESBgf6HUcHDRdpUrmvYkC HAQSAQIABgUCVosmigAKCRDASEyu9A3LnAPED/9dhkHmaGKZnn1nl3EO2+aytq87 cmugmFsidXUqslH9yNpwgGgqY0gFAu9hfgRk/YIYGri6BmDWPLgyE1wZyPn+a1Dk Uef64ZYc0xFVbv/iguHPw/uw2hil9LuCPTynfx2zVpaTXvd/8hEIggtjte/DNZ9k 33ZsIkdRabS0ogDZcP8hNxaAjrCCBSmntLyqtBg1WQ/jCMhq/ZkH24QCdlZ5YFp7 sasm/013SCq7pa5oNAzhzeHNeoFTDNn6RUszQNIVAydTAFebzqIMxzbfd5T8alol pnP2BuBMho2JJsxHtWKfC3Awf0afSeBzvhM9gKYQHr0HlDDTzIoc6HT1UtIA7939 3n9aGluf+KGPodmdFFpqxW+edklu/ll78vIMPtbDeWG52wARL9v5pHP0+P6gbpJj lQW7NPduA6FHJreeexLNPzEq4YYenloghwFYAAlZH7ehecQvoaXFzg5EakpIlV3P 27hJsJFmvUVdhxw0hzb/Ko8S1lx2rqvSG6j1Hgru2M/lhWnpJxF1195atiZ7CoKa YZjvzATs0XJiLH/caTs1IB7pPQN5r49sdkqjAlq8zYfQPHk3Wbm0MWuIPtoVOUrP o8RdQYA2MDZlaXCKMtITzCVFGnOkknlUgl2rugbTS6Apsb9xyUX4UzZ681/dnp9w vAc1m8TXkWLzOI9/P4kCNwQTAQoAIQUCVc5aowIbAwULCQgHAwUVCgkICwUWAgMB AAIeAQIXgAAKCRADapwlvzV91JS+EACbQ8CGoOOiPRJ5f0eVxX5wfWvA6QAHUwKI KeeYmk2RjcA3D0CBfSS6B8M9+ux/ftn2FoWPfSR4Yo5jQhLvz3HYOnK6dfpp29w0 3MkGq/tidhKkpUmtg7/KqkFw9LV1a1RNwOpQiPzv8xSfDzycw2aZzVYGt5xuqPfJ 5lfgIgy7xZ40OT5pJbeqSp4lFaBFKSm7ctUeO5ARlfwO0kkyY8hKFEO21WvpWM9t 6lipZanpgBok3yHVQiYS+5rbo8k2WTFzlSstGCg5bGGLUDP3UXBjBtc85Dt/E4xH eHrjyx1XQenqo+evBFpp+VZR00va8h57l6gueCHrIMRyRW702gFK+S2SFDGrodN7 6P1FV0nNe9U2kUPHcaccYEWmRY7oz+3+hsw6BtlNfmPa32iS6OzFnXSIAF8fYjnE qLgkk2mCBu9lFkWeNcX5uLXOL9obwpS5GsgI8jrD3B2FWsOLPjotF76se+HgCdCC /4PYUw9+RvGa3Q6ElAxaM+w2IjSsUgwjJEuDG1pULi5zsTssT2znF8FWiZbu0Jhz TZlRRMCk/DH/vn9+2HAU5WbAGY1R/QE1VPda7mNzDWCTxIRUL3NQEKBl/Z6lEdzD jb398j3Iizv3oCqQVqm5ONA0LsSztPrG4qVcN1OrhxPO4k3GpaXNImaFqNbQnol4 9P8rPZ7boLQgVGlhbm9uIEdyYXZpIDx0aWFub25AdGlhbm9uLnh5ej6JAhwEEAEC AAYFAlYxYKsACgkQuEPm/Y03/elqTxAArpAsrfVIFurGu5eAHOVKi3WixP2pLMZD oBlKFdvJAFFeolLZ5vF7V34OGG2ikIevP3L89gz0UMJUyP0co6lbtFnheJ2KXAJa Ag3DK3O8VaiPGNpcerBn0dk0LdHMURabQqJiXkMCZF82pcfP0F3qQ1A7SiE6yHpi +7iKn3Oae+4e0pgk0b+OhVG09L9BLklALBrkd9cNC/kBOG1yi9sJdZeJ/EEI84Af GHC4HpbU192SsrkkLbcaUEBhDKZatcYPkDoQcJ+PQa9gr+kJ1sriVBzrfLwx99PN wOLXk+Y6EuGrgfO5tLP8MR7IjiPZrX+VSkiiFiaCPrNApI5OnCKeQuV3wM94sZFB DcIfBFVOkzy3Z74mMwgNcbDU0i1pfLaWTFDdIjEAvGTTX3Ft7PYnGmWKFZidSYKC sO3MJ9xsPUbYeQ+J8lbKY0LLngYOejbOQ0KEt3/HBXY90FpIJve/5ch1Is8glC9s XBSDy8Js8KyJ3rIketecurWeAypcB50gFhhj+RUmwYi1xSKY3fZ/KpGMD3tade9G P6ASbm8/oG2WL2yDcTt/QyVi72H5z6qS3HAGMN2mePQs6VDiV9XIWn3FdYy5sSaq f2RZZJlqIEE3hAW9maTCTKSnmreXAKMz3oIOnSeR7Tn+v1aeG0Raibr/t84qZdoq ihq6T2SncCSJAhwEEAEKAAYFAlYbzaMACgkQleZDc/FSlGmvIxAAh+pJ6jNtXSkH cBSmoCJZvPGOOoCj385N9bOTXbE82svO92eGvdD90ylWE91EVsBaIKLaFQ6MPwnT QtEHi8IC3/c2qjg7QxZpOGiLTDA4C99jQl+eoeU00cN89NEiFeeKj0LeZBiDH93h JbMB89PBniL7RQu5LX03P5HsWzFRGD4ud/wdSJdEUwnAOVKGehlhHVIXfeTyeZQi ZJWbe/MlmgrB3hyHyp5nNRJf4vTZWQ1XsoZXYFCeB1isSgkXHp6pPfBjU0MKG9Za Qx/Ub5NfBlPYtDg+KaerZfnz8wv25lBtOUXhIk26t3V63UC4Y7//SeLJHlByhEbh 1r4vwqhu6XeiNJdYOQYtuuSDx7CDacJxZ29l7MiwjpEZRpZkvRyNaYqVVhkqqDOY uFNZvZKTkshR3nhQBwpZw7R0kJ4j3J6x5S0YWGkyG5KDsPB8JMDDZ7NLktL2IChY Z0NKD3P3leYbl6fJ8TN+fn1ObpBunrpd6B54DnWKbWcFWug2sCdLtncwjpVsxGlu VY9PPHrIih2OZBEvYN+dsILDDCjUVhP+/eHsSKCohTT4Ywo8Cm9ncvu/UxMNO3qF ijdrRT7fgOOr81aFAk7xVACrsLTIx3Xt+g5Hs5WPu/MfwW0ZZUixYW0/GohpQpbJ /bSFNyuBJGLzgolAUl4OU9AGIG59wuKJAhwEEAEKAAYFAlbrPz0ACgkQfFas/pR4 l9hQ7w/+NwrDOD8mCgNfC5ntRw5o8wL/DDr7zoyPqLkOJjg3LoY073ssl/xL4zSd wV8BsEYsdA53Us2UXPgCWaSY7FOLkHK1oGNImjksxJhXHeqATSYJ5J0lYawC9Tnp tdNiuta/i4CiY8qnPub1BZRRCbuYF0a1uYDGbMwwO/NuDAOnk9zu5Ss5t+cG9tTt +NnlrcUWBg81cWUAoR/FsaJ5FvgzMH7efsxcS+rbtFD9ZN6qON2upiicLtmQ4JGR oIFtBK6Ac+kAhb8p4xgpyn7qfw6IJr36cuX6G3tEc7/fd9ae5d5IZ7jGkqn/5zFO NGk/l5rIhJkFwOy7DWr7h9hM8kVbVgBxCvzWW5NZbtgAeAoD77SCqb7Go9rCRkiX G4Tp71wi598NXRaxISIK5owDPfGm5IKlk7rOWoz4IzAI+QQvl98m48yLXPYPjX0E QHJO7z5j6fvweIaZu+tKSy+oCUTXEmMNsVXOTQW68TLpxFdszQ+27dduO7l/xfVl mIth/pRCgrkpS9TAw6xOYfPAk8FI0SHeYGJT6HgR8Ly0Z3dzajEHkb+/XjyF/yB8 BfffyVerBPOWX9IZOWtEUWXLlIWuKxyvs9Zri1cmAJ80DiM9NZ9/RKbhxtFeDGgB 1EwOhKF9oiawkMN/mmtkZuhE76JvfVwRgeh34qcYiXQeplnrlG6JAhwEEAEKAAYF AlbrP2MACgkQA0gCx6ykNQp7Sw//Z2L32DZb9WhXeOLh3xuuVguOS45HQK52qxlL 9HlCFPGPMZcAYSr92V8vC+HKPrRrzINrGVHaHk+hcfRYI6cRP6r6kfAYcEaUc1Ci 78dyNnDgSuZ339KFoNGNnRTABCJnvPhxRCLG95BCp2udHOvDerIWbt/PknEEOhAd RkHJ1losEtLoz/N2y0Zx6y6RPhI121TCRTUDwnjUQvOFdJ7HTwBUW+fstCDNfSLY Skw3s6wnA3p3GZ2Yv7biv5TjX/TxWB00+xJ2TWqZD5atEpkXdQyT1YiIZ88A0Y6S g3ZyIXlWSEiBc2jL1meawskoJXPAZgGisJOFpy0W22z8pU5bSOIq17rTBhgBEUL9 H8UBHrxni4R5OaXchaC2l8TNkVz1LAPaM6A8HX3IdtndIymlf4ufFYTpOa3sV6ud 5B1TgScivB2gmcgwGm143yVDdGlaTFn0pX/KW9t2tYYa3BOUbHWdLYmr94Ktr+wb sbryR1Zz/pR4fKYKn5DcslYbgabSy/yQPKZqgXgzfW8CHCywA6MMA0RXvWK2WtGM XQImuT6grwAE2/qmRoVNO/Jz2oiJVRw0X1tgdAmAw4lWXm02seOZBjRC/mZKuhV7 zC7nZnuZ8smoyuPfhPgF/aVr2Vni1+g/OO+MDxCqpq4noiqlVcmHDsfH9Pm99p7J qTZMggOJAhwEEgECAAYFAlaLJacACgkQwEhMrvQNy5weCA/7BPTjyR5e2hgJmtg7 o0YbONgMyO/gZjVaOODMHYeWSVGD+2yBbgPc3vanjEbAtgwE3C2RYPeEbSDxKcvQ +uWQNAPM1w+dB8f2orP/Tj+7X+tpS7hTxqtOg/SNcj8RaI9ziRuEF4qAy8TN7HtZ U1WYRb11jKvImisCHLVV/HPFamUJY1g7ToW0itCnyVFDDyGUIwyeD3MNKaOpqX6u 458E+oGMh7mCmvKzOVbY6iaMTO9J2ljlhukOVD1b9V6SuRnxKb8aUSIey+g0PMic 2QwwNreVPgJwhgwJ9RFSt2oukXEhcavr2dYTsUs0iwfNRtYypqykKT2kA//KN4ok I8sH4XaXetMDOqPo42oZ6u5nm+a3cIVGyrxs+5yjHEyEwdOSbnWDlT+ihmUINehD I+56nfPgVKXrE+oXUZUHfP9tSFfyITbHgimsTDd+4IvabZbRLuZTGP1NYXIuSfFx 6Cn2pqqUSxGXsAAxQDj4bmxy48zKHOH6DNH4CujfBYgIYlUR6xHsGLAmG9OKP3ab E9Q8zi1EXJZJOJEVwP+2GY8OpXLTelNCmoJ6E/AjpHXaaTIzp0lmzIXgpIOmsYPs MVyhXQDRM/R4SZEjPOUNSHWn54KoGk8xe9m8iYTvK1i5RAQLlX5KO1dGIisi4Tv/ PDUEDG3EAipoLHcEccacSfGoP9SJAjoEEwEKACQCGwMFCwkIBwMFFQoJCAsFFgID AQACHgECF4AFAlXYMLECGQEACgkQA2qcJb81fdT8Xw/9FjA/nqPwmdu8qF6f1BHs 6xkujzcSewSFgiJueZm2P6WlZwoQ6jHWsFjAz3HAeBecgcRoe2AbMyN+EuNooM8v sZHpUFZ1/GcE9MABF8JLtUoDMJxrIv6mhzHvNULHn2TBWJ+yuVXIeJSojjciem81 iZAtI/kHbm9iNU5Uisjpc/u+v+nl3GtyIKjLgbe7piMoeSXK3p++T2Avavnm87Pf w4AxF3bSUF22FeImmeRnqg44hAHams6lxyqrbOBdY9QYCb3oI6QRcDxc9sCegt+1 IWxeAY9jzcOksYQbeDcMpOwvCOZkpIj6xqF4PpUVhBFUaByR3oIVCxrMfpL9qECR JSBbbrRks+fpF2zg4SGNtN1vDZ/IeVKIqokz/rpgXYsyqZb8izpUJd6dQLWxhsbV m0NBVGhAH6RmN/VH0Dx08QybVwK5UY4AqmAor1rc17fy4POiLhyPz6rl4JgwTECU OndgXcox4qW7ZxoEN0XTOmMp035vKVDakGS/jTE5TWkGTOLAiknjSx1IoLDSGQiN 4LxAHoQUSPJfqKrlogkx7yNLBqcBjcGPy/4SrxOkQUp3Ao9tp3BwabuSjExKONQC vm7KqbgATMQI7BrvYSNVSyakZEzlEJjpHeobULhBC4Lrt8uG4ygkpCrwS7WCSPwo URfMzC85CrBRkFBHtmcWIZS0J1RpYW5vbiBHcmF2aSA8dGlhbm9uQGRvY2tlcnBy b2plY3Qub3JnPokCHAQQAQIABgUCVjFgqwAKCRC4Q+b9jTf96SeID/4+SRRtnUh9 Fwbiq5WcMZjSwJ9chrqWvz7R0YRygVNjAGHonAVIRG8ILYA9qUMCh/fekxEzUrBQ 9rGC6fDg+gBHex6h362K/oPhjmegGm3XHlELjUPHOD8hH/+50rVzZBjMO39ZtYeE 3wvkwN49gI6oQMM6uXrzHC3f3UV+EffMBgG+VBIUx6QvGfMWaGFa4ur2BiTTCg60 vt5ZuiUEhaX+ggsG/FKQbwU9U6fvCPWotDI8+PX+arBAcGe22leyfAE3Ar6VU6Vu cvpeqTdtEdWfRXZVrjptctOd3rnUv4im/y9t48dQPn75fgWkjN8rqlFuEvFem52y F6/KAJff8xpxWc0Q8SQ62AYwGu4HIHvs0E0zi7ceKP8upCfyBaMXLKechQ93eZyk JbsMBWCkhYd5ULolwMsc8WE0wMa5phMq34TnRAqBfK2dzVtXgFTErA7ZZ4f5GYly AFbSyNj6HTTarpz/JMGSY4namBbTf5WG8s4Nmku67KS4Y9xo4mkX3Q/P1qMQl4+r AdLAoymeRBAugH8G87ADvyaot/o/A5w8Vsg5riBkrZ8WzoSW5YpsrEJCQthwl9OI UZFpUCnPVBVGbQ4HesGGxvvmjmM/VBs8hj1NhVQmgl7MuJEmrzmhcdChLkm4T9VH CQBXbv2dHNMr0epKLZw8AWoH/O0Y59XSuYkCHAQQAQoABgUCVhvNowAKCRCV5kNz 8VKUaWorEADbvbARiIeDEAau7pdcrm12m1mxuM5GpDKvwUwu94i+JrY5OP2AT2kn FAaUOznjJrM9G+QPRSXzqoYNSQO23FaqLcEh3QsyQtK2endGwHGXQrBbINe7Xugy 3G9tDqibU+mT9VJvXuXXG+BRtqIvq9oKo7ywX3feO99L4DvhHbZsKwcNfnVijevZ SlWyJWLoYdjyCPIVX/igRCHqwE8AXQNuUlZgm9TUrgr7XMwr2cZlwtJUfVo1YR46 gBSR6KGpGPAyYfTJbgRFIuQxZw4LujXR5yLdSAj++df3jqGz2VummyI6eSiaQNsr 0JtYD00Jk4mRn0cKtKVVUkBqCISkVnLozaHcEURSCPhfNKEjvHYHkdkWE5cCSu38 qDZZ7Plm1kwS99IpYp19XGYpbuZtwRHU5yaKol5HMUqhKzM+YgrdVBfJ4tUakwUe TtGgeqAn9y3I6Y/r+IctRzXjGPqDzWPmRtSh6YR2dT6+BzMEGyM3ItV9cC3X99ji 2KaToO8Q8s19/NvoLFK+2sQi1aymRroUVCj/nOEC35DekBn6cpKQnKUYydFW5Unz aubwnFyinN81ixpTDjEPgAa5ZG0kp33vHV2jhzPx2DlWmeqWbT1Ot/o4puBX27K1 pkSLMoQcsD22Zp9pf01I/2aI0e7RUhAW7rnVIn/v78km7E2l/SgZ64kCHAQQAQoA BgUCVus/PQAKCRB8Vqz+lHiX2NRhEAC9UNfgPvOu9a2vN7s8YlNZmuNOC9OWoqqX nd7EBioqZ5HSuGxUMGTGmSyQFC1OlfvcwJwAxE6uk02JpYa5xiFoixvyY6IVGr2r GEgeyH3wDbYm7AN9Pr/qwJXTohqC9FHGIjY8KbT2ME0TXy2sK8bZkw8ft6Y8W6xw qGqEaOnFSj4uPZvBLxKdZUeH0QvtzfjXLHo+CYCNyHA8eeGqWaxBsSgBKrU4xGp5 ce2xmnxexIED3CfwE0LyjOF8TyUa2aI35IHYIj14waLhIIJv61zNzRzM+it0BrqD eecyfxbHLm/QSEG4yFGeza1H/jQzMeLL+mQQwEEs9vlrThqLHLtjK7wsQ/sbQnlY 46rnuGP84oxAV+CMGls1qa/6Wq0EwWvYhTTiFRuL6c4EnzFMhoaaLmfgdPXh6wak 9ZnVEKgGcSxXuyEbZ2eA5ZniRZ5yKwr9ZxKBf8jEP/nGNYjnWGTnIbYPFPHdk+GG G1k4lSfdPf8UJ8yVSTMEGA6Icr0EBjWGpC0VXDNp84w5Fr/SKHHNkzdAOJxxG03Y p/p95w2BmU4AVPot70lbvqjZsLEN/dCfFVoPX7OfH15QtASBAjhQb8Eb9dVfQmyw XKt2xTA7CZtKJ7gmhI1lX8GNAvxyZBVYSXbD5/9E9Z7GJyF1e2M8Etbx2JfYJa5M zPuDgTM2N4kCHAQQAQoABgUCVus/YwAKCRADSALHrKQ1Ch+bEADHrgQwfvGceVLF 2amB7HmkscKM8G9X4jdjFf1R1ggVIjVDpI2Gy1jWi/ZHby2yzZXChV4xs6atlH/U A4FBape/0q1k2Z+/5ws3/vnzvih4gMAIgNQRu/gZekJA5jFlZom0Plb8vUVKOaGz O/AnYBWEE5TScR7GZi7MrTglR8k/4HVhbMePYU/jpfGgtBp7KgXybrUTQXdtBKXb OBCLqw5qMhc62yIRe8oYjyj2D2eWkBWyJe06D4mhdZQaJr+il5zgY1gdQcemgzDz 9A52CS+0+c7dPRVrYYAFCyt8EmMdX8gFoAZdHAXoMLypgyZfKXnQ0LMTXQCYbMVK Po5yxh8X5oDHK1mk7L8hGx5Y+ADbl0Kq/fXdCdXrpd9b75eaNBq0uEnkaoChLy4m TVZ5TaaF0dGFxCywyDFDuwcEVeXlwkEi8cgFs79Wr3sjrL9tWme5pdApC8jXbLCM isMH6IomhVvJEzBImMI444mQPxpLRh4bEfPw15Y4pP/FUNa3DGRYgZR1wkkNfcn4 mwdyB+yBBD4wkhqdfHYEXzJE3fQ5rp8s/ShklbgdXal5UUUdRAIy+Ou68J+8GZSL wdPjRaYFKV80KYadT5/isgOAVLs75TyyoD49LxIvh8fc7iG3edOXWp2nfz3OZyW5 PbqpN1+usfl1PRsCoMyIq3X7+/SwYIkCHAQSAQIABgUCVosmngAKCRDASEyu9A3L nIzQEACNUMtIX56vU92ZwfdWuBjq8rPjC/MCyxosz8vniQz0XdewtF5/0q4MpEK2 i8MH5pFZpWkr2x6wek1Py/DnLJmwkOBQLbfVh+fdGpWZ3HPPQJiLpDkTRDqNIVAN 68G7n+w5bWqSOWgxijHgHvPHLQ5QILbPu+jD7lRer1WHrdm1xljojCU5gMnSzotS QfZJNq9COMELT6P7XPZr8q/402nWzibts5FamuoF3F0kKUkOSQlF5hNqFCxQNwk1 q0echJTd98ghdxLh+WNAo+wWZ5PxPp8hJuk7z8caKtudu8tGThg57kyzALuQkwYz Tc66/iK0gC3Vc1+JGkVZm3rZMFW/wNofvfot97CaO1cspi7kZQm5Yk3kuAJfK5x8 hJmpoeXdn/pMssrvCN60F3Gi/KFGYa6UjQKVLwr8ZxgWRDj48nBnl+zYlo0fgI5N m/1RtKjzN6ekvNU1JzXG7BSQWyFE2NfbZIdI6QoH6heK4pPSdm5BcCtBrBi/k2Zy caZyu5ghR5a5olrX539WWa9PU9hOlcjGyQkJQujXeIzpI9/5HB+o9GQcLdeI+lZb UPYtLMdyv34vfaTyFTI7wqsE+574oiBOdiW9CF3eRSkxApWYKQvk22OAvXKckuZ9 C4oH+4at1h/AzD6tBz4kGp1wqV6yq9lzr3JVMoL1ylHSBp8VSokCNwQTAQoAIQUC Vc5aYwIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRADapwlvzV91BQ9D/9j T40ybqTuXMWFkVh+VFTjROurWeZSz06iBIxYxXF4YubvTGHrqHCn/CtRa5q+cjR/ CpALwAY4pBhbwUVxSFwz11QbiXz+1VeqY0DQre8RujXoXuyxCuqnp/DuDUGYUXmJ BSVEHlcBstRusiwnZbmGfZQo7uUkJvgqCEjI+TrgYIXr+Ze58TTEy1bUJst25nfJ 8p6HvAkwQchvbO1mO4IOwkMPGA3POi3pMHeMu/dhJpdWgbjeahgtc4+IVdyLsSBH qVfa9yM8NvOkmTqJ7swAmhuCqGkMrQB7a8If/5nTCKfu/a+Hns8Eh7BJ9D4fG6Ez h3zW2FMPB8Y/b/6w0MAzOWQOK42bbeNGILuOPok3YYL8C3jr6dUtmgeVWQT2CChA APBM2bFMOUwSqxwJHvdAGxDbdP1ueRCtSTc1OyKNTy1B5k9vCbDdH5AY61u5ZPAz LatHFP7H2WP7rNy42x1pKkhATmOpjF1VbA2W9W2v9/bUjRVXXGitt+oNG9hAfwUo 0bomjx8qumo+hABAiz4CckjSfGGh/4oqgCrgx4/LLxHoaH+6ZqwvEWacAuM4vOXC QszLom+9qk1AB0jqC5Z5wBOKzr9wNUONp6vu9uaS168FsSt6zRdbl67cwo+vp60z DVTjEmeCAPV3Ztgwsb+/Uq8vKfJ4uwJ0rMUB5Drs3bQrQW5kcmV3IFBhZ2UgKHRp YW5vbikgPGFuZHJld0BpbmZvc2lmdHIuY29tPohGBBARAgAGBQJTr6YXAAoJEDwM M7tEK1vpJmAAn2YFNT7oz7LFTfn9CSHu7MDeivP4AKC63x4WH3452PT9tvT25S9W egjMPokBHAQQAQIABgUCUywEZQAKCRCzPkZCy24/80CECACDr0yaf78OYtp4tFCn +cf9SEJ11eaVgbdqtSej+WcSsCkP62wfYthgo5NzUiMVXlPv+4DREO4ZoimPlOZA s17UNW9jl5LW8XTyGLvwm/YiMFUfTtThIaA3fvu7xAcFiEcqNUz6Q5sVoA01wjpz +mCWW6Pv6Ii8hVU5NzQfun19v3QvjT5WJURaquUw7tNy3wUjvxWxHqufxlrSVesq P6hSHJL3pq9bJA5ODuPaUNDSgk1Z4B8goUnd3tOUaGA6If09B6hlIf2Q1ZRse9gw yl1b+QU9fXsAMhoU27POxWb+6RRLE3Y692L0svBnnhFelSsRH/jtWd65t4iv9sS6 KVbViQEcBBABAgAGBQJU6MCWAAoJENQeLCdg9OD0xxQH/AkaounqIjboN1L9Vwcz wsCe7C0E3XMvJijbVp12BeTpWTJwHcIkDM5FhO0k5NYG66gF13gEqYt8n4xYnGlY Wozsq5ajIw6M+C+FciOKVM2lPIN9UTxN/gtg/JSy2GHoox+yuTz9ppjbhuTHNePL mOP+Kwtr9JvFm1LUJBtdSepV9a50HmIgZOH2m5qYXiEajra21RSLCxTUQ0j1lU0r KTCLcUPdpEiWvHdHrQTckdCAd2OhTF0/s3d7t1/H2UpFmnbFJorX/Y+qytCNJ1gM ++HebHQEVdI5yfJTX4rSldYwpERb0DZC83PAs/FJzYtxJnMupwZJfzCDu6YEBuCJ p26JASIEEAECAAwFAlUF20IFAwASdQAACgkQlxC4m8pXrXwpbAf+NkUAI0e/szy9 i5gJkPoJOlRzTsbNQcUc1VTwNuvO+rlYL6Zzk0HvudViVNX6Yh9Q0QWweuh+P5Cd grSPU0uc1/KJrDZ+2R98h37h0NenCrqayJrVc5TTx64wRiW4jAlLM/MGpa4F9XMu c9b3wo+QDB7zw5RR6XurbNXk5mCUQKCu1AdGrunerkNPCxTVRF7SHf4Gtg1KI7yz o+AxD0YkiHWdcGKHQXkwKPlDDtvEYMNyYYcsgGIZ2ZXdF+JPr+JwlIrFdyOHuzU1 2zjfjKiUWq/6CsAXey3QxUaf5x6YS2QCaXAM6Avu0D3VGBcl7jKBpuucmTMvwzGt ozKpk3/xQIkCHAQQAQIABgUCU/kcxgAKCRB7WFswgHwqhwfvD/9v0GtMVPURU8d7 OieO5SHhrhhQ+H1sJ8RW+KX81Xk87D93jWg2aBNwTktn51p0v4e7CjWZzMA+NMEF /jfLb2zaoESC+0S0GwpGGsiWleuMXiRySfWaXWMuIJWW0JGO4PDZHhcXo/9fxqGh 8bdGct2NWwF/uW1B0Rutbuu/JkXP3qqyue3k53aDAI+BUKlPxiCmtO8UsLESQkyV ol5sJRpdjKHEIQWEi5JThWdslPDaJHMcTGqu0adZtE3bPj5ZhV3CKW8nw7onKG2x cJI+w3eZsvdjid+tSYwhUbCZABFSe6JzMcW2YGRE8mxMxqXgLLZsOK4ePBebAtdi W4klBLjeUhzhOKwrAhf/0EuOVbIbuRNYUWXebnD6/pWO5AHVjPeAaLo5j8d64qbD QD7NWuU4799Rla2wu7ieuwEjkyhcMdmVGnd8l/tZBmnXMcaY0lis5r2Mi7ZDn051 gmjfTB8zmlpoobeLJ4OaGZyUwlAOr4wDmpkXkTwwyupZtacUfiVxb4uOfePKYknw Sf/TPhyDy+iGCBu2NrUxOhrgrmPRU/2qQ+tukHE8CywWlpTi8KnCSzQ5lgLflMQo raoR0oLCJxz9SoK7Tpt52lF7pgROOzE7ozcBgjDMjQo5BaZhse0eGNOsx15B/hZn L+TzOQmk+ATN64xyAw/BR9upxQEeSIkCHAQQAQIABgUCVAN/NAAKCRASbrVjp0sG v7qZD/46n/i+Sgw1eopuuhoM5a2dYlWrIPHKEUQKpOseIOI/Sxss77zNMJB8N+Bq wgvKRlMHq+wod35w23qtnRvcHoQudxw+4KG+PhAM+0rF2oHY0tXkLR05Em/DK/JK nPpGMppUuXDUlSnVi5bLotpr0pMUTEP8ZQkixQeznJpqonlpusQVAb5D72tyNrRI T92GC44woXpgpi2u4iapJYv25Z/EcHmK4V33EYo+ktCebWoLvVJKxjaQVozhNKzL yo9VaH9g0MHbdh4Mzmu8HNqDTerTtsPvu9r5bjrqzmXalhyb4p3NGoAt2zubB8tR Sm9rdqqfPvs5pD7Ic2bxdpVOWpgY3hd6Nbq8bw2jbrDwHHefe/cAgn1YbMhtZgCw CfFauI3QZelc3XAaG8tyXixdyD62tM1odB+quKmrExb0x8ORFTVUXwvjetI2cfCp IrW92cAJEAyfp+m0iv8uncwDKei5+UDutFztn5H+npKeikFvmRXbCn8fB+Dh8M+H ClzcWl1QeeH58SfLDANdFUwmrllkyEI0q+pAlebhyJritE8KeootEZTqzsuRIkxG mSbZ1TaymKXUHzcLpuog6ejuWn998HVCZe9Vyzo05V2q9JEx1cQTyfChUWiG4m5T Fg+mHV0qHKFwELeItfRGSgzAbNkdKsYTemDpZNj+0rn2ERUh9IkCHAQQAQIABgUC VAtdAAAKCRBEFz+hPQWIiFACEAC31XCtpSXFrNC182ckErsPoR7stbw1ImRQag6H W9hGnUD86StbCIbwOe5jbkgihWOVYlYwT3jHFnHr491UjLGVynJL+OXLw7cAmYDO N52/nactnqfRbG1R5AMbbahEXasFWpXHXZa9KhAH5FYURGnPHRnpL+yGUVC7tCxw jQ5RH99Q3x7DGUPIZhIjhRe5vYC5KPH+Xu4gZDdXOqTI/1elWjQOyBp2Vagz3DaV PzlKMsEwQcnywbgFRiS6PvBRxkIMNwVOdpKpSDCnIKM+3nP4JReP41n+cdEVVB80 iaAJpp6mBjhTp/UcfvyRUaQvQ6fOT8HrAq3MRELs/nP7XybI7tdUnZvQQDTAKsC3 jXesP3S+ezeFgMyMxkNN0ebt+H03aaaIr2UHWkW45OLlpQn1ks1MMivkpzaosWTw lWhO8yiCHXfLrXc/GfV/Mv09iNAvLecDOPnwpeMjNTFTxHbX6mJr42VULFxQVDAV ay8ZOftoTXMBDtMGKPWIsnG6wJfNfwNCGpmudwtyIF0BMtZgFIjfxAluqIMK7Fdj n28DbNcLeG7KZKO0UebtPVnrKjkTJbDpZqklt+3jcxJWtPck86dJ0u9oesP97Djp l1sJ2hkSqqihEmT17YVriiZl0rUYHN4W8Gc/VF4JhbqeRKveIO1wIOPVscalO4gF HQ6x+okCHAQQAQIABgUCVE/+OwAKCRBZv4n6RzeIc06kD/4jYFSpPN/VSaaqF6vD FH/7zxpg6FcO0AllgASnJdk7s28pb8wey7JxWkkKcqV22NEZXrsT72ac3Ay5ayoy W8HLgIhz+Z9PRYe3X3F8UX03u8ufD+XUllEumNzMcLYPbgDLsg1izV1dAhpdUi6h y7dXQLPYihnj7Uk1aKScLiodw2N5+HkASMoqmk0SqDPbHl86M39nqzKkV2iChLNE mRz5Ht1O7e+p/feFcYBP9rTBy/s4qq6a6hxw6iKuz+cBM75zCAkD50lWOJPpAIEn HTJ5oFt7+KGbhtexQc/TbS0vekOGFAuatPPc+dTRKqQgq9gDpDk5u3KEfKBHksBZ o40SCyQLIECUmrZDCVCbBfCkiEyjtbnkdklxygNunvWhwywD42bkANyS3OkfTnmz 4YqqHNJEK2v6pVgv+r7jZfVBemiO/7yiXbuHV6bxDoRn1g0xIw+kQ+RtsWM8T2FY 5SmEwnUYW/bB10D1M4aufxp9IAiBaMm+vEPX8cv7fCXRFV4zKAAI8CGJpioklNOS bLwNazfxAd6+ab8UNe1zaaqdy70Rwl2EB+/3xpugYu06zakJ9tvFVlkKJhOzixl6 DSqbfh7NKg7EOSV5RT0g7f/kT53N7OTFZ4XLFkFhSf8kZ158lO39E13Snzarj6t1 1QrX06SHeZEy6ueDXRspTfJsu4kCHAQQAQIABgUCVjFgqwAKCRC4Q+b9jTf96ZuE EACm8Zwx2NFEQ4HDdUaon8l6lXVb63X4DBBCwWDzrIZG8/BVER1QIJKu9leOVD9a 7IUrv3fHP01DmAWvnOdr4dRteY1NrHaLMwgmOMsmhP8U0R1yLNafPdEj7PKfJAu6 dPy60Tsxi0tje89z4dK+zcI/l9mx9BtLdITsyDp8JF2/EVh6eLcwRg8UpfwbmKhJ BacrAdXzgkLfdu3d8MWxqPLtt/5XkBMHm5matPHDBX8VpMnXcwZ/ZfZ7WwEqqCTF kSj9OMugMQX0LHcXlnYpkMEtb5k+mjYLkPy6xOPgFA+JZE8gYBgWdqNWgYqflpG/ YoKDv8wL+nhOmnIYxClpEzan4nSP23+NF+XRB26sP4DBtqUAFY9C1QhZkJH3QeQ0 A7VsxrIRgiTI7R09hzqeKTN+uuee/LyLpu1B1wF5v28RvZZ0v9IJqFho77zURqDH pUBP2bx1mzVlx3vwwJyXO5dUWzJD58QachA1ZpeOimoI4vsFviAWeNlnSU2jZCdo VgGiFA0fM6eSkTo293XyS368n9gUeC8oj9ctSwarJrYty3fSvFSSQKEZpNyb2J+Q SaDMFe5PXOUa8yvCCTZnjfBsjPr79hNnsMfCDURbHm1DB8d5cPRP2HFdVqHeqOfs YEtj0QQgjf8/1CGJ3Z8nmgunPxDLz3JToFHOCoWuprHKUIkCHAQQAQgABgUCVAaq aAAKCRCzRk+JaqFZSLjjEACCzjoFzz5/KAIwXWJ8i9f/ytobcyZP0RgOyEJpl1NY UqSvfv8tL1Ofc1U4K/IXW6zXyyynHizO9TR+PYzQV4fHnBUgG1PbhZvfesBw2IMI Rwt+YJyfQkzPm7y4WdVzpo22PsRM4+wxnnHynMF/Tps/QNokn1SaqPgIRFqEc4q+ TAiJAy9fe0Ko20lGVJHpP57zXiHZS5CwD+t1Xbhm2BqxrWfRlHRLKAnzsrFUI9bX HI+fUsGSD8AeRoudaxg0HxE46XooKjO4TQZZO+HeC8tvR2xlYvKkNCuwTovCDjxT W50zgZvxfxxp7VzywH+svoUORY0cP416gOlM4tL+VT8s0ZetTgCg+BlH3NesImOr aJv5Tw5VzQHCXpCXBSanT7ttHyln4r9/OyHdr1o6rjt3CtJtDa+5TTqBmTz46wip NN5ShY5eIL661m99+pDKPotYHHe2DVLJPF6V4EzqBSdc1X11IPvtYF+z+P/VbbTX JT4FNx5uVqetpym4NijJeSoSK7aloAFRdIWSaEhWWm8/v7qpHpPuaMogiIKvcI6x S2vdgmDoCHIs6nF4icp7qWVIqjUsMfScQgn28e8hl/Hkqhp52PCFBG0vTi/xOsJJ lhrhNk2FNa8wZGo56LL9DvYjdBxHv2+bS/CSOSr+Pu8x1EUnT1h/mw+6rOlP4Yfa +4kCHAQQAQgABgUCVAySUwAKCRC6nHgGHd2MmxSLEACXbGbTAFD6FJic210fUIl2 qctMLCfHvyMjxwxQikAyOPh8gXgExwVUj0xV1fx5EADhPKsFPKAn6k7xx1LSgPm1 YJEZ2wYN5rFM21jG7PNjWiElgPJzdpECdSNudm/BM7505UEM9Pwt/aq4iA1ZI4o1 1wg/byzaPKDieF1C5dpTwT4gqdcxSc40TUC7RsUMwY8wJJa0wSnBvJ37xDkTCvgI MktOKD/xe/CBg2zgpFSJ2RaRnmRu2R4gWfGdvTNBBAKmY7bM6v9+nsLNr6Z0t53D bWuUVmmiSKGoYMkWOHELrUCc5QOAPHOA1hEVvaWFQB77GaicJsAiTun5Y+xHwjDi HD8GeqAGbYUUzyJyM5ClQy+wE5hTU4tlkizPsCU6NKjGHMtOY7xJWqKosUbfJCk+ w+DH2DsPpBAltFXoZkXToWsfYs7c4OIUbKF6B3LFDw8eruvGN7Dt1u81cwEi+et1 IVe15r/frnXRkC14Tkawpa2/xkXhdPKtjhEqBbm31LhGM412wALqCFWG8eTFIRzH uRSj9ilOBDJM47V4jogm7yq7h/S/vJT7J/wKO+KEkXDpeHxZEVC7BrKj1QngIuk8 l3kRC5odJJ2Rg1KKfFhKgi6etRtDJ/ZZZe7MVp7BiNuqamPBASRKtentOf5HA+xE /fYVuTNS3kJjUOkMBAn4jIkCHAQQAQgABgUCVA+g4gAKCRABgXqwqvbNrtMJD/4v elrCvza2fhCj1dKuIJPsq3jk3U9PRieVaHR3c1faVqrWBJ103kzb9s9XmF9M6pEp Yvo2RSO/JZnSbUhjze8aH5myFiOoRR6bNWgpeRlLAfppZiR3xLhj0D0W3ztpfU9E QxMAVD5w15VbAmZ5XOxzUxvOwNRzqwIXNt61oFuXCyNgIb22O0kQDxkFj5q8E62d 6FmHnQwVqiLcap485AIGFVapXnMvKy8hsnysAzKAgSUTGH6rBcX+HLzPoNAimYx1 ZN6ejVsuNCXSK3+MOHVkeygqihkxg7k2ROf9AQcVdMMGsVM+5WaqZh4kXwXHuKB7 kHNwu+ZLeI/kLspxRcn4Lhtda2nt7jsACKWnfG92vuKOFoILMwM0Zp95eOKwmCK1 atiCj/C38bN6bcwKF4KcQZnE4QBYrmrpCqinvQ3wxKlmaExlgQSmO6XqUGL5/XGv ZulbK8iVOuVRMSic/RCCHNlB/asrsVWLHPWvtE0pxBfF1PFy6wk1AY+TKrNjRX7x Fy5MDXPAio9V/ZTNT9wGsm7HSLOWatQc2Vkh0w8npxLRWisSxN2DNj5RYkeeqtoM 23QRiM6yARyOCt0acWUISe5KTcqG5KoxbeiY1CuInY+HDk/NsufkQO8UiNJUi+mv 6d5KvWdwnXVY8LVxZU15BJLlMbsSn1AdwXBJFn11F4kCHAQQAQgABgUCVBKWjwAK CRD1GxjHICSCJB0WD/92o5b+eos+kRAaUnbTi9/fOsH2aswd/r4N+zWRxmjf0pKg D01LZ9+P8Pj48B0VjrMorwVLjPibz2jXIiYlwWdBX31zNM/xlvhBLNTj5T8DYY1+ ucvUREZ4J76jzKNOcNScnoSkA+Wl+j0DJBJWw5TSGmWrf9W14k71Z0GwWKa8xtVd meBMVJxdfbgxxxFgliY8ifY/N5ibe3ACSpm0Y0LgZHMN/Wtk30uf2NfoHgH67ESe zQVqDXKbn00SPtK2HqHjLSX3fbjWninuPJVcvO1A26UU9je4OiHDxsEwX9hFCPuf t7jNxkt8FUTHnLix95ebHUqYfaYSwVHvPg3vU8oSEmYF1MIljmHOnsHVa8j9Yt3j c1+fIGPI33eQ2GhdyS2S2ruHMeFWg/exck9RvctWLW36dv2/Llp1AML65uMhbfl4 peNMpn6O0mnXJCLExVIWf5/ngUD3fVanDClmgb/Wfla1ABLXZNB/Pt20UC6GPQp2 WA9IM2q76OoP8KVpojrINWA7dUStSbNEP8bfwLAnH8MC7aynEfUtcORDrDjvldJ5 RGlEoRKU1PFx3lmnf+qjKp7qhxBNUxT2fMHySstRyPkDpadrPQdODjzP9gsdUE3x cvKoendRDJG8mTjz5XYkgINyp+7FOUPFFdnlt3qn/Athb0hgXxY1WTEk2988v4kC HAQQAQgABgUCVBwvnQAKCRDZKfKZK+8KM5J+D/9pT0/VUYgKqqHJVRXz01hP+rYo jxB8l/mojr7CtNn1lEypdKkxHLmARP2jul1f4yJ2z2YzHeWkNoSxWXf5acXmvoy+ 3MenfRnnMiQswKpenTY9iiHjk4W12ZslawGdgWXIAojFAp2S5HktP4Ig1saz1MxT V73AwubDR1jZITZwnGG6nUha438rRff9GGAEa9ovATDdDOijpvMsU2O4uE5wfNvP 3d0SUzcMARm8AedYEKaX7ygwm9jCAsXasgHch3ZaJ/trz7Dj2ZYXBqHZIvALYuoj anxqYhXrInOgqg0Wu9Bk8AmiW8VU5sHgxxhQ6rJ+5Iqnr21oRRP5uBPHrBHKJ4ZQ IYYBC9SwXnIw11V6lJSCZmoyeyS+Upv0sGqHBKjKZTjda0Yje6ZwIsdm98FqViyi 4woMwHnvUC2hfhEvZEPAXrdf0VkBOcqE8T6g8LD9LXMPQcbJ06Bv9tpcMJlIz6kL IoqanbTtc1jdna7fQu4RzpsJsMQt/79IEQX49raduc1lVLZ3ULEciJGE3WtNx+v9 5fcSPcnvZBZ24npld7q8heoFYTD3Ay8OTG4aS4SyKCWmAl0nLDRCtZVenr0jgW6E WVDbdbEwOOFzvdZxIyjd+8dW6hsVMBAEY+oFV60MLSrd2f5SYiuZ5vSl/pkZTfei MVdOwArH0vcg+LM2JIkCHAQQAQgABgUCVJCdNgAKCRC45Qh3ZkdarzL2D/9gveC7 KgLzCmyrfgFEvnTNmu+knhBGcYzDXtMeK4djww4qCZzKOVIN991eEdJuUbLTHFmC LffRmcbuih/NpwKX17Md/lcwvhH697pjoLA8LDtKoa55saNeGSHlgsjPyQZMrsD/ FD2Rf2u3iGQ9oy3POCqm7z0XN5faaelX+dezsFRon+zWclDhS3gN8SpTMfXoWvYz cMLJ2NhbrEuz5I8ktvOi/bRmq7xLzZVG3HiAs8pO8LvCRO3inJtxnv67vienqIm1 6ChkWOSHuUvKqK0+7mkIUV5981pOoQfVgMwmZPrNzGn1wdUMmPn3RKOdDpX7uttt O0A3aakor0fd7afJSBYw/vWg5ftaHKfRcHFRwd2971fthmBVBoV06gzHE9EnnQcy giMw+DPfowXcmjnEC1+Nrv38vHCXvMpYTV/euzNNF/aS+4HPRQB6au+ZW2RWdACt KQhqHERPXL7wHW/BWGA6dHAh8MFpfafpfO+EYIdfUA6mK5XAut9WjQ2fuSbDJff2 9FtSq8tBWpekCBsbfSNcfqDwHhFrCE4mkpf6l639P6gXtPgnc/BgNPV2thXCkhFY PTqgxBs55LqsLcm20i9mwzkJT+sLHaGNPN2ypB/q0IXgTqnRBvwR55MEicqLl0YJ uZND20iiySzjRcpUCURrpURd+pIVBDJa7TrR8okCHAQQAQoABgUCUyyrQwAKCRC+ KYElCJblgfrRD/9pW6aw4ic8Vhlkf2K2M0Byl6w+9aLcNhIQ0PXwnytluWTN40dN +jlDepaEL/eD/gIk8G3f4ucOfqyJQPz+Em+4yyPgn/bX6UCXPxPuCx3xYHQGrgKU NZoPT5KYed+YO2yDlDSIl41uqJr0tVhoac5Ekzra6Av4xFt+P/DafwyeGqmLn+H2 qYwlBTWDf4NZUoXa80MesxrgUthRSCE6mijyqraVYsfPQU+/pM3zaFVZh5zcYrrP /41j0jpgX6Gj6+zoYS+zEla9dtQJXhJcxRbzoK4iEBt7sDV7p5k3606kGrRxJCe2 sOyjZoSXr44AjXelXAac5dyPRUlfIRYh9G41zDdHIJ9KmaaeL2UuxwncpZEh9rZP x9/YEKGKRvoomd2hHQHSXRq2ttuO1dIx5jB2iHIHbFGoXOmp4TpxVUXh4pgAAl1T B8475qmFuDQvgqhALrAtj7WWwPipQ5/h7VGFuK7bfw0UddW3OA6Qgxq3Jvk/UFYy gJ+uJvQENhT+ldVQnyjH0vXvOg4lhru6SD8kgeJQhpxpxrzLR1nuj7nIN8Ox6Gmu PfP2S5jCVcfP+yAF53XMaG5Fh5YXdti2PRfovpbu7k0gCHGQxa7zvRjxFEPZAg2d g3Q5tpk6JoXDLLzO6iGyTbbRkzdueZjSytXVCKqK/npMcCLQh18eCAnXXokCHAQQ AQoABgUCUyy0AwAKCRCvgFKHTdNAclMMD/4xmPea/oeF0u38G504YViM+H1jdqIw XoOSNTjqJvsWb074veQsc1xgzT+7upoQVBw9PbXz3JIDMYwmLG+VR35Sm6jfgBwV u60dcCX3GUS/qNz8JVYGsjEcXeHkG1IzBKFBrY6r90pu9Cqhw310Qs9c8NCA18L0 OxQSJxMOWyBUBArv4lowutvxgzzpPdXv7Wo33LbMtT1rm6lvnjEAu2+O5gmEdQRu bjut0bI5u1za4PJkbKOv8ybl5LfOxOY1G9y86XRu7YalR6Amxk4KrhDzSM4ynm/q uKOXm4fUxmp6O1jpWISLuJMsY3ql/i1sxgGU843AGr/UHClLhhjZ873cZ684KQ9n P/Ms5kXtmjUsXhESINHiuIraQGZI9BPKsDGLH33gBLOutBhiqRrZ4MtIYIh/anOP +D4oqnb5tJpeR1EWO7bduHSB3PfOuWnfnrcF3HzDJE5Cgy49KlqRqjpj/Ft/o2vL LX7vRYBqRFjz8HnopYQXvpjyGP/GFmxLe9IPMiNyf2SHWdcg4mDUGIMFjZaPp6rh DAilbIwCSf/70PqXMwwUdxSgXNIHthdWibVdIFeYjjLI4B27gbBV2bejkH4hsSVc T9ux1OKso0SOdRpg7QtrlJLyH6EGaBKrBA+03vXYp35nM0vcLDRd5n2RCOsFFxIe BxFXWmyfs7c8GokCHAQQAQoABgUCU/wlJwAKCRB8Vqz+lHiX2JtCD/9D43s1leCf yFI1ZYy/ybLe24QhONxCfRyl8k4zcy9EhgQj1xpF07GW5X2r+IBd5kroHigIBKqt qiYU75jCkobTylbvm8QtMkOe36az3MZyx8tjb+ONkGNjBTBuvybcUKcFeNeVFHXN 183fb7JBkWLq6rTIvcKC0kJq6aM+1AOJvdoYPqBq6o1sYCf2Ds93m3hsgEzhif7D 5PzxGIUmwtBRrWm9jEHTpiaR/CiGJ/LkhmpmVf53zmG3Ct4g14fW0lrSsGC7n+UK G1ULUg7VkXJATNZmLpKl2F8Vuq8XS+Zd0DgefEGpCeOkQtq5S50eCr/+RzEEGHMI U8+mV43u+e9Ldk45CJddnlTqvdjBtBfn55htsrcyfeeI4Mce/bX0NWD/GeKx4wVx JNSmYuZ5OhYQEWJMUF5w77p9ik+RaSv1/PoQJ1boO+5KdXiz88t2SIXQ665xlAyp 1dozxshpZSLoIwvNXw3x6u41KmahepIkj9WT3tz1bUjMEvdo3LMELvjaBi1afvTp mxzSGRhZ+0CxFB/lN48hXVhpoXDOfEkKBVeCmPtKKU5e0c158srK7E3sTv5xEodb QmhPUqvQuzR2X5IX8HXbFcnEtJUWDCRGForHE24JI94eS8HEIhtxKLVVK8/vt47m hxWeLDFpvrfP1AlWqctl+mCgOpaFd4XpD4kCHAQQAQoABgUCU/wlWgAKCRADSALH rKQ1CtBMEACjekw3eairU5nl+QsEqXKL9rdd8vdavPpEzzdCuAgxpovl/pSoLSAH ASZshhuuexyDb9K5dFjRXos8EykJKCzELUuUNETfpouKuDb3Nmlb7E17qZM3JkV3 imJGbf2/vUNqOsEM4EpHcEhClJhvSODdvgvuZd1ih4ZP2vjJeDdrJDn2rvrgAsCM WLbN/V7PJpbpDEx1+oR1ohG74m3o6W8WVJTcj9KhN9kVmOxPRQiOobKlDOeTqN9O JkrmwAmDM/zaI+Y4sonClx7Mjt0sIWvTCSzarAu33hfdqpYEZcfeQGFK2ll8RBzi yjjloXf9SAsA/yCALGelCQKNkY3/vxeR/JC3GmJgpNKjqEcOWg3jpPUl2rGvHuXG WT6/frcpVO6k5RHabgoqlrVy9I4Z+FL5DvWe14EOkbi9cQnTMp811rc+EzggT5OJ 8GXGOBqh38KFg5ZiSSqNJH/rElYdCUEu0Pp1LwPr5KdLzy94QHyIDQL1zWi4WSQO eiaqKcYVfNtgGmKroO7oJGlcT0gLc5eRnAXqlfZUcK5non7JjcCl0tTnq7O98Yd2 F2ijK6Nd0fZ4CwdbATbfysq+pNK+30YeC1I/DxBAiBOpuOw+gDak2PTBT1yM8PCZ 4WsTKojUriU9nVOm2Qjg58IPYAHiHnevp1977vxKYr0K7v8rIkdhjokCHAQQAQoA BgUCVAIphQAKCRBXWfNQAapKZMoQEADO6OUyQzsMi7lp5oVgDZq2VPN/Y4RAo8ur OHjRzBmkOUQ1eDAc+dRA/SeuBYUqvvnxcI+Xk5Ac9bvacdokfYqsGghoGH9O34fa mOB/KZiOo6SgrB5nbS1v42jp+i2OmFzS1M1KR3PWOWIxN+t5KihOvRfYiuj7CWjI +OxLAcqlSILBjX9/KrCXCzt2khQpDqNbcnscFp02RdWvy0CAjGI2eT2nA/nIafet AFDjzZiUCb3ujyCZiIaad2CLH3Cxq0Y2RtdR6ztmhvJ8ApfgCFCKxi834YX+J5gJ WEM5KjEyv2+2tU8AVVCtEYNKCKUIHCspoUgkVJpSs6vV0kX74aINU7YZiAt8AKQD wroEJ6s4kAS1hlEJA9AHr6uc75lhlFxuiPoGBuLXo8rKBmx6cbqdMwuVVIDMft9m qD4B4XPaJVeMNQkVZI6wTkQlpxH74kXkhbJwzLWYTwAfyUu1hpBUmPNS44UlJcZY xuOTTTq8ZEJLSozjhu+T4TqjQhndjZKl5ybP6DWYIFV5SsRaUHvOdbKpRAHBYX23 ZgiCJopUvOlzxRyuPVX1Rnz2HijNFFLm3wRhH/O7nYUB5l27Y44oojS4tw4FrLGj QEoUG7EoZ986GafZ8iJHjTR8mNJbzBLh0Io3W8gEA+ryuN2j6PKVnePMFRh94wY0 tewnvm34wokCHAQQAQoABgUCVAYcRAAKCRAWCZ4VWWrpKCS0D/9HynqSLhIUaEsA Fm7bHagsHkmQS2p+ClHbO4jH9DPr74B4YER94QdoLnYSSpWRMEmKVN4z1V8BJSAS 0QdPDddtgWSRG9Y3F9mdnxpEYx/f8v5J8F2x5iKhqVwzb5TLorJovg1v6S9D4yoa unVl1Oyidgf6XdmFcJri2wH5v45eKMU2n81QwLYoAlZOV/j16PHywvAlIiPnG6Zy 4ytjuSEyPyrhqmXspeNbY2WGwY8QCFDjVpR9Dik9YsMehqkEBe5hPWplQ1ujxpgC YhL/xtXveJH0ixUDU0txOsBeFTDL5S8m0CnEvQqX2LBOmOtp9/3gsCgjijp8AJYs Bc/1bk4QAix64gcqYX92Hzfdw1nOIVgLN1P4g0CWXSoTpY7eoUq8XcOz3gVUquBx PYfY4FgOFic0OoRwEXL539XO2vJ4iZj2EFxrD6bLvxT1IivOLJ5BKbVaoH1htXer 2UWWHJ5Bgbm8hdzA1zzrrVxca2W9iNKi6lF+wKkSQzwKRyPOHnm2mun+xwUq9tg5 daYA6EaBeEwSEx8nSoNFGjUnm0lMb4UImCGfjafNY4+mNTKt1n0ExmZibKiUbugW C4oDZT1ilRT6rwjbELzb10bsKBDEpt2nHW+tqsjryujqmMrgEfChUhWnRG8m9rwI UTzhgxy/+8lWWQSFA1q0nENBwJWuR4kCHAQQAQoABgUCVApw+gAKCRCII3pqU6sb LjqtD/9uzVhkfs1cfJ9dxStBdWtBYiKw37KMEYdiAM+iNoP5cNe8hUicj7F2O9RT DHPNiJNS09/eRHj8OAmj4BbSklm5BSbMDn3yoqnoDo0Gl89YlAz8hLVuHonFcwET vxyU1nM2Yi7umZgEFOQ/wjwtLpX8SrGna5eYPilH2O7YrOqpgLbQJv4YaKwiNao4 85rF5u0R9FlmNk/jLSqazU9LkcD/gg5ujxtwII/ws1bA49zvGjxRxkAxY80jJFox LJr9Y00hDpJ1keOD7u/TGtsbl0E18aMEylzAItOE/GpXliuvTiNns4tV/J+LUc50 AoiyATgnAqlh+ARH9iDHMUsu49DWsjy6RaSF4D922z1kCwscUb94v8J3mrG0Fl/a ucjbRglrz/yJNuPilVbHX/qgNcsMi8JqQXLXm/O84INdHZzxLBhzw1fZtP8RS3Fu dwUcFyBNgsgsUCIP1A9hUXWyrh0mZUN2z53ZvfJK0dBE5HvlmnrWz/7r44GhN3Ql sqO9O5SafTBGCUq8wXOb3jsuSCIDsS6ppcSlzd8yXqGHvDp3yn3OnqTk9iy1msm5 uqxZhPj8jd4j+Qgj8hq2XYVFC5kwABSNtE5gfYpQgaYydOjwykeZjyzPZoPyQzrz KCZZVX/8aJXVSoyKDZefJPqgFe29NPsV2pZBnbFgl+C4pd401okCHAQQAQoABgUC VBShbAAKCRCMv5oyKGGnkJs/D/9j5Z52Y7fVxYoXrhNrcyIpcwajH0hQKOL3ahma dWB8MBhEZu7t3hZZUIfTggHv4VAVG46oU9wcBx0vE8QaKOT/ZfcFlHxyRSpvO36w yRmXpHOohE0xq5RcZ6vU1bJdVCEcX6Fq5lrtX3IZ2+S7XGLX1ltALv233Y1qny9u Dzbz8xt7cRc9jN0ptvRwib4MLJahNkM2fm42nPY59P/VTwS/DFnMzxbhr6iDQ2Zd Ze2pxUn7am9oNIWnTpjhgn/XMd12r/Ryku6RMbyhh1zhbZLY+RHzC1iKAUTnB5cx +RWuYJrqu9/Uu6BEoWThcr3TtVe7qmB7i5Q6rZ91857rOCYZ022GFRxYBCNGRQCM V+r8wDrYzbLGvYDqym9SY0/nKRJU05tZ+E52cPnyAKIlXv7IlsldP2XIHyXJ0IlD vq+Kn533y2+0r7tgvs+vWmCnioKzrYWnh4K4RpE1/KzJaP76C84VgiVSwJuhqh2d UTQh+Wbo47BJ8S9jeQpHlEgoTjq7AjjRbvCbGu9u2TIvfKpXa2WSttBENklna1M7 nOocEz1rCUTrYfR9M9x5wj+yj59NmX9iJI9WbnubZ/XIjRSZVgsxpCanUlfAHVbM H5sJDYw43MBz5f2ymmt6BGL/GgWLYDgkyB+NmcSZMsl/lXjA6mNa68tkIcx7xC+G 821PD4kCHAQQAQoABgUCVE/8nAAKCRAY82hcACK/8//rD/9NTyvOU19S3Cty/rrn PINiWCjxEyVm7THeEpwh6y81httePJvu3VOxkEzqFIiy6TSEGUzff/Bmcw1BhFSt Gg9W9RFd7y4cICWPKglieYG+5d0+e/Ys3ITem9vUA3Q9YOg3gA0+M4WOWkOABONt NTA3x8evBBS+YLyH8XGXwR/PJAYY599VnpMh9l05Wkb+Ed8Q66fJiZEasedt3n+c m5bb0f9RtMnsKyYVaDq8omYyr6Gxc03aBvxhLK+hKSxYRkKCPaVmx1TiQrTh693C 6DRwL/XEG90U3MeRrJqIYtcjL4dhnq0j9GncPpZWFno1APl2bupFAgVtkoQi7M9w rIvROkPZV8U2Y+vLJV1Y2z3jalo506qCDqgQ6i5tTJdl2lytKM9Blqz7xQCNS18h puOU4sEmSgK6JiYkXNeD1iCfPAfKsbwU+Jr/J+LSaTtNp+AlY7HEGmejTl1LDOyF 8z57efRpIkplrFxswlqPozl0LaBuQre7U259IwnRR4JBllU/w3IO8/+LJdDX3MTq VCXyeTWyKr3S54MtKbw9bqGsWNCRaJ0lWDFpq07RA32cGpnpOZULTVxWvvnVReOv /IluQcgVJ51dbNVN0paepCYpI3XZvgNqQ3shkR6UGxACQA1cXEjqnrc1PrfXTVWV 3TMaegeGItEVDo6WMckUE+Xk3okCHAQQAQoABgUCVhvNowAKCRCV5kNz8VKUaYA2 D/9wJI1r/UglBw2pD+17QVdpdsHx2tmli+gy6ubj/1w4fZrjaJHG0ZkTVCnsFC2x 2czF8n0o8tAzHRGLIRolPHYz6B8QL5RX1mr5WPuMxzalt2RZlIVxDPhgeNKxOF4v gj8JfRno1SrzzFUQkdDMs64WJVTNEMTfPYxj3yakmoR/1v6vrelPqYv06pG4z0PO +L7jXAt/kxjnwZ07qOEUel8Goyn9ZoCiqc6toCkd/i0WCYW1E3Vgt3kXJDx+vyo3 wCigTiQ/A41tqPuG6CEz4AY8/APLGNwFkBdVFry3kMICP+Sv2oOMn9oykrQsu3+0 DjKz71RkPgUcvWks06v9xkgKqiduVuE+17UkTXvP/rszi10YSOPLxtBSyZR3hpKB M7u3quzfcLz4GPeCIcKMcpjU7jdCAVu1xKjI5kaBP1QonQAEDmt4/WNN+wgcwGZ3 tN/A9mbEyfRaTA0u7wzqQDqDadqdzhTGwqmKJmR8L9bCXf/Sb2Hd465Ljqyz8h/7 fyOMbVfEoggbuStI224UqY1eJ+lf7DCquMWpFiLTR2lH3/mpHW+J1C8llDu+cvOq vEeWDd5fS9muALNQGby36VCPL3o1oJgJNjUp/91kLH3kiqKqNFodBMSWNWUr1gAr AnugSopBe0yygG7gs7zrYW6JnMhAV6ZvuzAzVa9KlUNTR4kCHAQSAQgABgUCVA2B MgAKCRALxH3GTRNTBphnD/9JW1q6SS0qXP3NicMUwBqe7ze9nVBlC99wQH/mf/gT 89TteuHK2OXKMFPrgJMQqB4IFahuXHlmNHrPEF4mOnLO2Aj/tPXGvGsUxVsXQRfF E3xuCEm9UJ7NxvYLJfiWyVDjs+UQ9Xjt04SyRIo0LpmoaPHTzlobTrZ1RRGmxDCy g4nuRmTP39CDE3CMij3hC+vlsTxKk6e/194/AemWoGnFHPcnI85yC5Av9ORKirYy bw5MNaXmZLTyGR4lpnzKTgtUd1MiaUnjUQe59TO3YRoVI8W5WjplX8IiWjrCWIwi tLQP/VoDEU4beMNj02b2ZqkUCy48zypuVPlpmchGQD8dU/+fV6OZK9sHQ/ugPz7d MYii/jPypxfiseAikXf62eR/f4+fR0ehmMpaum4YmErj+/FwavMlJde1o/RTxwnV 2qP/0snZfll2Qh3LrsNwZfgDjbhc+OVABBCis//HRYku3CnCYJ/HYABcZ/8jRVHM OvyCM4FH38x9h5ZEZNSjAwfF1XbnQ45PrVeUI5w3fFVVzBr0uPpzNjib/D2xxr/0 Ef5uyjDCZBsJClIpgHY4qWAOlUbDWCW9bVGZs4cn4ujDEaz8L2tSCmlmg1GTOmGW QrGgRj1SDELUmf0WBbeCnavwW5IAQY9xcVwcsYj/rMdVlBkmjGkj2ryGb+G/egJc yIkCHAQSAQoABgUCVAkUrgAKCRDKvh6eLro2T7YcD/4mTFz7gprh8Kk/X8zrmlFA pKKhzPV+R6UZXPCq/WgB4r0UD67cBuIT7c4ZrUFmkq9nyjjox75Rq61KbchC89Vx wiCtUMJTpJpPxYMYri9tm+L3jL7qUQD6ePejYgaQebExs0PG9nKeQ0Cq+bJseZ4h J7Fp0C6DOfzIHOrCFbgUIpAH6yzsewDUssxa1Jpi92O69DbmbEFVS/9trQ4OJBxV SU9EBEecRKofdN84isCk+QQhrHLt6YDqwWmiwfkUMveIWU8/DGo7iS7vycGDanWo gqolwfX4wn/8QotXm1sTCWftuiiQPg+GYZ0WhqrlWX8W8P5s90ojb+J79bIGrvLz p2C9j8VPSWmrad//GWFTQrIM17katryYHNbzY8q0bkYB9rnBfhw/fJxSB8F9yAEL b4WDlpSAUpkRAiSSllUvJR+E2Gnzmth+FP/IIOJuTpoLbIbRP7OBbgJVgZnsvz8b DDmIbfc47N5mH2C1/Iwg5pxQm/7zsug7PQIOb4xxshb6IiIwu1mVuNybtUTzObRi FKPszAqGsELCge+Rvhiq6xMD5KF7BPZp2UktOzPYSA70oCvwMrObJ4EUWugVh+JI 2dCgaTxxGbpC6VaMlw67fiuXcMb/5xkdLOPLQbT4k0el7U/kAGXtbEYvQlrksSE0 KO1IXLjPoycCz2shR+9JSIkCIgQQAQoADAUCVA4VNQWDA8JnAAAKCRDM0u2U0hc5 6YN/D/9RQ8msyXJcVJh0Hohf3/d4G+ifj7s0jCMrgn0oBSDeCXJJOfQufj/M5pfo Q7PC8OBPuPujX0gDvdg6h+o/gttmUSvV6uS18sTLf3TkC/CEn7IYMhinda5z4uC1 yg808Yurb2xQgC3tO57MVnbxcGlXm7GPlU3xuqv5JT7LDltKlrfMQd2kaR8DAtlR WMtPkjzxw1pbyEF1MP3jUt4QDGiz2P/UKoDaHo/6CFzLXX0VHTIzdROeybUcoSK9 oGPFRIP887DwYrmUVFAtss46HJHvefvV1jVJoB67CT1jtK33rsfqJBa3xnAaroeI PFRMaVe3IIpHV88tZt7ht52M1P5x/dJuDvOgOEE2Fbry9O+eoqAbNdPRV+8DU4BX Z6o6VevAcABu3K8Q9cDrU1BoPC1b13UyztEM3/qAI6ZUFGUqatfIUwsC3iaWGrys YiZqz3INc1cDdv1Fxg5N0G8HNRv1Y9o/Fo843Ex1OjKXfzuG8B1I8XVy/r/KDzZE NOW2CNH/cYGI90IEgVcdOKWHUQi4+e9pFqy3nFwxtJX8DN+TBDEFLVHh1FRz0apJ 8MOcO3Dxrhw2gkJJGhA67yqYmXCXjhjdq30Xi5o2M7hESxEk0cqwocy7eqpPC2aS dmTHAJKMhjggBzDzNV3KB0KZEbAM+6v4qktUBvtRwHR3dVPhbokCNwQTAQoAIQUC UxD6gAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRADapwlvzV91JGqEACq aDhGIzvHNunE9ZoMy/MabLlPaS5FmbrrtxCTC/RB7+pCuJkCI/tByrR/QncZ+eD3 mgxLZai9FRfXalARa5Abg8KvmYsFpCU++T7Uzcl4DRZ4Brievk1KgzHFYcJJX4ZU 8w6tiAsWD7Cep613IOrs8X4X3aSrVxGD/uNwjam6AhB+Qw6tFxDuihMVf+SI8EU4 EfpVJKpZh19JWz/zG4uI4l6iamnDG5fsEuYFZgGBAoyubCy1Hx9NaLG+XHO99hJg Niq+PNKevzmtzBEoajxW2kFSW451Gle5t5tHwV6VzU8g3YgdDiuDEr01apnX9fye 5C0z+Op7xOi4RwA9HEvK5hlGCrV75qhdFj62dJPR9u9sZNqVSpVvyvZxRNgU+ysq kTtkrl7SUiaF3ey+zhLYJscEVG0L9iwWpd1hp/re3ZY0rQaBbQRsEk4XcnIjeHjp as2yBBwDmZ2yJcGiQDorQPQThfxq3woWqgy/pSQrsJjqfs9U1XbkVWSrdAN9ZfMc ID9oqYngz5rGSro0M5nBORmsZjXUkeB2jGavngmvz/2oX6aJrarWezw7WQBvsZWF 4axVwF4KUUadlNqI/xADav95lwIs0MhSuVa+gp8CH/pdsF6au9H8o8LLVDD/avr+ lS/ztaXkavB7IyJplFNSboIFxf3H2zIhTzMqEqCsQokCSwQTAQoANQIbAwULCQgH AwUVCgkICwUWAgMBAAIeAQIXgAUCUypIQhMYaHR0cDovL3BncC5taXQuZWR1AAoJ EANqnCW/NX3UFVgP/iw1m9nqHeNGi5AiG+dvl8e22cOsS3NWkhwz7OdSNDLhrQbl H9+AN7y+tM8zJOsZdWr8s0wv0aJaqbFd4FkwMMZ+dwt5h9gXolcGW1HmXcIqmCku CYq6X9pbLxncKxoN2fbSHkkgoEbFxlwkDE3UuhkuPTs1Y6PgbjmBkxo5Zrb4XsCM wUf1EkJ0wi5kCGTX09+Kj2r3ir3mxYA7K4TQJ592VFbpC3jHEGRP/KxsdCldfHy5 gVZC9SF3iTWiU7tCElZnnE5EpXyOF7kJLaZrt75JITycT5O2RghwwRUDbhq3Ntef +HXO1tuEG7UAfMx5qO34ffv2vyxoxvLLY2RFojNxfuf3ObIGqkVVUvJBz4Dnguxu bOUemE6A+HLdj1lKiSJo/NW/mO7Neitl5ZqtNQEvgP+83qUqUHW1L0xMYDla2Zf4 pYPIlxa6nH42xdrzYH1o0EWPHSNWWBhmfrF4ZGEhgFJYnIDR9oPbEi6tWoiLa8rP QZsucIdOuXTqG8OO4dxD+iYFdxHRMxQrHvljCo84MmGmkZtbCwHfiybvqpsRd8b3 Cso9eUkUIc1/UOQAL14QezrSPgkO75A5xR9+J0cLJ9XvLBMAAdg8Q2hK3SGtDr7e Rd7lFYXGAOA2LSPNwTwHsv7typgX98JPwA4MhmUppiqz05ZbhT2bgmSs/AJvtCxB bmRyZXcgUGFnZSAodGlhbm9uKSA8YW5kcmV3QHZpdGFscm91dGUuY29tPohGBBAR AgAGBQJTr6YXAAoJEDwMM7tEK1vpM3kAoKbeFqQby7HPhZ8vvhJqg1q9r4pKAKCm c09EsatuZQC8MCcnDJlahlEn2IkBHAQQAQIABgUCUywEZQAKCRCzPkZCy24/821s CACHkmzPsV2iUrtbtx3lXo5us7YaXdCSrahQZtNzAi2LK8mZv9SX+BnjmM4uHI6k 2R6/laknySr+78jTo2WC5CXW9C+ZRLub4V2ESdNb8c3q7XYFx0wWFmmAy0rPCw8e sMcoGDFPZ9WUgggEi7EPPT+jFgv2CqEHLgkZ2QFdtgeL0u34m8Pz2yg1LgVg9oLp cCPFHu9/Pc8LtozRvvgFfgImBWbemAvW06nNx/IEvMpzMp6+daCP0Nk5aDeGFVWg mB/p7yB2sQwJnlHaTpwqSlRfnaqIHmVeU3wUONmxiNILjgoXmhMo4dT6ENjahKGK K3VnCvl5TOY2r73WAfJaVaGFiQEcBBABAgAGBQJU6MCWAAoJENQeLCdg9OD0I+oH /1CbDdm1NyyRE78043VTv8NR3MmvgWSRNfTt/PeTXTyi+iiamqeIA0ln9uhR2ejt EQehaRD8uHl4CKaeGpZHyPdKP4TeLQNuSnZ4UBVLKSZaS3OGRUKtCRfuvQAb0fKC fLGWZmbRbznpwy+cigbG5rbfgZstHVUz9DcqDTYAuVA3b3teGXI4la7qjkwW2215 AWZ7A2M6JBnQf1jSe3m0FVt1Zz6DUeFQFT8jDOsMApddE4BZWQ5S4/ncik7Q/Fjx ykYmpkHDQOiNGUAxmKrre6I6DTtITGAzP/mpKqbaXrLwNjlTSWoyM8dhLvxFEkGZ xAh4R5fVksiS3EVOIA7B/iuJASIEEAECAAwFAlUF20IFAwASdQAACgkQlxC4m8pX rXzoFAf+MVr1SpmNZ3HigJ+gxmBzIMrkJOnrQlQaECGkjMr0oeX504bTnzF5K1Rx nPQbpETuXC1xDRN0Lsxfe+uymJgW0/QBQmvH7kDv1hG+1egeZG4pDTPFpZEoT7xF bPekfPAPeTfP3+mdPY0j3hrtwvoLEYpdaBycFrNI0dSAgZSJp/NPhySnRZL6s+Em 5nGjatCym456yrrujKbRoqdKhHuO+XoR+kB1qRNDKGKxoOAxhZpgrWlF07m4LmMq RZnIfnQxI5gtF3eoXsYlHnZTDlyRId+Q2929tjAlMy9Uxp7dPI/7ohUeFYX+VsQE m32tzvavrhQ8sdd4AFy61bwoAsYe5IkCHAQQAQIABgUCU/kcxgAKCRB7WFswgHwq h/qlD/9G7Ln3tcsEoNDbgB05mUx9eUxpPczxnZRovId5HLTT7U+eTzGf3ZN4wS/u EK/5h334/fObOKUj+A6g+DvHyxVHEM5YGbFblxFzSeoBzA4COrRozHrlSdf1J88i NFZNP2HlLugt9qizciRzZBMFAIQ0CG/s0r76sA3Tpazu3fE6LpMiISufW3TF1rkE CfjZrTfXqKvjaDe/PU8cXfJotInehaZrEeKXOjNpJP7RYNFTejCk4zF3WN0PoCVU K6t+NlqrsK5s5k58C5j7UROV6XenfvPBjgWv+JCB+xTIAPAT9FM3jwmxts+rmRL/ O0Lc2S3EeWuiV2Si5dByekgM2B2h6PHN+1QRHupJEc61lgIdwVnMQQctNLzP9LSB IFEfa2qtvIjfHDTn0JibN9Qbkq8tIkPzRynZxd7KttyB9QRgcpetffMWL3dZMv7Q HLA8hWk65A/b2XShfQJ2NemT8XyYH9arfDUAnDI/DkceaOr1n5eaxldSgGnW/728 GP2SYZmXkkGja35MKd050bvlb9UklPWriMbAI5L+sTzdyV2xe0vnp7JcR3wLICNF RvCxB0DG8P3xLaSZZuHYge0RWVGOodr7B/GADo9t4dfGgr3ggtqirE1NINGSFPS9 tx9KcSWOAc1C9U5fH8MHX/2PRTH2faieTlb+NVijOL4TPRF1TYkCHAQQAQIABgUC VAN/NAAKCRASbrVjp0sGv/iID/9407jbuml93wcgSlsno9abYlN1JjZZSkbuM9NH VyXe+m4iUP4RXb1MPqlFNHNSeT/wpLhhoUM2iAgdjl9EpT14pTfsmig0QCK1BJzS OWK/3dL4SwUADLVOYitEtbjkws4pLJMIolJVxfB9JVCZCW4qEuYEI4NKmru7/QDQ 38Jmqz6rULWVhOjvmABX4gb2HNm7ZfgnbGlKJjniMIhWKGFuxxYQ3cvJtPzXMEj1 JJnvPGqjD4S8Pm5oRfW+WuISEID5OaLITIrKxWrS7zR3oU0mVi9k6w7XY6q7mYle NY548jvWQ+KOAIapzwVBMLjecKb2cpy73WZdfJALd6LY0iLeqFnAf4+yo6LuPl4j 1hdkyflo71OBlFRTSw1Z3O9lviRlH0UvMPRqX7qOXPLgSyLJw5FmsgQ7JA0bN+RB zKEodtaryQ9nrknYTLLt8CPH5uKcCPeQhGIoAHI25Uz3listTJxHqas4KhSgcKdI uZm7slemm1aC4wlZUyFXuWXty51Phd5tXAtZ3obIUGhvcxhZyFwunHqFtp5WJ+HS HudRfBR2lAF7vqVaaP0sNbTOjz6zjPnIJsUSuAvpIqetrND6YYIVdrunWhqpq2XL Ma2lUMRwVSemS51Pu6yXzejuMKte8pzLHJ4I5wftlVtzLJb8X+omKtUznPAl5RNA zJBoXIkCHAQQAQIABgUCVAtdAAAKCRBEFz+hPQWIiFOnEACzKlAOZI6RfoHS70wd +lNmmAGa4P4nKH/W6R0AVR+4PMKTJZ3kWHDG1eoaCR/whcaXLGq+CMqlo5XnFqj6 i8ug3wsT8nFIf4GFQUg2qEpY2ycX5Py9I0fF6PY5TJl8vQnlVAI8Ruy9Y3l8t6BW m0Di4k67EkxtT0+reMPNwY/BJ3Ze3gTreyuSoJj/ObTchn6oCDOrhEvdrbD/SGGY Wpe0wZunqXpb48DcURVrs/W+zspvhplGN8a52cyLdf1amvVP0w180n2GmNkIvSAH Z8nZ0azRnDYK36L1fjg8GoieRMfnckDteSHzlKpIGBd5THATQU4Hu1djqbpXD3fy c3NQCZHa0tIZvtPzsxCEwags9OITaeFYz+K7xRBJ4XohjKuovy5Y7vgqDbInaSxI Jz+o59Eatfo6hL7CZI27EjpzAesFPcs0zUf/FdpJi9cZ9VlRcAIAEEqD7L+6oR6z 7/tQox0sW9fM+wUnS1OHVS7fAuZ4yTymCsPOZy8yIg5cs3xJpixwtaSPUgUzu0dO LYNj2ylRMSlKdLl4mD+tjfFst71yPDNQ5xdOyEipcVKNlPlhr7ynZ7W6SqBg4gej 7JYVDgPpif3Mm63rTJMt5TvWQVdVojCW8fiEeNahAHx3FaRrOudzXx0VTmpnuKQA TUVUgGBrehndnDnk8WME9Buv8okCHAQQAQIABgUCVE/+OwAKCRBZv4n6RzeIcw5c D/4sk6UjRQEqjjf1uqYrjjhhszYq3RGzdx3mTaGXszvEOm49Yjae87OuX0Zkt2DJ LqTSeSJrqfbQJhVV80EQjeq/apGKBRK/a8vqaN35E4lkdgQfnvBU8mgHXOdGIHmd FUtQmUXEV7n44iqxaJ16F50aby8qe0emYk/czqVknw5S4EERiNW8KRVGf1/JBdcD 66urOuX/ZlFkVkH8ALfH3F3khSF7naBOyWZ/KjjvEE+E3qt0/FiXbUxkbtFvjP6/ ToUjbbOxiGUH4xNgrz7GtL8RZYPHvO2qX4J7P2wiBDq8uYFkcX0PXpwS484zMhxL 3U89vURwuyBEc5YEEqOAs43rp98IJmUlFs+LItx82wkI3OvUnV+UhzaQHD28OP4F fqiU8ZGlw5Jkh6hESY0u+oSwjprHiF/3yHEJHZI4DYf9/EO6F/FdWwzbhVAGVS6G B5UdZ3ArIbK4k6E+bIF3JpqBWDjeT7G1tZ95I+Xtnnk55D3Z2zVKdTn2QnWat6M1 S2ygRnjSCxcMIsBdvZ6/zK/qsdoblBl7JxKeH4zh0BP0oszupX+AdyyCeJCqo8Wu vw91LNihJGO+6QJqS1cGMORfkdku7YAPR+nfUPv7yBPfKjfgfpWWKIGyV1eRXT1p PHyYS+RhGnLdtXZMDGTeHOjgU1Omi3cAO8Bwjkq0rKogW4kCHAQQAQIABgUCVjFg qwAKCRC4Q+b9jTf96RYhEACMVVkQRQKeZPIj/M09DL5MOg/RojwPQk8Glc2GVGQo R8AAQq/w/Nn9w90Vlej/AaYr8zdufC/KGIBIOP4/3PJUSkA0yNxhyLyxr6TOl1Vl bQL+PFI4IOjdW5rXj6Q8iyodzSdPpE8GaJeA1jtA57wsPZk6qwk+AchZzu7omUaE HF1kXxTasfgXxAKf5mNd+YD75ynUqxDGOF9YHWc73Uqj+VndJpYNDNmLVLMqeU2n WM4uH/f6+QERTxWZxzLkfOAxNDGlJEp8AOD54INalwt2TjGm5DoOTyDN0ZaQE+ot pKhFMQUlSO2OY+hT8k2/adXT2awFogM4KgyZro54q/eYfDNZFsn445BHoKPpnVOB U7J2ZBN4WYhHqDxFtLipINOG1/Th69OP13lhrlWKc+Leua+F7Sof4r/ypkA4Vyvw P/Um05XL+tIMSWyN+yK5BaWx240RvCL3LEV77QTbdPjHAvDjzA98xdZzVwXT3q4o vHEk3dDp3izxup2e1/6b/uUnfypZooRrVnthnx3idWUJwt7CChuv/ErsHkZplakJ GBEIYMqbOmZ9jyKxrP+DBgVjCm5GcfBMs9FI6xsEtOHCRQJlhPCHe9NsUbnkccZH xlROzhYrfg1mkTNUg6bejgpcvUgC/oNhUPcFRuQC/ZkkdojXVrXMXrYxlUa/Yqop iokCHAQQAQgABgUCVAaqaAAKCRCzRk+JaqFZSGgYEACHNA3KhvGLIPYSaN4FxG7f aChb1feM3crG21cCR2L+ghWHMzamG+iVKVWstvRdIAkaHg4vUedBiKwZS8JSfUr3 5FvuwzoXPPkfCexFOKT/LkuVDz79Zh/+jzJXhxNCQ6UP9yeHFg5fIdQUj0QKagXv n+AU4T8XIT5dP3KSJaDfpt3FLQ//RnzKAELL+KztcmIZ6RNMLeTV9MWL4OeaxwpR H4C5IkBQAJbynQ79M44nAneO4q2kz4Y2p9+BsjnERcPm7bck+71jERVn8hUIT+Hk yJ0G3gkznrp4nLP/pVNNIKN3O9bzjeJj2CPEFMmxdmSpXru3zBx1unl2Ur+gpygf FSOilyh/5xOTqOHpSVzIgdB1jlF/f0GvtuEdr1WDiLy6WkAkyrq2BfxC6choAunx eqbYs0ZqPyfV9xjHARen0kvAeEIN+XJ4p58MmOObX9Civ7aVSxpneKum2C/Ma5Dd m8X+xdQ7/zzLcLbL2zKUbwRP1Xp63XuyD0UQ490m3Usc0iNu054cZpW4lcqZkK0r aOq8PTBpIN4rrnoGi3CHyczbwmAevBcsA1nk8jeUSVFtZCtU9BZHJJmvdkBqzmv8 ChBuhJJt8X5B45lWvySrXOplw3fnMxG8wj3cd7L8MRjIMjIcUmrW6gV0g5JalR+W WSX1zaU2guTrMvixzFD2P4kCHAQQAQgABgUCVAySUwAKCRC6nHgGHd2MmzeGEAC2 W0cDe2Uj61Y9RH3X1d6UdiwD8R+q6uy/Fa8nojRlSF+53b9A+wvpjxPSpXcGuR8b G8vBEnk68yVz21kz+trMnWuTwOhTA0ymsWxCm3RKC2Xs20PICDI/ae95q5Hundyj XU9dD1ATmIqaRFrF/TW5bWVhaQz87WL6DQY3+bfiTPyIp5Bokd9YqAnHkI6w8j9j pC5exiNB7ja/pZSgdSyW8dAG8mJcDKQlujAaybJonL01LiSVjVdnM0WRX3Nh1mSW cY/yFbuElF1mK+7+H9TF6/K84CzbCFBGzqNNqy7H/ZMsHG7CPGUahczacEir3kOd m0IyswcKG+JwyZ3CW500BampOialiwB74o3nA2eU8Ov7ltrkFVK33fpB77GsrwGQ 2blXesvbWIST9ll9e9dITW3ixMCvI9fnZ7qFA3wTN88nW+u3wFu56FEPL0ovfU4j 3FkZO+yEfstXlTo7Qrf2eaHkttzUfTCGOOzZvoxNpeBdNyOT+Xo4mzhsdmU2DAGH OVghmyHd29GiD3vD+tAH9gk1ZF8YFSiX2CP8gYjdavKCgERgdGIm/n6MCQLPqa1J 9gyA++XBARjCiVDzt6XGiHH2cRnM+rihY6F4VVqWKWosIUus6jBeEsB1y3Y9oDcr /Jjr0YQw8bhzFHRfXk+EXlM3m4bRe/dtfcyDgOQcwYkCHAQQAQgABgUCVA+g5QAK CRABgXqwqvbNrn0RD/9v/RmOjGS3ygUg3nM9frycW84qgwLj/9mot6Ig9tO+UQNN oNJLsxyWKXUHpI2VTIux6rIW3rS0VXCO8LqaqgmjeHXDuxenogL9f5Ytnv0W4zKJ nil7588lGbr3DsaNFDYv3kvET/zKAk6c+blbA8Dgx14kGkManBOluqA+XxD7Uvie //RKhzQXcxImfFhFKCfsAygf3e++j9EnK2swfMqtgZ2zOgaZVZdi7PwoZyoDFw6n dvgg6VmyS7d264yEl1iOEydhE7EpK0nhOmxa4bdUi1ua+6ssmtt5S0pcO0tN0kEW Nw0SJOIHPlkkfEiCxYiZ++7i8xM2XMxn0zb5haZOLMO4Ojv5iE/AJ996oLZZf6Tw YuViLN9Jdpjms9Amc/3HNjXpCuhZfuirdhHyUdnI9SQ1wEOhH0F44al6XoqZnSvd SSQ553ik54ywE/cPEYMwdnmlyo9PllO1VvA8uunsy+Ca+OMvIDUzzEX9BpspuRbv O0RdzfaNVLCQq84pxO8PllMNKSPY8CguGd8yAd1TJPOdajBH0syao3bY6V/LwCoB RkECIVS8G3BM4Lrb06VlEF+F2oRWef78To5TVQZsGavUZG9vh3I5YfdN054oeIoJ XFTp78WczKrhcuDf7Vhzj7ip0HUgGYGwECrni1n3VecrAZ4eI1x3luq0FTdwFIkC HAQQAQgABgUCVBKWjwAKCRD1GxjHICSCJJeSD/wNVjPhbYCl00fyt474iBs+aIJe 9ZrAtaOTzpQbwCsdA2HupDRYNsna5960A327DAd3mYkt0uLDsl+QugqA8g3Qiv9D ujZ4T86ZYFXAc1sGGZt3UUSrf70GQoIvZXzgA6Vu+kudlszmQzGPokRvt177Z0F5 jmB/td1deHCTG8ChcYUfJ3ws9TboKNEQcPlk9tJPby3OasCi3m7cJIVrvgCaaLwC 5cwbCwUDBfpQ/hDyz+I0bqlFkgjpLLGSixguf7wqVxn7JyRvtpsTlUrApN/oCeNt O38cUXzW6DlbPhGKfG9wfrl5puYumozWOCZzDdoQmo5Y8LVfvK5U1qZIndiUF2CA CVZWHBdjACFvvqVxZ2eXG/ThkoHlI2u3nDv1iRTznOkMOaOWokeEP6rUHaNc/Egw kPRRs273cdqYuc+9wgZnM0rm+aW9gK/rJ+dAUsyNv1b2xROcrl/jso605dizR/ht /P2sumlX8nzBqieQX+Ngm2mFzexdUDIgnPK2rZRoeMPKnfWnuS9nfglRA8ptP9dz 39iy2em44CeoA+xq1uLmniXqqjSKyvqfgZHDaYIdOmSmk+0vr38jYDGfqeHXQGOd AJu7rGXgpcnp1Y02f143fersIYhZqzvQ53c9ksgW4UGVhdxel/BCJ8Ny8UxZhqLl JTbiFLE3HmvQIijoaYkCHAQQAQgABgUCVBwvnQAKCRDZKfKZK+8KM/h8D/wIAN4R H0mtV434gwXq3Jj0GeJFRWjiO3lhQ1mdeJq08jFbqCjZ7SITrtNjAAnCZAfF1ALV MuPDgPWoiE7KNKI4JZe5EX93yjNj3sMeAQEBThh8rHlHdJ+e5G5/QTbSUS+X5wb/ ESZPtSVI+cXCXh5oN1QYK58xZZNoHQg43FQncruI4j8HPaiThsIgWZ49fpjOmj9m p7CB8nHuLxrUG/nCcOluKWSsIgLJMeHcpmhWJX7ojjPENQyHNMkXDNQP82DiX7k7 vbanu64sGHR4Zj8l9JcQc2j3EYl7wobVdfO8RUk0IO6BCU6B8TB/GJL24J4jxVRJ YJbo8Co/uvUoNnAkMQptID0oOIb3YqmvxcnJPVyj3qKrndoUuaMJ0ByDAMpmx3/h K8ZHLr2jAAWiQEP4watJTEwJJQ7LWYjbMWGZ6pwhZcAAmyUWUbxbEE6wHntl8i+Y AcFXrQ0jiBeM3EcMzpwaPfrZa8wbgM1cbxm7K8qJgNeE3VXYOJQfwOaj9HzIGYYZ i7e2uv5I9wEsh+tb1bu0t6kTLAFke1fNYEMYDmiu2IqzaggcgDwn3nTBWTONyBx3 lI0aRYoM3sfEnQdU4jxehBuvW/ClpS2es5qfM/vAia9VeiQ0gHwUHW7srOW5vY7p OWxoCCAXrdb/3bDsgaF/na4tDjT+MckJvlJW6YkCHAQQAQgABgUCVJCdNgAKCRC4 5Qh3Zkdar6PQD/4smUJjLxJgdoXxB0BI1sayIF5yBoGKZiHR5IesqAVGJ5zrAFP/ 8fbhTFYng+9SqUTj7oaE00Qaav1LWQs2wPIsclYa8ChXn2IrQp0P5oVuFs17OwCC yKm1EGPppi7h7gvzz6s/vIa2fXc0ijlpuU8G3H+B/Ck10HlLs925AVyA15Gmr6qk tKCvQV2DqYv15ICekZbraeUowHsjdot+FMGu9OEAUWwIBJZu4Tx+Or3Nfwrg2Lat IG/H4hyDykFfI/ND3zFCcMxhs1Vtx6g8ewCWgJ/AI+0m63YIOPUjs71xy+5nLZ2R 8sYNsK1xXq3Zu6GHcm4dRA9Xg5w3z7rg3ej/mxOD3j57TIMjd6xQuSMy23abeMFO RuKV2YYqWCgR35dttkAsZhQBfU0ZmzG0GRSOXWKONfIY/BcoMPJsuehP2KyLPEuW 0H7SCGwqKCak8CaI3cLBA2J20cuIhNYQhsFIy3lm1FRtxPgi82K9rHlAh6mdD5rY ssBzN9jqH5EX7EnBg1UoIZ/8lzWDMhRqUZYd2pXQsXD4Vq5vCASka0LBfj7aGKF8 gc5pb7LWlAn/VK3alI0pdX4x5SiPsbiz2a9Z/xnDQyin8uYxBaNpBKRZq9gBLoOF ycUzUuxk7stwdjahEUzwVgwcPHlUvSJAewbGNJhgvsRLdzcZuqbUjBYlsIkCHAQQ AQoABgUCUyyrQwAKCRC+KYElCJblgZmBD/4g2MlT1IcOUJLrXsQVlxFsjrBVl8zG 9BoBPSPM46gYxknqDu3UoxrEL9Ic7teNPEq/Z5U4gzHXZ48ZcgmCNSbyzofQqqIv PbWii+QfZ1paUR6gw6lkT4iy2aJzx9bcA3/boM2J3lvfjMdKX+M1/MrcJY84WuEv m8WJ4E5D2U6N2A/4EiXtru5XJiB3Ml9CElsTjCVdocK7NmiGavxjUywh6x9TD8mm v6kC59ltFQIhbyI3YHzXYgCRYN8Nxf1eGd3Hezcu2hslpXHV4UptgFiVu0OJGroE 9eyv4Uc8C7TE888YQinykWXqLxmsMNu7MN7z+cRNnEgVBjbdK1WBDYChw4gKEWdX 6C1m9iGNhIItZnQM72W64xoaCmK5FcRlL3jM9JFuLhLn1kHHmSO7c2l+M/M7Syzk +P5rI8kNBkW6gycyiYeY1+MKL00f+cdQ8jrLOE3ncieBaCdLa9W0CpGuBAzf98+O Xw+gp+iv3ZfiYHYBG6ui7Yc5X4QX0TP1YiyCQgYNlRtGvH3REHsaG2hJxRNJZN9D 9B2bTxfFDyGC+FrwV6CUHUlqz7cTCGMo7o0fYTBwjvIYBDST+Y+fJo+DRISG7nPy tnLsiAXj8bz/oT2lhvxtYubA8m6qMXD6+bncsXpRZ3RcrRJjMwud+JN3c/CxbNkM XgkHp3tfEUyxEokCHAQQAQoABgUCUyy0AwAKCRCvgFKHTdNAcjf8EACqqhW0ZQSv cUNMcbCrwAVMFGbGtL+CYuZheLCTODOJMYvez4fTrkMmuPGR9Esj8rDQnQIWGXeA eDODpov38dv5lKZEgjMERM2aDL21RM3rhnOOGCzVuEZzVYZqxfh1g9CF0KQsvLPq FvbCHh/Nvj9l91tkZ0wTj1vrm3Qb7wtSaMJhvz5Qwl4KKyldh/e/ipznTGVgfxU8 hvX/tstuaZ1ew2SEXf3kjjYMG6oJlQQxJUmYVF5H9MkJfPMC6FyXcMfzAHMXT3PV 6pcAtBQcxa3zGTfz4ZmDOF9lc1JfBHyUTJ/7QwyFctFXj7P3fQClnt6CaTLjwhbF mok88TDNng1XC6hpODCk/M9/AFtQdWQSLBLLc7DVggVBjac2p1T31cQw3QQjWS0b 0A9p5Xwn8lJIKFWixy88OheT9+b6rlzDkIIWZqw/iLVnxIRWOFkW9I6eH84/kT5Q 7Y52LNYwcmJijzSr1ZbyKQplQdDkNKhYTRU09PixR90ng/8YR1JLRo0phEGplPzC UN5QydyjB1Ix60MUiehaF4aaItKhGDQBlL8b8tCgz51H+btJAMtrTqZT8+AX4leE IOGA20bi5YMMO/LOkt7/0jXUJBagBRxv/t8Ufy+m5+LaqcW428Fh1GRnn0Y4GG/k NorOYlVr5O+ZPNDnAWci0DCpgEQ2O7RKnokCHAQQAQoABgUCU/wlJwAKCRB8Vqz+ lHiX2GLeEACw3qSYu6vz4TlJbjtiRr83LdnUzrqI5zc5ZpxPdfEt2IzXwvE2EZG9 o1nGh1QYvA4rUe8LfqlKSbikPxZHAm5pcgnUZ75TqOX1UDL/qYNlTP2KdEAOhGzU 4Sj1eQ/K1fH+xtG3CcgQ17EbD5psj4B4fNZWxSJ6Canj0SJq7WwwXvDIp4OHJvMh 9RNyugIgy3fLCZkh2yCIMFAsPaffWcMGvQkWp5p2EEXYef7Fyw3WxaCk7sp00yvy o3kl44fCN+g4tgAzbcZSxuIStarh18PS7unN+r3d/aJKTPwcL3oOmn46mY0S2Qlf tGeu3swbLaV6ZsvvHGG/hpAwhE02op/4WMYoo+zDttFUc70nZMrpDuv4lU8aqNPr /oeXyNWhGq2X5vCIJdSIKdZGttbWv5Ktb0Tg6I7AGTsItyqxT+ejizpmsoQlin9y nKO69PmsKIf/9zBqJh5IHaNFOz6NYCEOAYTrtFH5/fB/UU5UCpYgnvIrjVa37/g5 r3+UUSLCWOy4kLutZ6bsqd//hTZZfB4D1HQCx5SHkd1EU7Xykd5hhgNbLdw2xyN+ gwjzIUuTbL3zAvLEJxKnO7MTi+TMATCkJlezZQSBtcGmlc9bugPv2OBhottUtDnT QsSnSimecFWo6pT7U5E+cxJp888sg8HBZl78DHNs2aPe/kFLetpPAIkCHAQQAQoA BgUCU/wlWgAKCRADSALHrKQ1CoaZD/99qUmaP/8KUZYC20XMhrxacyuMqkJehV10 qFRn7OlkaIzy23D5zUcvVuh+CW/X8TPGS0GuNFSYK6Ap3ljB50WZkyW2szeqQDwK ap5EJtS1Nm+3pyEX8XkGP0EpjqIJf/oH0msnaFC35gchna9xFWYGMiC+Eyl29Rf4 5T4GtC8uenI4HaFRDhyk4EpPWm7/Resc1K/mAMVqbufnuXVlbYbKsmj2EY5nmsE0 4sOXU42pqmhWWRzl7ov9C0zxSENSLX7/K17lVOEeubvTaLKjKAsRlKKgPd/84JUQ 5kgJTTFhDUZb2YdnbMlS/tOEnF3LEwVN5zPNGPJnK+dxTAO3O10JXg7ek5WOunlQ hXnRT8PaQLsCs+8b3cgU/UNGo/C3/dROFzsNP3f2U6mXvddS4UItlAKW82wBtaLU y+9wtZFSFdWlKFeg89qyMR/wHc6M6Fi/r3RuPy1KJqEslDCcXm5VAb9jGe3T/uc2 +Ute9nRupU2RaO/lOIZKIP+IaabTtt3SFR2bMj1bAZP8VSghxNcUNbLtFGgWXC4N BTxT70NN/DmLNvOeUw/+5gbtQ/gu7tLwYJjRU1jLF8APtNb0shJqMPC49m2ZiPgt zj7dOvfwytEC3PcYxVmp7qou0Dcmd4oLXyvsZKSFYWazkFnHsXlpcgEUNhJDD5l6 9lMWZqABtYkCHAQQAQoABgUCVAIphQAKCRBXWfNQAapKZNLiD/wOJmEPk4SQaAPn 5w2h4+NyTKg/YaYA2Txrjuk71XPIJazmrmPOF29Cfm82DFYgE3l80BmN+i5TW6my 4JhtHalVPgaN9ANM633rcQpjiS+yPzqlayexYsGrFX4rApdla2QiSU+GBDKplZ3M 4ioxOzULWt038F7+FJGs04y3VYoHyQWRVDpUBicBKUWrksdJXlC061TpWJz4rDWn IDIoWb5aB7t4n98doNlKkf8U9w+MoBhvtz7Eu51qEHDpnbDLUhvP0pSfSI6kyHLQ R3VayZYRUzsVp2enIp+Ggza5jBlZI/DgWXsdSgQDKmBptXZ1A4fK2yaolTx2Xg+b yze+7IM0SoLNhN8pxeH9275z7qC2mEs2p9r0XYU7FlMzFo1MuPHW11gANy1cR5NE J8Me+3TUtbeIv5l3hGfhlYt6uqE3WF/FCFZx0UJ1E65la9NtLi6nLhI8+eEBVFHP fbfMvJFyvNbyesPEyBC+KBWhRW396k3+JMgzqd50Lm4gsFW9u/u/jDKn3UXPyigz k0bzMbaXInq++EYjV6pu9LJetZ3q28/QaqLJUl8evjEQlk95+WeYDuYPzs01thrK qDDQREUh9eMqTiBnlANiy3aUtlUoVJ7JrNxEOYFIcrSPylzvf1DWCSM/7O4yXyTT f3StlAQiQqAov+28DLLY6B2aGO+WAIkCHAQQAQoABgUCVAYcRAAKCRAWCZ4VWWrp KC/vD/9eIFYBfzU/4OINRv7zfWQ/VlPRtUxv0CshxqSUxS2oqFENtZu5M6ox6E8e rH9sJV3YaoXVkn4TUiURgcWQiFBVxxgVFcKlpi2EifNbbIJ8ydq59z4vGvj0l/Ud iihXvuUnfjwf3gSbl6nKTqwGy/r0BE1oc8ej8J7VprFpqzai+yTAr0fvuf1DDfMU SEhoiwYr+TxM//sX70XEKqdWXzw9JYjeDFkTMEast8hmzKkLycEGB0oSYPwv+PBj t+Ia9oeNBuExN/2sJfpfJ64356oo9p41VUjq8rA29hFqPFrf6BsTJ1y1smnh3wIZ aqDMbwvaGzTnFfy8/aBbdlb/H3ppP8tuP1vnhf3BknXKWbNBWTTQWAxuRnCh1NDv 11TlLrfKAKCV6ehLHvNCDvfAuXdeOHfTkiWm72fweCcjYsZnTlz11FSjyXc1J/D/ I6i+lFSjGLb3LIabUUnpBKwXdcCIAXfQYzhYoRs21WcS6VjvG+JerW5ltTvcmZhf y5i7XNpYqxonHz+KBfDTioXnNQiYwI/N3oeA1dRGnJjOe8p3lKdMw5Y0qL6hUMMD 4t1j0KvTQUOriHL7c6/HCwBX9ezOxvjHRBLjnYRDZbgWCgHDXiAuAAqxrymXSMPS F0EP5L2myfd3fzxyev/saD6QKEEFYpFIc8sfKOiBYI81WwxPHokCHAQQAQoABgUC VApw+gAKCRCII3pqU6sbLoN2D/9Pp7BfErn+hew9tJ6O+fVnS33jpfGq9Ygjjvsj SDLPqMMMpWV9hsk/3Op//3XP8NS03vpVsj9AA9C/bOh3iCuGGc2f4eJUmoiRjSkw eAhxN4aCQcYqtlf1fZP/Atg7mQrZ2c6UDMqwHH1wsmOb3IXWessBD1LKR/1H/T5o evdttwsPxKJ9ib2BExk6p3EaKfIIuSzFUm3RuySNvZvPJq2HGBRNI1ZbHDs6H3o4 WZVHphZxQjmLBg8G3nWU6aalrfvJID11NtL+YfLdZtFBif4hDTbVgkTOw/i5E+n2 E0Uu7gbLhmPDuJDAl1CWJCiIWsLKiZ8dlZtoRFXm+USMi0IMTYXbb+r9SIBUiF0W IyfCMOPuqBJhh2PjKYgR8xmqloY6T0J7qd/q3AjsoGlgm3n5rdMyYFu2EeZxXT8R tWYyxYMvc9DGmpETgAcTHhBdlAqmd/0cTDlers42kT/Sj9aW6J371ItGB6i3VwPT jdb2lPCwAoDo/sJzswj0cMVSHv/hUCq0MA146CQF8WWugXlsYEmEgbaYsOyYKv3N xtH8eBQlf3FW19SrMEKTYO86OTySKR0aSOWmpj5xneVhHY+mwZKdTqUh5BjwyDkE 34Yn6juH6lA1RMUHwBRS79XxJHp6C6gDBGf+j9RpZSRxKfMXmC+SfWDraqiz0jsf phGY0IkCHAQQAQoABgUCVBShbAAKCRCMv5oyKGGnkIp+D/0Q3fWKva9hGvgB+6Op VwnIR967q05o/3phrR3PuISYBFPWumjD57q4YXenecz0W8shmxbwZIGOOiBpexZ0 mqzDZDewAk7PKPwF3s4Nva0C4t2irWIQAs/z52jMRVC4/7ON1WK76lvxj5LYhbx2 YBC7VJaMv1DaBmOEQm1IdLYcjm++rFmnba+dbm3nQ33ocFnmeEAVBEHE2mVgCvxr Zqk9EMrQFkkAaDUjhHEzxpH7uSUvvzD1V61BR8gtf7jQiVAmp3+8rJ4Je84xl2e9 LZ4ywO9KOI0WVwpzMLQRJhTLusPn/zhUosDqNrzTRf3vePzeTS62vqCigGnmnm2n BEpRMvjCS84rUbWG902Dcn6KZiZFeJWs4YQ9LPpcz2Z6IeZeqZ9gPJ+0s3XiQwM4 oM1+5SaNTV4GMvSCxwsFF8xgo6x51NsAgfGjF1z3ea5EbqugrDdgbdMQaEIWpBIU tRTZ5qhIj/GvK7omhZqIRA6hEwMiI7w3jesXzNnDQeFNT6WUJaWVFimhOeYl6eOo uuZoQN+w5zbJ2I52uHUavZhM5f0teVMxoY7sBA2L8H66u5xUCzMOKN1zE5qTSiqP iYATw2PZ9Us8rPF2aUtXjsMfyyi8rUOW50CWgkvmLZpKCqK3RAHO6ZYYQsqVDrLD 61ajnlj6aYbEV1p2UVKgIPFWO4kCHAQQAQoABgUCVE/8nAAKCRAY82hcACK/8/DS D/9HDrF8lBM4BrGoBjEKbNkmWsEoq1W9h8uMrY1VSnn7GRjLUeCFFaGByL1sQ82z wgF/K6BxHBeBdWb5nEoU6VYjypJPMDP8A67L0491uEPEN/XzSb955IZ8EPX79N36 KVk90da6HbOJnZsJqpGHMhhFpOCPhaTAsd7eYVUeiimPjBsvAd//kcgBmg1g2wDp kt64f3oxjBektDHn4Puie761aqzLOtdQbwBDy5S+6+Iw2ofkWZo+9jlY/zveUT1k OZiV9zEKRUZQ0lTRrbpQz10qxse7KRVg+V/2N895zNybIzmMnhCr5Xcwhov3RAhX yYAn3SM/woFvwWJiCU3zQSCT/SBXxefLTywxKtqYDISX7sm8o+L2ZSay0JTJvpXj b8cA/uSATWI7AmGOGeX9NlIsYeYVz5hj/TpLOgozIymiAu/068FQrruyDtSgUIwx jmRlgiFbYIjUfoRHbwIS2NQmFwdTWGzV4nJK7kLrOxM4QAaopcIvkb9uYaDVJ7H3 UO6Ee0pmcSw5ZoUSKzJMg13EAbmqO4tiwu+VuaNck4axzdF848lSiIUtfunArV2t l8X2cswW7XVzzMmAroEfC1/KuM57nYKk7keaas9mwUZ3JjjSkPMRj7WpxmMtxWX5 5CuB/lpX5v/7yLPKodKmQqfwn+A4YwNwl1k8pH7q/gAlu4kCHAQQAQoABgUCVhvN owAKCRCV5kNz8VKUacgnEAC9dK3pRnvZdNcnifB0ghRJE/ELjzi3Cbj2ddIyX+MS tstceWtXQRrIzf2gRvlZlbOIJMMXDZRvP3kjVVrg5E8IwuU+wuw/D9VoAB7cAfZo zcCQ2HvzvPFJP7ARu3N/oGNclWNjt7uRqWH7/a9O5N0MKVVNb7ebw3FaeCCnyPT4 dZ9r7iiPaQjrDh1TRx0DfsIFy76IilXjSIkUaEwmn+7o1cyYjbpr+DX+iyTn79zy XblLG7k8bEyo1/LKfSXah75ytOEDrxIPlXkI//+x5X5YhKtNks+c8Kpb1V5bE4j1 rEGuyuC9cW8Q7qfM5KdBj1OQWXz7zQknumzJiiKGlSRTfUDjouHdVeW+LbKn0kZJ 8LHgljVwlynO+i4ruWBcTgeVfHXLESpuvkSvEfs5NW4nmBWbDNvJNmiIwqutUCIn UxtJI1Rb1UYCP9RqfMBCcfJ2xRwPFH05UkgigEYVtGYlU7iGw6rlnRMmQrsWBQtz u3qgP2w84mN8JSVF7Ax1+jhSCgnTUxY44jIj9KzTOxROiF80i6Xpgk9gKPzYqEO4 K/F5IPMGNEaFWameg4ZcPPn/fIg3eG6jMLZ+v2z9CpyhZh3YzszcJLdezcC24PhH 7FSGROvOQO987/mIttlNBRUZKETrHAOEfk+ooCTHShCEvV6Hs3m67brZl8RhV6nr sIkCHAQSAQgABgUCVA2BMgAKCRALxH3GTRNTBvN4D/4o2Ho9ltuC3QNYH5hyRW3h IyDVsp0bRDMShKYtImcugjLOLKxSdNCHNRc3JiJlOunEo3BNzJDGhsmBLY2evvQc sKWUePAaJF0aEGpTZi/lpsMyRDzePpKrwesjwboUbkTJmqRQUcM19MEVBrF+WNZc ekVBcW1KRSw7eBYGGepj5DeU3f2GBdV+AVDwC+/yZrTDvked5GqVq0HMFEzpZ1UZ E4tWdFiw8SSCIxNXcIWlatxzlh3GbobSaW8I/AtKaJ6x6d1udXtSjX5ayBiMgYKZ 2Jn3uIzHDNeOuq+l7IBRLv8HCP2//MtU9+EclzD+e2xRHrRu16DpN2zLCoNcAp/6 45g1j7jHM+vHfSzvPntTVwiA1D3BKNEHbWB3ZWJeqbLx99gh7rILFMHRPvNUktpc jcV8bFz3S4NQ+TSSb5CIsm6K1/kmi8qmc+1ZPDhlwBttkdCxvXNTCpX79sAgDvPO t2Gv0wwDzvdTnJwMfIT81RLBU55hNS2yo8J8UOYxcywrJ+cZWA64lWCraJYtlzMJ oPEZ+mViQJuGO3DML8AlU1X8y/a2TtS4/1+uUlkE+RPrI2zCAD+OCkQ7v/thEx07 Q+G3/34G1l6YsWokYixBG6hqS5lKGP2Lq++tFdes5GmhKAjQrZLcCvrbrunp9su5 4y/CEJ5DSFNdGZq8kXFxMIkCHAQSAQoABgUCVAkUrgAKCRDKvh6eLro2T/fCD/98 FKHOsFK4qO9u1iht7iBCzSRDnr3m/JZiaTCKosUFrqh2T0Q3xAEe0tOJCSQKM2ql OD5tTnhUFpV/ht7M4UuAr0aQMjwpKX+vQtuo4lnuPwb5c7C8LXzR9MetGi7cjXLy qr1XSSzn5TnDw27sn6rzWe26fgg9TgdoenAj4DSzECfmun7GedpZQlEIehAxtwj1 SEVa4pT6CJRXNjhAuGKmJFccL45On5QCOoo+LSkpvDj1gf+dP5vJysyXajkpaogs NGSzAO6IfV8vpeEqUXxyfPFcd0MEVDtNVnHS5ctTi973OiFxLWuTP5Bw5F7rdPwT lGZxvDodSkid65/VPt1U7rdoIeygexrHuu02+bEQyqGReQz48yqMCSp5gGuVjvhR Vj30JqdX8qpfaYW0nraDKM0ogF5XnIdCRE07sgZscT63XQAatnKZvj8iiHOjGXoA WWDXBZ6JL5kSfGfLhwDgM1HeC5YKukK+WCTz8ApjOa0+chERSwl8mZOddZfhZO5a gzZYQGGzR18IxrkuJ6quCV647VZ18VgyEXHbL9GNXdZpEAFVLMS/0jUDl6fWeC2O /C3LnydpoCC/Vo9a/bVZOlHvLRQZBf8U+r1LDiXGRxFIWrHMbIIjKWv6y3GLuVhX a1ja6myS63UUOufSGzh8oUqOtnU4FJmnWhYVJ+Bo+4kCIgQQAQoADAUCVA4VNQWD A8JnAAAKCRDM0u2U0hc56ULOD/oCwn2GbITtzRPkse6Ltb2xG7Fr06zUgrcluf8T O9Ztn6viqRpRP3nGkjPMd3F48BBHpTxlIrNPUelyC2UW+LbPWk3XwlibVeCWaqVj 1WCWy8425zSswyiHWb4T5anst0e2gcwGtZmkXDP4fBTgQDkzLo/SVAmBkONW5wVw 5l1yGxfktyLx0YT1lYNHvD5CW/pRSteSIQDHdvYfTCyxPXqSsr1pKswzeLIA/UIy LiMk2V0u9kuADPYJRK4FWPxMq6vYh7+Bt67plLBm3ioTF1HrYlwEPJkJgjoVs21K H2EIBixs0Qp/kqDZ8ohs9Qnzrj2gHs4bdupF4kN4KiF4QK12W4M2ibQvZwiKYeBv Kg29s6U4pJJp6pF9Kgp1ZCW+6B9uMWjbW3GxekPtoIlYNPN84QmCi/YQelMcK3Pv CtiY7EDUtU1WyiTFH3ezbVemBElkMLuXRm66s2XXLAu5ZrGyope34j3yjeUBFIqA 2g/wKvB8QwoKKNeeSMtvjSGcsNQe84Os8xurF8rAZKUVhbEssvvGkBU0twqcvWd0 2eH39St3WgBxPGRj2kKk0xZ201hW2Kl9l1Nxb1g/boJTVBKL7dJRaoUcdj92R/Ab bVYwVGJAXIru++6oRWimYPpfBx5/MDm1gAj47K8MYu9fcynThjmmeWeRxYe3XJIy GpRTPIkCNwQTAQoAIQUCUyVBQAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAK CRADapwlvzV91Od9D/4zOpIpXz0saY7i/A2h6TTKj8k0iNrn8CRuzNe4Do8u4vIS psGf7xC5OlEzpU1ZFFmPnTNmEM7FOlfsZlwm6cpya2DLMmCRvYSkoWxeWHnG781e vLPsx87dwCyLMg+HZBiZTLLOSZMEsuRHo/utaS+J5o5tclvnvglaY71jogPqUHl3 1iH1VN2ILQr0kuM/EQZKqC+g5htaDpxJnZxRRqygfywNe96CtI88p7oexOFb/1zw wZwNFpTCQYiwCc73HZyAQBJYZ5lkfna1hli70doCAOjxMK0+a1iZYdkkGB4UM7Lz 9IzowOykClagRokvimbnFV4WMhQyPnkNxh5SNOgjm0V1VmprtsqRJhfaAo7b/Eyz edFm2pqx+SrA7hv6PALMFeQ2xvZkwHQFanM+SS2LmxuM3Oer76Y+KmdBJ+4yaAA9 3iNIXsyCwOVWlNkny297t6M4mNfINUS2McXA4ONiwgU+eKnKEsQOAjBFu1Y23HhX j7OZoY/AA0HKUp+OV3RpeESw1xtFTtb5kJ0r7g8LPsKdHNE3Tk24VJow+MPApXHz JEQ1NdbG/n7QD/iIbpQu5tJaBIhn+yH1Sz5EO3wZFB59HniR1tg+6m5HQzKvAepA hG+RzCLGvQbdrsAaVF4DiosBFPpGwXt+krULteBiJkDQpyrB3BJGRB0tMpDOzokC SwQTAQoANQIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCUypIQhMYaHR0cDov L3BncC5taXQuZWR1AAoJEANqnCW/NX3UizcP/2PZJbHx4PZhKkp9jVKFrcRWTGLl uvxbPgBRJGBd8XYrAqPkfOOGheV1gyiFwatLFC3C7tR9lBkqFA+gxsuhtS65FEdN fY5aO7F3lBDWa2B1rUXecQnPEx7QZq5LVBfIcpcBkuPuATyzxGuZJWDOoY/ZWUgO +8baY45WlMajBKAm8Y9TMb9IcDPxSz76SBzhhZPkOvaFsoPK8NHdzDqT/Awh1CUA q29VxJYo22IuKMogSw3H8KTxAXHAVYC8+kUhchWCttoj6kv6/ziBbdWqEXVvl8hm lV+j3sQYUsHHI/PEOzB8cAsUjmIheBVAPsWHE7KZgXNcb7GAvgctmQ2qfjRR3uvK XXD9wemx0ZAhmF62miyOmaKlwWhPipGcpYKW/9NvVRib9XRmojApe1LLYwL0SInD xpgczvbEYlMqqQgvL3ekstkhm3fuMmt03wmv5Ch99kMAXMO4qwJRhx8gR5fdasHY AMWn9uUAwRX3RHnaf0CEA8g4PZmqNenBYVI5aF2uVHuERratlF/ccTgX0CLuTDSB evzdYnFRvVwtAlBI0WAlVt+OU/8YFLHC//0xOcWUJRueDqcSdewsozIPGbQrB1tq hZY8tG2ENpQ9BhiwCvVr/YPfDgzSQTn3lphqdX5odPPHCwwjXcyqW4bcqLETbiS0 L3RnapFZl5T4KpXAtDBBbmRyZXcgUGFnZSAoVGlhbm9uIEdyYXZpKSA8YWRtd2ln Z2luQGdtYWlsLmNvbT6IRgQQEQIABgUCU6+mFwAKCRA8DDO7RCtb6drLAJ9LiOs1 MMFLB5girQQIU5md9rRBEACfW7a8xnsKKdETo/B1X3MjFBM4OTyJARwEEAECAAYF AlMsBGIACgkQsz5GQstuP/MPzAf9H8iWnpo1HF/LeQJJme5p5ZZjKTOCj0IDAuXX 5mun/QhRo0NghU7s/xRNG4W3eTvV5x4au2YpiB1ycAXcRtWWM08pv+IfC+rxYY94 Cnd3u6bx8n1LlzEcAS91Yl36zQWwmIUmx6XiKua7qLCHJQoIs6Gb9MYatQAT6Zfa +NZCf3AgSZYT5db8jZTxfuIKOTdE3hHv1pzAFkeqYOQFLpUYRvxaS/JeXG+Z7Drb SCMi9yrUujHqHDeE7FCLUwWFFSfP7F4fMrUMjaiJljhbn77UtsKIAT48+u1vYnqG PaA6dwc1PwsV9VprZuXXpwdmPvF7GQCdZJMgSv2kkWjJaztVe4kBHAQQAQIABgUC VOjAlgAKCRDUHiwnYPTg9F36CACVog8GWs5l4+AHiV1WbTIBWUBMbdzzRxLQDixj Wr2gUxU17SJ8Gdyz61Y9i+0TNbnXlf+cdEJdh9DOvFeZd2giI6VdfHBq15aFetuY Y/MUWuGJZxjx2jV1+UhTjvIt/iU1QnV12B7y/c397LoKKOph6lfDNNZBg8+IaR3O BvG63ms/BxoPDfXL8Bo2AdPcva4c+lOAXPYmCdWgvH0kgYuiSJpfDssMic6RgP5Q iBYFF0gDJ3C2ZwdBoTaId/46ndSdBUn+qSvZtSn/xMuZyKmo0izjcUtb34vZVLBI cRG67YEqyTpeoC4mw8hrSa5c0dXdVwTIlcLyQt4IIUKViGNgiQEiBBABAgAMBQJV BdtCBQMAEnUAAAoJEJcQuJvKV618NuIIALF6MX/mEUeeuyQv4kKWUuqwz4L4Eprl OgyNsm7SqklDdpN3k3ZYA3HhqliEBodT3AghpyG1vPbWURlzmtfKajDteIro1Pa/ r5EVJTydHM4snSmOGYEvdiiGBS1ugOMF7VWTxIuakCt0KoVjs7Ol6rtB9UvDTayA Ilfeny7jlmJDxX+Xcm78oFoK1q3tXkP0pJOsO5WkSCTNlljrNUbzr6lecZQGzXiJ hYW/+LM8B1Siv3RZd9VqGwKnUgBBLUoVD38QnOxRGOCAfv+C48kxkOcKg7XtIWJf JF5KV4OBh3ySXelwmIAaU8dq7kEx597TH1BNye0qx38hGp3WnCKyTcCJAhwEEAEC AAYFAlP5HMYACgkQe1hbMIB8KofhPQ/+PqOL/TkAtuFjGfbsUuzUQZFIYtACp7yr 7QgZAH1/d8d5Ej9p7+jXbxwDr+YOUSzSGGqW02Tum8tmKwdyDrwVDSoiGuubsNK5 o9YaeID/plBKJhTrcX43xUoaE4xlygj/n7vJB4coa5YGwOJcJszO/Ob/yeQMtQFM kFmzKodLpuiqV4G5VoOd2yv/DXkEnxgS16LGM02PDNxjeoTeZzHv/0bvQwk890xF 0ZkwBCDXbXS2M9PQKLjq3JFuTZz2k97J2pLn6bMA/DsqnWD/yosYTJllzF7xstql M/JVhBZl8FttK8vBUTphP5zDWqUzS/1Xp8OPZOSukG3xf9O21Ub6m6qcSBpDlgJ2 ehAkQzS65gW5UfdYz22dyNYTekofl2g8PSLB5MUebPNiHlkg0cb9aNpHfD9JopkF IuPjd5LiXbCb/Tao5fnIM43aVFQExBlFxF/em0HAcr67HH2i2CPVNT9jImMyPAHl vaA7EnhK9tBxWlLOk41t7wzKbudDUIsFCD/8HY4S3ojCt7MyuiVEf8wFRRsx46l3 NijqpJnJbse7HKN0qZNLAzm4KDPS2GcAhnD5nGDUFbaRaEZGmf8PxK2Q6qURBgV8 vjPgbbVTadHxsvhc12ekutLWbsOL/uKGQu2/xZM2aRj9V3amSgW0FuvIJVFgPePV qHJn83YT+zaJAhwEEAECAAYFAlQDfzQACgkQEm61Y6dLBr+DfRAAmoKxMGpQclQr Gwmac4cxy1UKM5rDZxnzSIA6Zfo3IvOQF6/EzAbixzSXbvQl89c87zqlmDo6Bwqf hwMtu1+eVi41XV9xlFz5AQtOMi9PK5OWYxI1LnULPxyJgqUUOHu4tarYN+SlCpo8 wudNAo+NX+imVbJexXgr+JSLYfWadxDgbs/m3YdaSamCHHIXA1X96WporFa9Ob7D jMYzUqr96lgfbw+fWz/v57tB4zdjWpB7rtkUSFJW0syZIm+JNA/TpEI1UwTm3UOg 9xHRgxdLzrEswD4p6JyHYrWeRe+MgSSTxepjgizDQwTOfIo7ii6fYvBXxmc8qttN BC6Jwsy2IH5E6NDK5k6QfEH5GeH0ILywzdHaWBj+Xxta3SwYj5rLnew9F7fUkypQ oRDwKQCSRddfNqjHGMwRGxYjTMlRA4L3spl4yx7MrJO470hVf9L+YuxHPJZROVIt 6W7gBEHhDmuAAoRTkYFROz/5PdFuCc0+WmCfbOtUoROWjVPaxaNMzEVkKnEIZcR1 LMsN0kvVN4hpI5rllQyQxwdb6vdIetxfoEEGhxrfVh9Rjh4VF2c0V7jcwml/PNlM SqhGAuVkG9aF7OMuAYcPenaw67Y2RfVBIyKf9b/7BhYb7mS8/hZLToI1MmI/cLvA z/KMWUJDzmB4eYfy6j9jar79KGiJ+giJAhwEEAECAAYFAlQLXQAACgkQRBc/oT0F iIjxnxAA08+s69dnBMLlzMScUGu+iULLT5XvT6nQY6GrEcXdy+OASE5AVexxISZ+ ajqq3pN7jmJyjpOJ5you0Zpp4HLL9QdbuKmupFm7MRwYSMdFSxYRGEafH3ycyuoL lFpK2tEBE7UXnR3IiZTfp4BrwN32Jev6KmcAGq5LPeksGQWLiY3vUTo0pHTWXWtd wfUV9H3okOGeoV8zUcuzPN3bmdHJiKc6qwWTjdFwx/hH917Rafp4eWfR0mzlHzt9 f2MrQyqdm6NYEZzWRj0nK6nIJIKDJbfqHT4hs5UG8HFK2X+LRBSW7CZa+3VvWA/4 hWA3F7vCZ+UvC3lGdsCbBc47Lz6VCIzjKpfXUMf9Vu4dFHUsBCnWdUDgf2ap5o+1 ACLQY03rMTVp7Fo5wN8hHLSKlkP4iXJ9pyNUEtEwaITmwtdmq0kcqq1+MnWm18GD KysOixLS815grKA8zVVqtQrmrX3/OZBeL2XKKIiZpizZUgIsA1pC8v3y0Iaiq3gN W67Txahpb7gk7+iCF8qjduosbm8Rs1uaHtpKFT98ewNy6l2XIiXqT3LrF4Av5o+R AwdsaUJ4Nn5UjRsGHBaF7SzN+YjFRPejwIPiM6+WYCaYg+oYPyxKX7DL9tiZXbh7 tna+7/NmORannBGn5EZufN3pwx7NOJRHFqChFTChptoSdbYpaxuJAhwEEAECAAYF AlRP/jgACgkQWb+J+kc3iHO9sBAAqu+7ZMEYJbGrUXt3ZUUmpEayvh568k64H24F JpKXiMl9dI91oygZkCz70pqJTlmMqPlEFVB45YyGO4nWOaRpywUApaKqTFM7v1JY RF/odJ+VghqdKkGgcGIKvl1XGoXxyYEwtfVMH2TeIqnmFYVCEfjoKJzQdPfd4Baf cTObhn4URSfjsiZhgYMr0u1I5cmJjBoE+4mr7/+SS1D8P/Pdm67U2KHl4o4t1hoU 4KSpYou3JGepkI0xbLw0L1kRC1/9Q8vNufOHQ4lTU1T7jzBcjYD6cl1KMcARprOq lZjFShSlJ7O0mjIJveuc63ELdGp5z+HJvixc+NYeYGh3xex17ceSwjc6mpvN6hBZ k2c8v+Nl4iLEVkAz7B1cxFUZaYOWt3ZQIfk3JOtwenLRoXYbrzNov9/Vw9TALpmY sasjAGNVaA1LimJCwB9VsNgQx/9iECwPcGWxnNpQR3BjU390iT/T8OKx9EJeNS+z 8makQOKVdusJj7si3Uuoi2n+UInU+BXekFLyVlQ8YorR/AzJPDBIDJmMwf6o/ooc X02HzAqHFV7Uiak3INVXAjTkYIgLO2FVW/Hk2AboAEL4JJygzAxSFhMR/q0K3zXA 9X1UmOrmY7PUPsUA4+fnwcTrGeAjfOP5EUFIh5dkCum5gYwnPMN02d4NdsqXjo+e +ftc2LuJAhwEEAECAAYFAlYxYKsACgkQuEPm/Y03/enhQg//YcULIfTQMuvRP4I0 LcOrRtXk+BXBIEDEkFTW9MSNqWAjdManzTs7KHvbgQEtqSK7kC01y6HYacLkgRkm GmwQOZzduBviwBTOvl9kDf0d93Qfnz5rHMTLJ+IcmABKLehz8ZVVtw1g+bxm+Pdm oMGSpdKa/szmMhCtJr79GM4gXAFE+KmKwMKUzT9ofItQDltdHMIojCS4NFJXOK4z BDni799yMnO+uU0dBq5DtgqnCgnljDh3TKwSJPTKq4xnaBe8o5pilGthNWpD5QS1 ln/M5p9sE7fSiKi8mmuBUkInnzz8oCbwbzLXpgaUGcCnesCcBdINJG2n0nBqO+gh itmyphVeaVORAbE9fGv4jG3no2RH1G3749F/+NB+MjYyqY2Thxn4VtCC384ow7Dt KeeE5wZUHIDKYnjqDsvaKWYLOANzHHAbb5PK6b3bqsNQbgr2FLXNVvFybBib6/sv YVEbG7IMHPxnlCPStfQfZJd29f/rm3OLFAvCTQyqcvA657CdUqCdiWbxkk8EjsNk OYAkSoUo0t4q4cXWbKqqpYACqpphW759UvfeSHIq/+2tRJ0m8UiNB+JupbtNkvAd L2GLsTzSW7CKXRv9PtT0nNcfDxg0YgTxLVv6Z0MOZIfBBsM4r1nwyI3R3TXdao8K Kfjy3i0dEDSwg+/dHeEkCJkwqZCJAhwEEAEIAAYFAlQGqmgACgkQs0ZPiWqhWUgO Kw/+PuJeehofFIPgaNtTiCALloP84VjV/VKaBLb8WcUFQ9uaASkV0wFRpPLcenW4 X0BdenUc4oDEhsoFRJR8ZB1WphkQXffBoq0KgtXkT1KUFuTaw/1nmdnlsb6ubyly yMkV48hUDE87vTUnC33qLvzKYIuhEFjM3+V0C9Bu1oUgD1vXwEg58kzTVButBId7 O479sF8zaq3dTBn2G0ZEFaArktii7bDDyCgZyvS2SHu8DgW9z/E69A3wXsdV4EcI jm/TSPrLhtnZNzWXUyXFujeg0WsAO6pt9jsjt3huWV3lKH/ufWG7FRrX7fth5e68 LxuppVGQx55QXUBhjX9hn5DEU/Bn/vpCWxjHaC1vCQ3Kx8rmR/lZT2e0627riOW3 PAghvvRwxtY3shnV+AOycP1cJe1ULdh+tr8nRZnKfqNotuQX9A6xOaKiejKXML2+ 1nkQMp6zFbeVkibqc8oAIimZs9ecf27y1BAWszlDXeT/58pS37DIvjTbd7v78PIP NJISIGdVD5TnkDqM2MHsLsv/J0ZS5fWMPO6z0IASK5uEwCX1O5vtk4ZuXD7dZMtU wmv+Wzg8eb3f3dRV/74O8qZxCpN12otPxT63csOLz6Il71D5u0wjTNanBSuXn82G oRyEFOK4X5eOskbEVMAKOUU912j+zxAheNBW3Cdiu976CzaJAhwEEAEIAAYFAlQM klMACgkQupx4Bh3djJtkug//VYbjKUdQMQpJK7oRRRm5BQ3SOWRvxWGvdGPER0Pw oZoBcQjB+/wksBL8QChuDBkb3qnq4UTN9DwL5bqUmMD4+rvKszYTx0Eq++wsu4EV KnRZx9BQDWuEjGpkKLOH0vQWYP/40v4ZEG3LDHef5GFQ7DOD3wga65gvnq9Sr6// 2v5QyY24ezadWeaRdjVz0ymZA17mk4m8Pt4iJpCiG4zSQXKBkOoyMTWyVl0QWvDO 29uZQ8btypYHJDlcYEuxKLD2cjTExaUAh6yjKhT7yuU3wDOXL0edUw+bRWzpnQBM 03GyndO/Uopm00EstyTsE4gwJMffLVdZ0kovDGO1nlO9NwukgB7jqY9iAxrg4664 oMIhf9zkEV5zcjXmJVgikwwjH7hD8eihnP9AXggQK0c2HIcJnLLag9adKf/9Nf3B ZT384TKkhozznXvewagZiTw2r/x/5XJwrr0x8an4bvXwDM7DgzuysAqTqBl+VDh1 KnPGrfsLdwO3uuWPndoD6DvvHWNDxOWE51fl30+yv/6gi5JYF9uX9NJ3tw1sQE1X Os6wQbdHbZmwc8sX53m/tDIqTNM4yBA0WnQuBaAV/WoUv46LjCD8HTTn2RA8u1Ey kbhzuScNpCGaD9r8wR7stF5H1k0e/U/NJ04i7T0bfA97emNjTO7ODc98jpqVt39k EnaJAhwEEAEIAAYFAlQPoNsACgkQAYF6sKr2za5D7Q//eHqCkDdU9fE8LDYwjjgy vktjEYwuK4B54rHouM2IqiPgu5PlqA7HBi0jn6/qdJm3GU9JgZhb8/Z5A/tyhO4v nLzJ8Fhcwc8+oc9V45KFLAgkKNoxIUfiuuZEsHeIEPELi2ob6z4UENX8xEVIP5NN MwSul59sHc30UFG/xLkReYM8Tcadd3rpGy8fHLUTAhQ8XgJOdrtfdmlB3ToI3NzU dhRjOU4OZ8e8jFRmwg6yv6O14VyOV1HqqY5XexFhclr6nzzXzCc73Oe6YVSCQsKm 4EHP+Hy00irpmBFtT8mzucbqm1EMxwADwItZDwNI39AJ9smetN0qzH0kJ902X2NN Vh/trQSd7O1DN8wgKsbgsPvXMJ2UtwI9NpneAa7zXBGnT6wLWqJj4rs6rI3D8kei ZUHzP9/Em8FQKUKwVF8eRGmyC6GlOV/cpJ3Minxy1iTdYxOjCImSi4vaOdUgjf0Q StU2fv8M+PhHz6wZFk+Cq8sNZ7Pnd68D+nJS0BbFhZNEQNvtozJ0DT9KzdJ0PQyx uuMAjz8Y0MPNwmlBYMqNI9yLo42r/KHFT6rLHDPiRou1waiEEmrTj0o7UE9YMFFh zQ+zMnOCT5FYon6rGsWmdIaLw2pQG3RWLgENasU5tWcZXabY+OntEfMsK8IynnjZ 3/13l/YkZNixGqdvlQjeM/6JAhwEEAEIAAYFAlQSlo8ACgkQ9RsYxyAkgiSVIg/9 Euw3pZWta0zF+GSSF/kDMv8EcMxUAGU7lu1XuWRAZjIRi/kk9gaE07Z4EKq1ZNFy AfJo7oBknEpMm6JZu/4Cdm6uU0d9bC3t1/rSp9iL2zerdjSi2YaLSGk6DZzsMGBg xTAJSz+fKW4C7KnO/V5NyALlzU+YPoOR73uEtmHiRwjMahIW18KTomJMoRqFROC7 anHftlipXhIXXHpw6gpYhZzznLJDSR58LdVdjqcjBX1tawWh/TP+tbLPifvByMZC 7Wg/ym7VhTMwrQOZhnh1Y4ziM3Lk/Y7pGAj6jV0VUzdCUCv/iPAz68PZriBat0bq sOKxKNwVKpy+hhB+V2aRrkyHzJlyDnmSwhuSoPApIedWWCf0ItePd0Lq4RW4HueF 2EJMgnaFa6PRVIAQCtNwG3wSlHRgrgZti/j4dthPa2O4eJBHZ1VcGBL7mzclnaEs ifXztGEgilf3l3iKS3Ek8W9ccQ/zvcOZaKGei4jdZaL1a4Fo6vFBlYGgt6kErtgK irpD1jySeXviqJphLdCmKcgVCy/SV1RaGCxZO1mnrnX+C4mkSEvmTF2c44EB5aIH x/GvYZGFB9Tb9fKOfqDVHdki46x7nWdYQpvK+wOjG9z1Xe0J3MD6zoEYHKjQL48G B2U1SCzBvmo8skemGh0m/6RBjjMCBvh4/q8EVHlXLj6JAhwEEAEIAAYFAlQcL50A CgkQ2SnymSvvCjMG4A//RpPYQllERMkKtiFdS/hWFF6N/7jPuDLJtHL76MNsDDR9 oVZjy4EDwaD4sVQ+N3W1gsnKSkaU8i+SFUa2mNrzTH9LlYcA/W6YLUL/NwO7ax0d Heii+TpktskBCl17WIAPUSxLh3daFok7YB3Km3WdZJvwqpioBssd2YIahhn+CWLp 5wnZ7EwWeIzsSRwurFMIKBS2k2uK7faxf8KYF0yLjsH7YoRDsHhKLaev7iPNS0Rb RpvtR+fql5qpgFONlGikYrVrDIYiTvhFHEwxrl+3IDOuCECBkgBWW7gUiviWHEmd NuEWMSjVfPntneBUbRdx9EgA/WUQzeVPlM8CsY16IycKjMHVeGENA0lhwHKdNCc7 GmBm5PmP6llbnvQjO7OHIclQcyqb3unNBqJCPsdNYj4WRiudrrKBjkrLyPIDT85x f3MO/CjOmG7i4NEsuLTsNIS5uBd68Exj9YGkaPugBWveShlcaWVM0wCzK8iJtcl4 R+cuEaAUYFhbrcIsTC+n+HOm6bn3Ud/0h7NQW65VqY/piOmfgfr0midc2eaIL7+q oHoAAy5gDAGdRbJeIeGeBqBa4VQ7BSgIb6G1GlulLI2b5+ODq7czQgQEmXdKdZIy fmPwCAQe3nQu6YwYcluaF34VNh29HOhuokR87D+DgzKmjpKt6dvxgBJQge6v/GCJ AhwEEAEIAAYFAlSQnTYACgkQuOUId2ZHWq+swRAAov42+NhSMqBjl9DFgwTrAWI6 8Xgf8o0xsouhREmvxg/MF+W61OwE0fVi0P6UwEhVqL4quIYakAIFTln0DzQBFVC0 GAoETe9Y0tfYFAceEi4J7Mgpq9Yj+TkHAehXL4JDzlAIuyW1C9QzLYUKp5rt4vqX s5bFCN/4ZemgO3T/2y7+OkCueO1r2d9fUvhfJ2o1NtPtZsxri5Qv3H/oaDRsGm1I dh12qFZBuXlkZUXrFlbYrmdXv5LRbSGw4KW8qvmfMZoT7qNQM9PVctoss9NusPYp zKuN5joxiDhZ8Skfc+y9H87YXaN5MpEa0iwVZeG8Hy2jAJathQu9xh3P4927fmV6 uL3NUy6Qs7C4MyLg4u83FxebB1DsOMJNcys3fC4ph7kuv6Qqzrpwz3+FJ2HzeVFT teRmontiJtYxxzO0qVUcqmKlWyBYI20cdONVuA9ifW76VjuvNt1FXGF9vhpQYDlH QH8cBoZIgg1qIXINDbjhlf3GfD5GFpFA2T8LKsQmOeL22KNohH8MVM8gdanWF/sr +d6O70wcFdqM98Cx9h1ChZlVg2T26gLOdLaD8FZmWolGwUUi04sn60HJiq22Gtco l77YpZliLxLL314Law11ETCz1PwrYmCL2TW0Bz0jcP3Q5Rfm4ozCInHzRxus+ObP CMKsG3xqeNxY3R2oxqGJAhwEEAEKAAYFAlMsq0MACgkQvimBJQiW5YGonRAAtD5s 5DxuMjzE30vfI3BukF45n9qtkruzpFtKm5KMzpESgOvs+11YFFGscAfVzqw9yaSu kg++NkgnXHH2kpo9+taUQnyx5zEN8+ldXySOR1gyQGWTmriljpv/whmlVR8FRlfB 8sbsDv7LQcALjut6xJHa6B5nD8BMNvLWbKndwk1RDNfkUjyOmDnbjKW5kyStGZox D9Pn1MtyYfO57URgX3uMnfSQtt2OpC31wjU5yzFuqxdkSuEBmLbTXvlORDU3ad6g bkBS+lzWS0+efielFDivk0iEDAlM1WQNOgw0X0388sqQ3LVqYZWyFvuS2VwSGxYz ryl7XbFOJVkRQLeY5PTOATMEyzXmpT7Jda/h3TnpKRiYFa6oeunF4BoB3mlXM3OM jGbJ9rb/uO/fOt2gpXW5dtTgdYOziT+92hV5xBQCc6uP8/7H3mDKcdmWCnEHCKJ5 gozJFS37dGDuYOerZ3V3Gh2MzabJBG4XCDFfuKv9x5S+6X0y5E/O2tblaAHco0Uv 3lVcMgTNM5g9Jphn8Kg81fNZqN2ePzczXB6OyuNLo+tHo8Qs7laMuxxbzpkQF5DE O06U81ZqYcE1K4rQInnaWbFDuYJwRuL3k63kjBXcEq7siG1QCiEqMPtoDZxDQIwI 2QaeA7SPkXU4StlTB08LVpmqmMgNuhSMYCHET6+JAhwEEAEKAAYFAlMstAMACgkQ r4BSh03TQHJLoQ//VwH9i8bjH0WcwpY82XWbFuMmr94gUFSG9INHn71xixBE74lX IZTOb4gOA2ta+7pS1SAxajeFSSaFmW/MN5NyU+y89uEPQ55YBeZoU1KHEuJ8VPba FLaLDG03jvQTgBDY4wmINBDbE5C8PQJGxv36JNoy1DkbkXsDK8qaYU9NwbbWvhpb itCeXjHM09iDRqeX8OiW0YXJsfQ9VgPDN7vuPMAsuCXZZtvGCQLFjc2eICFedwQk 4NpSpr/Eo8UyxgvwFSiQD2FJQrnRxNP25wdfRf8+mCLHoSUyrcRPuzo9PDl7nq1p hIz7kUh60Q/Fy0S7QUf9iMP62Mba6A9NQHNUO/310abI90SCcbTD9ZHPsWHL1sID jxCbYQsy4PYSIHQ2xdI9YcjO0EfgJeaD0F8SQrRM65JpMKGEYIDbMVIjAyi+Lkm9 qHlXNykQ68+rpxV0ZH/fclmp47FDJVFHUPJojrgFmRMbdip7owc99c4MwTpVK278 vC9YK/AuVilV5liWGjzWWfu5Z/W6o0IDhBTEo7usU4l/eXCTeNbDuDFwb+p6cl4U CQncN7hNXak49kTqFdaxEogTAgIUFcG/qDJXcBqOP9eQYRzoYvRL9InG8vqhMU+R A2rsjVKygrJBPB2+HCxjTX3H1MPr1zQS4ClSyBTLwpSb7ibDIQtgOvwDjZKJAhwE EAEKAAYFAlP8JScACgkQfFas/pR4l9i2/hAAg+coUYrkQVSeAg+Qkh/NJEJsLcMR YTnovGS08KPCw8FuJSLismPKqiNqLbfuMrs/Edoc/MTXrqVt7x00q4Md2a6ykady Ti6JnQo31xG3PJZ+U9TBv8rpvA0yRrpxDTCRGIEzkrczJyhYxhBsazMBUDvgnDea uqctO6ckvJeHyFTS2Ky+Tdi1RAsnGW6wIct9MXBm882gHGqMRuWXtfbQJp1rALLk jrGbXlj5D2pUqxDIVXponYmXqdihC6m/fNxoYsxH7NSF/vJ49L9k1RXgevV4eqSe tIa1HIOxLdhtxbSaGdWkf6SXvLypVHAyJPwrcQ9keEYesvRN12zf9klZ4sdaS4FE wMjV12wEGyGxQ4Y6iAQHNYBEjasMbaaQ6bZIUXloD1CVOu92yg3qw7m0CvsnkvJO hOHKQIn4KuznpWNO0QKc+UbSfucxUaO5Bne6J/C4shbG8sxLcqhhHEIZZCskmnBc Qh62Je9rTr4XaWu4ikMJVODlTctyO0kD3GnsTw+yZMhVW+c8H4f16Z5om/8I1F+3 RGfeFE4y7LCH0Rme6uI5+KbXbMrIespjeJ02pSxn8uzGDRUHNGHsSTkPTHuBc8bG 9NciRJDpv+XPnXJOzP/YqlTIog/O0GUv6jC88V7en5ke8aS7o6YjFd4iQhqyEmeH ImCFRYr8paWeAYWJAhwEEAEKAAYFAlP8JVoACgkQA0gCx6ykNQrpTA//VqTmb5b2 bU1+DYX1+UI9wK5s6Cpk7BHbewdpIBRwh7Vc55faD/tliiZHdqmY1tpiPUvOHABr JGZ1PfMiQ2UTpneV6LPKGTmemDVtnnb0DeccisDWyh5CZri9UmcXM8HgKztS6XrK LknAv4Md8KFLZVv8AG9haN2/eVHLL2gbbFItBK3g6fjldcQSLsBXZVk9HwUBDGN7 iunEGkTCfazwwshd9DhdSIIZP+NkBgzZ4Y9Gdpht3r76e+1iaDaywgtk7DCoMMXt i2ibFyNS0PdW9mJ7b2BpRCs82bN39FrOzgQR8R/yjQznvuHPcQaHpc5/SxnvYt6f AIubqpiG85LUK+xvbIqcn7o0ALxk9z15E8WbnQyhYtpvkQqWsYyy4YSmbXnMxcei A6arPZ4Y+CU/ti47KlOYX8Ha1tXP8UN3o0q/DnGoVRwwY6C6BfmyPZI48P1KGlTt ys3E0Jd6CSH+e+nP5qCe09I1TJuYYV9PvHjiOYPXBdGakwgcZfN9WTbZ1n5zbzJx jjJ78XfQ7h6nfLgWbv4pAM6clOae+j9ZQeZ6cAJpm/4C9CrHpjBCwkLnF+cOZTCd 3Qfh0flqZM3volIAMlHDFXJk/Aavr8g/GzyL4Q4JSRja2Z44qJhP4GxtppaOgkpY YOl4fbqeUwwggArwvV7kahqXEK2MOtvd7SGJAhwEEAEKAAYFAlQCKYUACgkQV1nz UAGqSmRKdw//RjeJlxLkPrkint4WEEDGMF0SqCbZjUPGPkPJi9SHfbLCA4SiWs6L t3Xw/ObB+kB4nUGPhvqpYAs42aSfsabEPZwJoyO5BRZHrFP24YVYm4LXx8zfhyZP EmHO8Bwxqm0hYXSawQtiNiBewr9JJz68KcUzNze3Yf8m9Vdup7qMpzAldEyL8Xyg t97LEQa0gK196/J/hPYSCzz/fLCDPuQIJ6T2fksLxExK+YkrcEI25txALUhY9u8H v66Fs6UIO4r7Ryfi3czGn4cxU4qIgK41pbv7cd5u5BlLfaMC5X5GhAswgNUP1mVE xq3Ltbwf5GGWVUQX0CtoxJQiV33QTP3h3XoOOSjDDL3S+4LBdw7bLMEOGyjE4UfK YJUK5Ll4kMXZ5Hkjf6/8ZawSIlV8SDBO9CkwhnFyVxKEMeMMCtRRWhHZlgD6zOX/ Z7cL9OEOf8aeeB15aYyB6dKS3HB2GYFZGS1zeT2Y4VEKWDDrlnadsN2lMsyKBXls 5N6XK5nt4OmLQrMHbMoxKcqtMwVRVCBHaMG+TfG3xt413bRNRq63fP/K8GZSLf13 5wALHWPQA0UOC3ez6Mee43E/2pbM8yhgOhnU9etfTyHsdEmJA/CqaZ16cxQUsCAI +azrEpHDQjWzvhR0voUDw4LJ0lHSurzJiJrwR5+HSNvkoMekFiST0IaJAhwEEAEK AAYFAlQGHEQACgkQFgmeFVlq6Si1vxAAivhE3jmvyRWGEJyF21Kic4LlgcFvm1SH vaQkGfcFE1iiDabgnmJAbrggKMsaCYfDDgnIJ4hP5MRH06iBoLyLra8saStXJI4s TNZeEtt5nGZH9o7Ok4M/7Lzm7O2xLkALTn4fbjeix5XNByPGsheVeVoMvPlf4Hn0 yNgSzbRW7NHTcILKNLwcCsXe7OZDWlZXsP3EO9xCsYXDAizESS3AyIPQ25rfL0XP 6/yPIOYdErm99ihg2IRXFr+REw6sHh8M2AaoHdh/UTfAztOQQgCds3b2/NnJ5xJD TZuXkJbGHggYLgVW0spNOllXmB87fTEnN92+8VXfWYVIM92qN27utKBal7Hi6Ggz wt2niEUVNv+Nws5Hua6WqvyGApoR3+RzwvlRB/tv8cumL4oE5dx5m9LSpDN18QCj XWFaucEdk4RJKqXkMi7EpiMcM6cOlQhUe+rGC1hksk2AgH69Byb08ZzxBDaxE7Ef 3bKw5NyRczLzwAVHHShq8EKVZI9ud9P3xtMGVU8VVEjXgeFtyAwUZD1qfavko6AR tn/mPJctDLB7hOb21ekng0cPMJbx21gEj2RDHXyNgaWiYjjLCOU9/eYZBISxj2qI ATXMqRUhZQPqCBdcjggjGZqdUkMg0ueJieSJG/4Qhjr0LByUTuHpUWya3eT6xl17 OylLrSkvHE6JAhwEEAEKAAYFAlQKcPoACgkQiCN6alOrGy56zQ/5AZUP+Uch0oLi YlfCi3dH6G2CbmbopNgyzWSKcUMpXHCji0h8tTKxNVAaHM02/WHpSI3CHJAHXNZS wxxl3vgPk+9c52Gurgk6p3YTxlDRCw5OhNSmnjrjXEbx0Y9jwckYVP5qCxWdckhx TRag6cDinOC5inQPhNtSMcUxCTWVi8f25xe11UR89VAfVTlAdfmQgyZrrwM8+yde xdhX8W81blI4MjMlnjApB87GNZswO9LJ4PTmtJBWKv2ZhSAEpju74evORMo2/E/n a+MiM/gKU3/ozaLuGVdJ7xbc2dce+zCSNf9hSRddPPlwDZMtLnUoodTK5OzQZt3X vMQoKFnjDEUdE+oobTbTBpNFNc+RXN72IrZ3ygcPYT07tYmLWrZ/mxoHjGqjU4DS ydhhFmECl4GWGtGKH6er+YaoQYvI0IIjxmzcUavZinNdfUX9fpO9TQ56tEAtpWyt 7p6a9q2201j3Gwv58F6+1XlRsrZvmubBYob+WRx1jpExHdex4L2GszKjnHDpLMQV WtbOceWpeEq2wYwJEMZRFZYksILMM/90P2KEP0k23M67S5SeH6KuCeEftiGN9/aG tyyAzRu7DSx9aIq1oAseouIJZidW0CNkbkslK0Vom2RhZhkM0mO8nWalZdmVCfVB 6YaaS/ZYbw234FfVlhx9HCrl1zni21uJAhwEEAEKAAYFAlQUoWwACgkQjL+aMihh p5Ch2w//YmF2ZV8Vrf3GVvoWJNs0HElPmq4kAzcRZTY+XwBJhNz2Whm4dTvc4cG9 /n9bxSLkhM1YZyigHZS4K2CT4kzujU35Npz4vEDOJ7FNloXi/hSXyHimLhzEKwUY oy1qhzUAFGyYHVNHwaw/Mz4ID2W6C7ZhT4PO9PZySaj4xJxlK7Sj9EZ3zas7g5Ak 4NNOeFRZ6qHivLXTOU/t/HNI+QfCM4ug4g61jAWwowwSpIfYo8mGXy19kdk6da+f tKaR3ky7EvCGWAZ/Ee11so0tK1fUT5pG3VP3Vc0ym++8Lb/qtp9ol31FvaMGEAdn eiZ5w3NZa6/MQ/hufI5Mj3wM6WoP1K46oXfCZtlZNJZo2wYPS/dmRkY3ht8C7lt3 uMH+Gp/Gz8+8+o1MEjhrkUhOODGHkM1qFqleDnD5ccx7kxY5Q2mVV1HAOCaMcWxb E/C4lBIG1GZqw8tuwIcjlNpzsjcCMiveQp0q+8bHgKxhvqpvpZE/brZZan4ySPwP iov5+YzJryR8Wm29v7AZ7QnXzRQzUNT79IMD7v06udi459XD5MgZY/BpBK0SZnrE /kGolX70sZBs2G5gkpx3JF4yj6z1MW//JCCbIJBPnyh+f7Z1hogMJD0TCms+PTP8 kKSfmfZ57AOKdXXQQcqYKMYSXugDLpRicmZEjZ/kd5jW7r8bUmSJAhwEEAEKAAYF AlRP/JwACgkQGPNoXAAiv/PVAhAAzZyMQ0XC4J0F4f6sBhmuKI4EOeqP930iQuJ7 gAvvKQRhA8shGc6FHeg/QIaYh9dUj/CVXQgABwkqyfgLp1GFdpa+Gr7l0knXgVXe vab20Vc2sMxBkm2L840nTCvXxc+idCLxRTooRai6US/P8npNlypUHoJBJgEvERm9 2VhvlC+dLiAjjgBCnKN5+e075hL0PaYCmE+38FSXCEw1QkJzLEJEVp884F6lbFa3 Pu0HUVRKL56Wj61Zs6rRWRZ56NyUCAH04Gvcc3RMJepshKHeV2lBNZWGyqLCXxgY UL6a5K7QlHhAOYaiw8wsFYQ+iXnapMEs77unwoIgaI3IUfRmn+YwoIL1hZ74pYi8 5Ki4YBZX4/ZDJ8oa01/oElqv6sb65kUvl9vF5iZ6G52kZ+htPnmJHqLq/dnISpLd pNKJePspTGNnxz9kCvx1QvkZqpps8gtXexywUCOMxTmNPikjJk6RU20CyWFoh8Gt 8XGrD5oyFbhZ13CYhSEkSw7OgfyWxmRtKw+ARSj8ccbBc+2o4y0+2vxoeGeHpyzE 9MaOAtKhBb6CI6MDy7uHyqQRrj0rGB13TFNHMxNw1tj07dJNzLTbjg6fUJotLhWA G3gfylVI4Pz9vRstm8Iwv/3r4cqxBc1JMkle6WhqpUGsjjnDU/DxN80SpWKIm1DH M29q/v6JAhwEEAEKAAYFAlYbzaMACgkQleZDc/FSlGkVLw//d/wua1kLAFv0/t9P IQQHrRHHBMJQ6aWJ6inveVu/Q7dg9r2Q9oEt3rBhzF0rOoYVudiWrNj/VXhtszLf jwsNoWvQWYXtiGbjfv5X7eZaJOstwwjvn7YYHeU8fox0ieucRN3npzEgtMDOp04Z QxIiWRz2Lf/GK4Hs0iG+0sg6f9S6b4wg1Ut341gJHxgbzSi3wWP3i/fxJ1yK0G5D b7lDVY9CqwUUixWfpI2vg2ME+qwP7ur+gIXwSoPpO1kNtQ4aUJW4AyOqp0vBSjVP CG3AQV9gADdFRyD9g8jW/EvWTjoP/y5P0VR0Qked9QzMiBB7kKi/KdoilG2//6xX ALp7rsRCP0qmJuE07rqX6Rd93hUeaeryt6OtyxdfbQOWlRQijkIXK/ueoyD890CN pjeW9juj4ceUKSagyEIUZ3zre7UcWH2INZWPxnsEMZQz14UKyuptgWPMg3GA1P7i qMNGhraxVcZNsTMgoIQuSZWCMQ9frsrzAp2KfujwvUFcRmwrEMIG2l+JEhJ4jMJk zp2t+jEKwUZ5MCp0Ua/a10JfnR0yTFnmpCLFCjylR/eufUpmURKy0D7PlvcDts67 DJu+uCCVeNed6lW8e3tS2r9n3N7/ssPrP7s7kv+RRtwVSs2geQpehZkdqtJYIV6R +j9QjmUopazD3sB+HZyeANFyx6yJAhwEEgECAAYFAlaLJ08ACgkQwEhMrvQNy5yP cQ/+MnKavk83JBxWzUhqNpCR5mBBMNXNDxQch8BLR//SM2d4jh6tei6Srusuz/9g 9R8LS1VXwFOfWq4vTtdoNQVY/68fHrd3p/2i/JalYpHW1RlPQFc/LWd8TP9vhX29 NIeyNIlPfKDGNkGsAYt4gcpqFbLKxIDbaj/DNxcTDv/SqGgJEwFnBDzxThIUvk6F ubjRCOJF5Gi7P0O2Ss+4ASBDdwgGZa+F32C6LWSqavNhr1JNbcaq7NiUeanRP5c7 n8yPpszzoeUMk5Nvfil7wvRUk99F4a7Px20+fvVDSknLuH8S35216D2dVb3caEQ0 KHAhL8C3rHAiAPmx8jhNsaRpuPqVuq2ZmjYwMAY0iUyvZVszoNlE0c0lM9er3txg QwwZorkaZ9jbCFGBxJuX9U3n9NOmAiLWIPuQFXJjZ6pdfAbdH2Mlk6OO1UYLxdXe l8tJGOOHmrCVgi60U3/5Fqrv7eOX2R+kUhnT0PlOTa9Hqmkmjehoux/A5kceCYe/ danvCY9oDWU7H4stuvolRZ4JQaDPHmQYou4gh8qjVmvjKOITiSaC309BDHN8WtWD z5oyCm/a1x8mT3KGB0+45k0IVIFItwCRU7F6cjzYnkwM9qPRkeq8CZ83yaC22e6Z R1TFWmPjYKzn9PZlYssOUVDTIUy0wkV3EdU5Nowfjjet+HuJAhwEEgEIAAYFAlQN gTIACgkQC8R9xk0TUwbEyxAAhpXAMdOYXKvFb9+Bcfo9O4iml3JwDvaAbw1UQEUS flqreg381Gng/D52A/OiAy+N+0hlAr24j+vsmk/rO5yPtFdKBCJEcoEDTsfTrbZ3 +agCAjtwom6Bx4JktWajd6R93ER3977/+sz21UGDaycrzxyN84zpIMlZdl8zaOsi pZcE0fdFCUoAA2km1IozI91ZzE2wkl1tpQprRyIFvYd+2Yo5vC0LiqGwJlQm15DF DVodMaiHHTGqr4y7kWJtoASDo6twEMc9mHDizmJOnB9UnpJ/A2NGigtNTJgyLCqk 2cYqQhXTdoTrqRd+nL+g+0fZr/XpZPvVi0bMOnm01x6OPdAxZLvFbdEhfD9FQx31 bunWLrEbQI6coRzLD0KG4Tbob9cdm7mmpYcOlsRgafm6UtL2cz/k9+XczqUKH/G0 D49LAhQFrrYAeGmG8YmCMU/GJqV24+nM3asoLoOLI7O+0KSgfhr3Dx68K327nT6N ezVBxjifMzFuNBLH8S6yJWPJofZgnKAIl3FSc0J5B4rN5hrHPuYHIEhkC4CvHfzE htbHjiaHSAzed4n69yBWNEAI1XE3OVePoy9LAA8vdih68kGLFM6o2k5+W1naOE+/ 1N8GpstBrjuFDxZv8aQJjN9xg2dCeSwthSK/6AeIfUBdfuGQwQ6Bz47id1vdv3GV Vh+JAhwEEgEKAAYFAlQJFK4ACgkQyr4eni66Nk916RAAgQlEbiTazq0napXMY8rf 10pAuYIEN6wubkGiuualQVVX/uwm/CY6O+I6AP6uCuZ59+hd+qX/Wt/Frqv25qTE Xt8K+9TEnoxxTs5g3XpbM70pYBEM8ftoWMfbW0iugtUF8QqSOtAj1b2MIj3EYKeU KmmHnV7kdjPCMkhlY8bMjidq3XWiq1BirGfwGGFoFxLZNQ2YQIOCGuoj6DqtXfB1 f3qQXCuCPPGAM3WOayTicQTFHdUTRmvfUh+pXhQM/FJ8lFSHHuUDEBJCEKkv2MAV 7EtQ2L8OGpcQo+PT2F7px761Bzd1FxhbQ/ajbvGyFa0nsC2fNwCfuVyLulMVIP9S 2QbgnPHdpg3YIapfy4bVMWY9KUmIG7M1+ef60NC30o8rlF27tz5rzXfaoUalGVu6 Ql6jLQc35UY8jBBcdjWVbY0uhTqA8nF3jZNp987GVZRM5pJYrnSDp7vhlqM9/xpZ mJk7nUwSCsefrDG4MrisO5FO1JZ5YTUMjgWyao1aPNQf5U57sCRl3LEgl1XqobgL 3JNFHaCZHGVVYA+/O7uajZVj0fqFDxdz6q8IfHwNk9KOEe2jQ3T8oFccy8q+2yPO J0TD430DCB3UMUoARRa+Lz50Sw3ss/ebtzt//shlp6qhOQVhQraq1GGh/rtYfUzV LmgT3Vws+pxZIvuUFgRrC0aJAiIEEAEKAAwFAlQOFTUFgwPCZwAACgkQzNLtlNIX OekPhw//aiXg7IRgTKGivLz121cdz9UWWcH9cyPoiFW2H8z2Zfm1G161eE2hvHFa RcrKp3gSHiZAaN9+KbkDj2nFqohZxopnZ5GN7QVW6evgJA6L9FEvWn21DKZFpvE7 DiEDLCZODxyDvBoO7LRg7gQVzznCg7NqVDw62pzqPBJyRwMzo73+fGbg7UIX5KRL 3eYq1SN+uTBv7rUOdT1EFMeMlficNCyf01FPJxZck9NkmtuNff8D2bUo8W3hJUN7 DIAQoZQB2zHkJRmpXrFvSe49W6eOBsAafSGrb0133j+0h2gnGzMST7cblVegJL79 R4CWdkMxiBkjLAY7xtkd0LeOTOmrF78qCZ1ssBZqbdx2qUTQDgJYxF4qkh9cJdlS ZN+8HtSDiwUdqIi5WDapfbqsy5vW3Pah6F+Zg1ROhyPQy1KfJX1PFxyXLL+tgvTm dLpglCjz9V5gjPpWhkT3N08PWOqwCNJpeiXd7aGdKRHJgKydpMH19WsX2pjRcZIA InQwZeXwdS35UOYbOL6cP15N5Et/s4K9qq5gCfg7USvmidlQCxaRm2/AwFnjFDmV Rw6TatNDGs3IntQ+1alFzqQhIredSJiOQFKjOUvuvjOTy8G1MTWQvF6tlfS8hkpf CbNafgakvVyZaghlOK1DogALH0ZHldZP0U5S17Jx4VWJi2V3t+qJAjoEEwEKACQC GwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAlMQ+okCGQEACgkQA2qcJb81fdTh Kg//aWSME8pylfR7q1s1keYaU1+lDZLv3SRvJ/7mBGMEO7emuWZ0kxEMON1WyHUc 6S34mfY/9TwE51Ntr7SnsPb1bV2ulNbnDNOLtoH8as32i89eKRnFlbRqzNNxbYNf ktaMAluEVe0e2GRhiIVTIpqp1j4q6oWopWW1SdNDn8CCP4h82WgxKt/S9VY1lrdB y9ZByXv6j1KuB74XjQsUiAjJcvekWsDbPnSjvD6KU6Ip+g4NL2EOnVuaT3U7vYp1 biToxx8GLfJOlS2WU3IYEKdrFvgUQWq0P3QcKY5ptHN0I4tIUwnFrlXZ9RSYi+aP Khj5OAHwC1tPbNQd00Z7KAYaVFmcRebZ3cedg2yQMlIRFmCmC8Bw4/2zwvHbmtnt YSDcwPxQ5jG01yfiOsMY6pdTUb5ULysN6Zc1DSzxcNrmySojtoUuF7R+rHRK3Zjb uasLgy+QxCE70RGASKm17DfsHku5FlLFEVdDgWPPAWNd1iEMkJ54sub78noqi9l4 vbdOzkaRJOVNVhoApWxHoHZ2JU+whBpyTSWhbgzfcwAnAA6w3ySZMFeRy5A160qN 2TEnc+isbtfql/gPeug5rDnk1K1EogJOoUdwslb9syl7xJOnsf73Pe2a+aKduAJv HdUThVcIR5+Cb4IBGTUnqd7APVc1So0DznOwDSdJvcKPsMOJAksEEwEKADUCGwMF CwkIBwMFFQoJCAsFFgIDAQACHgECF4ATGGh0dHA6Ly9wZ3AubWl0LmVkdQUCVdgw sAAKCRADapwlvzV91AZmD/0Ux57X2+HGPeH3oLgcmWFXD7DEvaq3FDj9m2tgChq1 5L/Jqfcn4X+zIzcTsHMb/jIBJeMleu+AVpCqgSq223j4tF7uM50rLPc39S2aejfa z6p1BJMbCV+7riQQdVQts9TGoNFR9Kw7Za8LnWJ9OH3Aez4v6wPNqJD0P8cgsPmw 79AuFkRaHW7HBHUYjYK6E4e9j5nlciUOmzfYNrbOM0qEl+bqwEW+s7+EJQWrVia/ FohtLa7rwbk49AK4yFnr3XmHdUJeoVZXq5KNs8TUCya9uFn1f/pohzndUs1ItBUd Zx/pB2F0dz75U5glVZHGOATeYNXasWbiiqB2QNYwhKU3sQ7mCGlilwGAKj2HAPg0 B8Ol0vb1EcQjzY7fVAuzzHpJgngQkQvgJpGUa0lFiSCbjIqkjOk8SlOOqHXqdpXk oHNPeQivsu2STwiI+HidNalNJnqf9b5CJ7ovgPLSEkbOKLdmXagaa2H7zC1yTqXd +DBi0xkJ8ogFkPjNg7EAe3R1FSY2InSLncqtG9VXj/z3B/7ev8FdIEyP6kOpmgZQ SX0OpELW1MPVmB2W8rYgnFX59IBJPIBziDGEzFvq63t3cNB8as2kJcQJXk3LucVJ FguKxhH2WGnJSvklO82i+XK9kHshT/SfONWaeTRksVjDlSkF7q9fTH6sO8wcfNOw T4kCTgQTAQoAOAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAIZAQUCUypIPRMY aHR0cDovL3BncC5taXQuZWR1AAoJEANqnCW/NX3UnWIP/A/SocCq+yKGsSH7wrTq z5bRQD2lqOfBFWiIpQz5suPbtkGhMuP52SeN3fv1aHPnfj+q9UsioefOce9itJ+N 2C+SNiGMvk2sWpkpKfTVWV93h3T32GotjCvdTEOAOScvjGD1n2dqhsZiG2bE7l/s m+kCFf7SEi94QII364+Tx9UiO/ytxtUZzvAuxPAjQITx5hBLm4MtiP1srUNo/iLJ N6g8HdAwQNiMFnexCZ3aJLEdI3msOcWSrKmLx0XH8oACHSMVByu17XyeXAbGkHtI vquNiEs420SYkZvZaQyC2iQQxsoFbKqvsRG5eWVQhK8lLCzIsCJ/N2VXkRRgCM7Q ccqiDc5nUAVAm9pwxcEE1Tekfwr7Q0Xp3jbm/JaELUoHvK0+z/6dtU7iApUnLeNm lZ38glxKc51Zy17aZcCXzytI/3bIVFPhwSxpXPZC5BXFu78yTTvBEagjOpV4fMCF CM2N16bx3SKkdaPdfYNgbAmkc7MMxhBVBQu2FfpPQMdi09QN+0I+iEtdaKiuzDdQ ESRie/CuXRek4MYj5aCDidtX1WmUcQ0tOOb/VteZqRBTjBpHFS34Vr56htSZqgdM Z2fGJ4cf/Ur7ILeTnMwSOYlnwo/hBDVTiyonCqkzE+jLfKJjZuhEvgofTF/xd8Fo qw3Xeay7Mrk1+As2DBpZ9/wNtDFUaWFub24gR3JhdmkgKEFuZHJldyBQYWdlKSA8 dGlhbm9uQGluZm9zaWZ0ci5jb20+iQIcBBABAgAGBQJWMWCrAAoJELhD5v2NN/3p zdsQAJy9nO8kjo6NtnckXFQNs2ELR6s3TAa0mShkoj6w4bq3LK5TZu5EkPajB4La Ndynpw977/et14U8v0D9MImYMMEM/DjrumywvhUX1cHaHG0895aaiT4XilEhhWQc sa+Pcq55yWGBBlisMDHQ5Ze2KPFVb97FbrJLYznOMKcfWboLJp2YAfGhJR5vklmf f3Cml4Ewiw+BzSiVgQvEKwU54+W6rWFdrOFNRBwQ3dOyCUmtRfdStzUvj4QpG3pH eP0cq4m0pgwpwAkXHZ4UIsxhANI8DwQq2+Tvxa4Wl5t570xrjesoX+jpq9gMo+JR xQ+f9DGMLb0ovl9R/mGGRmd4B5tlFVbSEbwArWJp3I1JqgDeqw3sU5rDufO+DoaF iKdUTxD0fcKeus4gQ4zC1OmAahzdCQYtbPZYMDAVgcJEX9wnpv4Lw8eSc96VVKhs ParjUTytZSlIjA4luCq9Vmg7CdTK0lva98RUC0oo22RZoyM85ydaRhH7LgAXB92M uqmNsVLOL1E1Uraea+ZHezNzE9jk3ZnE60UAl1O1DbgOStX8jnQE8fCbSK8csy4V ZX6proFb++Z3Am8+CWXoZC3MRYaIViZmhMYvk9zYD+V6UBaDSlNeBUP6Crfe8rQn bpo77RMu5PPVU0wnVE44LEmDjgzYJQv1IZxG8N/uEx9qClN1iQIcBBABCgAGBQJW G82jAAoJEJXmQ3PxUpRpJWYP/jmDbjSNnddxbTYrxo2hr/gTFAILVLOpUKkuGkE+ aok33fe0HnxDQiBYs+NwAfpfiw5NiOIZk13XH+TV4rh/J0OnYRKwWySH5ykAeFSz mBA7xdqI/LYlVJteJ7jW82KtPqW4KmPP4luBDphGl6SQBmvES53+4HKfU7ZAWQQz 6pcmfpFFe4qeKrARn+oNGVBQWYclMyq/ho5VolNlj9kXVaMJsrsm73RJTxdel7qv bF93yE3bnlR6IdiZTpYiTPDyu0jWtYIw5MHH22RBcQBQlam5+4giiDXjnReF6/Ch IOAQi/bzFwNc7jGtzIKR0BmEApXxset8rm/hvYrvL3N3pon5lQXlbCyVQCL5SRnL H6uDNv3W7BnlXGJdIBWX79fdUQKkchHhgaK5+Ps8MfSfgQKu//j4oOqfYF18qdD4 GBn1ICpXebtNdHvJPtHJgiHWBVUgnyEWj5ZawmMsL7RQPrqKTSLp8RJfb+a87c8T +hN6ndckHKF8PbIdZregpH6gPDiqrX2CZQgF0KD3WZhFTZlHXoGBEiy+l/7/BgRU Z/KnHKLXRXEZeuf9Aclf+4boyPnTkS6clhbpPlSas6U1bfcSdqPDjd+O25b4TOHZ oP3y0Eor/zPVhukUWGBnB4YgziJDVfWMlvUQnUw2L8hf7OF9qvEKE8IGDd0c4cd9 iwfziQIcBBABCgAGBQJW6z89AAoJEHxWrP6UeJfYqmwP/R834mqntfpNZeg9HH3i durBD1RJFPi9VfVZ4KeRwE4APq8j+nSs6xcJDHzpCnnjLn5HjcWy1hxC3z76gSRc umaJIpsL5QyH/qXxo/1UHVOmNVHxHPFFRePc1tP8vlP68/L4nCp3Sj12jkR7/8Oi dnPzHRHo/7RmaG35N1GGmB0CrjEfz8k4umGDoA947Yv6dkLVON9IfvMTG4ANR2k8 E9nbSKAXNMoiG0pjb8+cHW0zm/qusikBYoaewou8T494JfyijT7L1tO80jdWlWzU tLBfyAwcy1lxE35KO9XjG37qPJTXfG+Z7whQkcSZFQ7NXbvxm+T5k1Gjf+MUNF6T 2/lZ/eF15x9qC566NaU4afTUn6FEDEpuv4RAvopL4AH2vTNPRGxl4PxAfsZSHBEF ossAsW1Hlv09BiipBKDcD/wuGXT1qyEkxKGFsZ+lbgUm2Dga3wYofY9z/mw8Nb9x Izu4GQbgqPbK/J6Eodna59N6arkrWiyY2IOGgwaEec8cmJS6bDw6jNLiJLJKnmL9 ZlC2RwRY3dQGFlRRYLkIROcef2p2371GVD38VQNY1caub7HOA1BInluRu/1JQImD lEbuupzKlYzcPmu8mhMvCioTrqpafT+0Cd3lJD5rb56aKDqO9dOUabZ8F5RP/gjk 18Jr0DRdZ2vzlL3p3qll167wiQIcBBABCgAGBQJW6z9jAAoJEANIAsespDUK8hcP /0auFCHVNAa8oT0q5HGeMirmWou7LHYqMEKH5QGn+2yLE/CoXUSFIQw0z43Bxmkb HLFu2FJyRnzMDNMpxHbStGYHVANzWqZa5Uc01MdzzyKLxQoPKpkxmalQ+2pe6SsW qNdgwf8E9zX/cJpGUbp+/TIQ3vTR/+pt+ax5QcP5MjNv9HzFdWmC40Bt6NIb7pzN KpvOCrY2rY49B9c4N8orChD5uSG2btmCqs8AQ+oA+Cs12teE50pospGcRJl9sIbV 0Bjow5MzK0LnOAwltO+WMTjwJwQ2l4gffXVDqguKxuLh+sdG+iOYAlTjVzJvMe32 n0Tf7s0DBaMEuYzhT1DhrneYHyDlEYwvnsH8u4lw4gqPm5QaLlXJsvNbqYBVEZjn aDckoPTw59mWD8abHGF1vvYJrOGAvZLSZI/spCXT+y8bUvmNf+uKEa/CNtMrqpU6 TtmrFwetLIC8evxX50bvcJB8xSQrnRxwea1RQ6Sgobc932LhIt+ViRgBCoXWjrxE pXiWW3GHi6ok7zu/K4L3d8woo7ODJij/9JAT0pPqbnUMKDc6ceseyNlNKQrSn294 iKpn5sSOoOgfPqRMKUk7jDmkDGzxdp4sfY0EbwWtWlRle08bpHrFbmCh42mtlQWT 75YyW6biijnCOmnhMnH1XdkCHn7PmaKiXNazxI8boEDNiQIcBBIBAgAGBQJWiydb AAoJEMBITK70DcucIYEP/0RvHusMlzHeWe6rNt/JG7S0ekz26z5zfAellKgp75Wb IarriLq7ccAjEbsAMbm6xHT7muHHSro6Hc/8MB20b8cw3/qhtEmEJg9d+DptEXBm GfWfPqShvMPKaX5hgBv8m/8/zrqOGMsndy6eSlu492RgJ56KHzRKRyYhSq4aUzso ZnXYcgpq5VVvCryOKJtw29esBdrPjOIQlWgHNFQzyw5NVgR+bRVKw9UlZBDleZt+ 6zmlJIQ2kjBBnOXLl+GV3n5DyuXxAEMtp9W5YcyF3NJdc9g/bNMERbiJDocWen5V NnWHDDF5qgV3CywmrQN7+trC3d09NcGRsNZ4gIM/ylPOSOxNnwbOJJhEFA+t+NLX 9GKTKxlDc8nh2g7/XjG7s+yO3d2w18wcSdCqPjIg1m2I2ppPtwjuCWz+e3GvrfSu zkp5wbwEyqUqScjWJRN7uwrUXxvVX9i5nvnxezOhfiemz1xexwH9/2DkH6z5tHfV s3qVGSlDVcfTs4Hg7iW2Y4+kpJZH7ifOgf4ivy8zFMvHTFGeBtuCJe1mw6oNqOIx SNIswGJSXqMNKHXOSVlMHR9KLfW2615MLLCZCttDvrx1HzvnSpXB+M5W0QqWnHEU csn+t7TQHuldMsg+qK80FRqmqkK5oX22F4QIvT4PBa5vnG+bntdtpfNp8oVNv9bp iQI3BBMBCgAhBQJWAcyQAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEANq nCW/NX3U6TQP/2rJ+oNLyN0ei7pRVAJpsapz/wEzEB54MDaw4W9M86HuV0vlVyxZ GjS7hVhQlD8JnrbOevUsDdUbCxplVSSdCSSw4P0ruIStVIdhH6X6bATgebIXD7J/ tsno8hsFja5CGEyXfqELqGzIGHx+nzEbuoqNkMA/2pn+PE+195hHuDYJbGmeASJM kqEqRyGva2TXcR5xhZ5AmOyOHQM7k/KcbG7Mcti5XChj61l3+UDwRFatZP/ktqoz egUAH26jIVD0njel/AmfkNZmlfisv2HWPEbyy4sgzvYViBuw0gNNnefaESK63cjp BZSmdr9mR3f1Ewa+48CPAAOAbuSaPiYS5m59dMmJScDFBpKVMYtOxK5VrMXeTpPh i/+/9QBH+sOsGpSXA8uwIftKyfW/7QwswqEOMAO25dRgK2g+GFFSobBPk7JL2ZEW 8S3OGKrQDt4eY0ZNhnQEFRcNWq1rS+Pigpsj7pkPeSdnqXi8sNhHPWDspWGtJz09 mcOWPBfuaCagILHIGtZ2w2l9AXJaBXNFp9LyTv6d4fUKHAC/WoGkNJaF7r1KZu8W cHr/K2twghrVpF88WH0uHy0J1M6vuCiThWqQcAeVr1rkgXOrY8EiSGQfCxauUO6L QHlQ/CwKbhf32DemPMcYckRBbNTihkWtuEdHYkro4W4kcy3/O8bDtIUAuQINBFMQ +McBEADFLKiTJKpxPGg9U9rMZnxUuKwjzbJ0eXKe6YXg5dPHqIRE1CLeR5OUFcxV 2yieTUvFsmNcIGUK206haxAjxyyp132oD3khUbMfmyOb7v2+hjOSd1R4KbbU9KNP yoLsnchC3jnxFvZFeQ7TyVmR1kvAakeFpW0tbpRXuJPlrbDMOS+I3Py+WkLIc/vs tQh7u9NtrtRqOgTHR7757Luy+DUpeSyT+ZcV5CvU3maoMSXZ0bCJPFYaOYe9Djrq IiyF2XUxhd5P+UkHVetZPRLrx6Rs4Eah+u+4F5xwDYuEZ9AjvJWfU0tjgCnYCMF3 brSub/xMhWZHO/2+3OcrQExb93ebb987q3fPyZ4t8t1y+TMGjS0NfUk19SQo5IBE DSF3ow5MAjn21/v9gGI0/PimSCT3NXMw0Khf7Ja+W1wj8VKC4VyjnIs+XfeOQfia 2pzsHmw+Zs+H5PK/my4LxME2atOi7+mKMvdVhpWOb8FhaBmIjKm2dEV8r+qCfY9y AInjKQzjP/7DrJUsKbu8KWNf9EdchwtczVx+/MNnqsG/w+BjGdWFT0hafh6dV/cR WMVjmuQNVhQJEBQ5m0Z+5Cs9Bquzly47AJzVE9noHywjp+9nTMBq8TbSTvPR4lRx 2DPDV2DYaArCzUt7gDXKqD1frRl5SP7G6Y7bJJx3+O5WcBG1owARAQABiQIlBBgB CgAPAhsMBQJVv0B9BQkGcK62AAoJEANqnCW/NX3USTIP/iqucKRp4BXdUe5JNKu/ YCoJdXXdrnk/SMPxc7XKvcHvKlniXJTtWSQfPjSdXm9dW3jGTS3Ec/kS4Lg7ZTkm x4IOi7YspKGdi5+En3T0jzFx4OPt7aEdhyHzTj0lerbht7Vz2qQQ25vudCjKIqH7 DxoCm26cYCT1HfoZ512nSZnrPmmoYiCX29URP8CRJA7zpsD7TeSLmLBSU8MWjtJ+ 4PO4ZwLNdWf0hfuHsPKOVqBTWlQ9cxDGzMEmJRtVzJDua9VmXzMaSJNqRevR0lvm By5JoEvsxsQTPJiFTYkbMPpX2sgc0ObyX7aE5VW9J/zijgkGlbraN5DL00XmtI4y +h2CCNCwcHkSszfObVbafLopckmz2IaAbB+xmsnBZ8FLegnVRU9NM3pWvhdc5qgP p6K0/QvbYfDEngzv6Mtw5DnK354oYrvhrYiq2WfDTHnJWFE+mQ8w3X0+8eZnP+am Dq33lb1rSbCZQDKufCt9sGn6stjzdnOP7k+xD3qHdgJkffi/dFvNv81Th2SiCjn7 Td9CHQQM3CnFkqbSAGiylzBLQiJORq6ayyX9HQPSeWIhbPoosw2T8vyYNkLlfJ2k EuR2oSkAmqqn3OMI23jmayegU/qgOBNT1CfiztMfNS4LNf1n3T1E1Tm/E9GFXbHS rbsNPURogQESQCxFYMEUqbcA =/1El -----END PGP PUBLIC KEY BLOCK----- syslog-ng-syslog-ng-4.4.0/dbld/images/hooks/000077500000000000000000000000001450431004300206505ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dbld/images/hooks/build000077500000000000000000000006441450431004300217010ustar00rootroot00000000000000#!/bin/sh set +x set +e # we are running in dbld/images as current directory and we need dbld cd ../.. DBLD_DIR="./${BUILD_PATH}" ARG_IMAGE_PLATFORM=$(basename $DOCKERFILE_PATH .dockerfile) ${DBLD_DIR}/prepare-image-build $ARG_IMAGE_PLATFORM docker build --build-arg=COMMIT=$(git rev-parse --short HEAD) --build-arg=ARG_IMAGE_PLATFORM=${ARG_IMAGE_PLATFORM} -t $IMAGE_NAME -f ${DBLD_DIR}/$DOCKERFILE_PATH ${DBLD_DIR} syslog-ng-syslog-ng-4.4.0/dbld/images/kira.dockerfile000066400000000000000000000010101450431004300224740ustar00rootroot00000000000000ARG CONTAINER_REGISTRY FROM $CONTAINER_REGISTRY/dbld-ubuntu-focal LABEL maintainer="Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_bison_from_source RUN /dbld/builddeps install_pip2 RUN /dbld/builddeps install_pip_packages RUN /dbld/builddeps set_jvm_paths syslog-ng-syslog-ng-4.4.0/dbld/images/tarball.dockerfile000066400000000000000000000003301450431004300231730ustar00rootroot00000000000000ARG CONTAINER_REGISTRY FROM $CONTAINER_REGISTRY/dbld-debian-testing:latest ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} RUN /dbld/builddeps install_apt_packages syslog-ng-syslog-ng-4.4.0/dbld/images/ubuntu-focal.dockerfile000066400000000000000000000014221450431004300241610ustar00rootroot00000000000000FROM ubuntu:focal LABEL maintainer="Laszlo Budai , Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=ubuntu ENV OS_DISTRIBUTION_CODE_NAME=focal ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps RUN /dbld/builddeps install_criterion VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/ubuntu-jammy.dockerfile000066400000000000000000000013551450431004300242170ustar00rootroot00000000000000FROM ubuntu:jammy LABEL maintainer="Laszlo Varady , Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=ubuntu ENV OS_DISTRIBUTION_CODE_NAME=jammy ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/ubuntu-lunar.dockerfile000066400000000000000000000013551450431004300242230ustar00rootroot00000000000000FROM ubuntu:lunar LABEL maintainer="Laszlo Varady , Andras Mitzki , Laszlo Szemere , Balazs Scheidler " ENV OS_DISTRIBUTION=ubuntu ENV OS_DISTRIBUTION_CODE_NAME=lunar ARG ARG_IMAGE_PLATFORM ARG COMMIT ENV IMAGE_PLATFORM ${ARG_IMAGE_PLATFORM} LABEL COMMIT=${COMMIT} ENV DEBIAN_FRONTEND=noninteractive ENV DEBCONF_NONINTERACTIVE_SEEN=true ENV LANG C.UTF-8 COPY images/fake-sudo.sh /usr/bin/sudo COPY images/entrypoint.sh / COPY . /dbld/ RUN /dbld/builddeps install_dbld_dependencies RUN /dbld/builddeps install_apt_packages RUN /dbld/builddeps install_debian_build_deps VOLUME /source VOLUME /build ENTRYPOINT ["/entrypoint.sh"] syslog-ng-syslog-ng-4.4.0/dbld/images/ubuntu.prepare.sh000066400000000000000000000001231450431004300230340ustar00rootroot00000000000000#!/bin/sh cp packaging/debian/control ${EXTRA_FILES_DIR}/packaging-debian-control syslog-ng-syslog-ng-4.4.0/dbld/images/yum-builddep.sha1000066400000000000000000000001001450431004300226720ustar00rootroot0000000000000081e78a89cdb1bdee953fb23c0d0beeacbb5f9253 /usr/bin/yum-builddep syslog-ng-syslog-ng-4.4.0/dbld/install/000077500000000000000000000000001450431004300177265ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dbld/install/.gitignore000066400000000000000000000003541450431004300217200ustar00rootroot00000000000000# The directory is kept due to docker creating the directory # if not exists with root permission. If the directory exists, # docker will not change the permission. # Ignore everything in this directory * # Except this file !.gitignore syslog-ng-syslog-ng-4.4.0/dbld/make000077500000000000000000000001061450431004300171200ustar00rootroot00000000000000#!/bin/bash set -e cd /build make ${VERSION:+VERSION=$VERSION} "$@" syslog-ng-syslog-ng-4.4.0/dbld/package000077500000000000000000000003761450431004300176070ustar00rootroot00000000000000#!/bin/bash -e . /dbld/functions.sh package_type() { case "$1" in ubuntu-*|debian-*) echo deb ;; centos-*|rhel-*|fedora-*) echo rpm ;; esac } pkg=$(package_type "${IMAGE_PLATFORM}") /dbld/${pkg} syslog-ng-syslog-ng-4.4.0/dbld/packages.manifest000066400000000000000000000156441450431004300216000ustar00rootroot00000000000000################################################## # packages required to build the docker image ################################################## # packages to run gosu installation gnupg [centos, fedora] gosu [ubuntu, debian] # download various stuff over https wget [centos, fedora, debian, ubuntu] ca-certificates [centos, fedora, debian, ubuntu] # criterion compilation cmake [centos, fedora, debian, ubuntu] gcc-c++ [centos, fedora] # to unpack gradle binary package (zip file) unzip [centos, fedora, debian, ubuntu] # I dont know why this is needed. bzip2 [centos, fedora, debian, ubuntu] # Basic interactive tools less [centos, fedora, debian, ubuntu] vim [centos, fedora, debian, ubuntu] ############################################################################# # Essential build tools not explicitly referenced from # Build-Depends/BuildRequires ############################################################################# build-essential [debian, ubuntu] debhelper [debian, ubuntu] devscripts [debian, ubuntu] dh-autoreconf [debian, ubuntu] dh-exec [debian, ubuntu] dpkg-dev [debian, ubuntu] equivs [debian, ubuntu] libdistro-info-perl [debian, ubuntu] make [centos, fedora] rpm-build [centos, fedora] which [fedora] ############################################################################# # eBPF related tools ############################################################################# clang [tarball] libbpf-dev [tarball] bpftool [tarball] ############################################################################# # Tarball related tools ############################################################################# # docbook to generate man pages docbook-xsl [tarball] docbook-style-xsl [fedora] ############################################################################# # Build environment dependencies that are not strictly required by syslog-ng # but are needed by our dbld functionality. ############################################################################# git [centos, fedora, debian, ubuntu] ccache [centos, fedora, debian, ubuntu] ############################################################################# # packages to run successful autogen.sh # # NOTE: the versions installed may or may not be enough to regenerate # configure scripts, especially on older distros). We only guarantee that # autogen.sh successfully runs within TARBALL_IMAGE (debian-testing at this # point). All the other platforms are best-effort. # # NOTE/2: debian based platforms always regenerate configure script in their # debian/rules, so they will depend on these tools in their Build-Depends # lines, so we don't need to list them here. ############################################################################# autoconf [centos, fedora] autoconf-archive [centos, fedora] automake [centos, fedora] ############################################################################# # syslog-ng core dependencies ############################################################################# # Python on various platforms # Python is needed for two reasons: # - build itself (test scripts, merge-grammar.py, etc) # - python support (e.g. the version used for building modules/python/) # # We are now using the same version for both. python3-dev [debian-sid] python3-devel [fedora] python3-dev [ubuntu-focal] python3-pip [debian, ubuntu] python3-venv [debian, ubuntu, devshell] # python 3.10 has issues on Debian Testing # Nevertheless we should only downgrade for Light style-check tests, which uses pre-commit python3.11 [devshell] python3.11-dev [devshell] python3.11-venv [devshell] # libmongoc and libbson packages on various platforms # Because we are using fixed version of libmongoc on Bionic, we need to # specify non versioned packages on other platforms to continiously support libbson-dev [debian] libmongoc-dev [debian] ############################################################################# # syslog-ng module dependencies # # This section should preferably be empty. The only reason it is not empty # as some things cannot be resolved using the Build-Depends/Requires # mechanism. Exact reasoning to add anything to this section needs to be # added as comments. ############################################################################# ############################################################################# # Tools required to run @kira-syslogng, our testbot. ############################################################################# gdb [kira] faketime [kira] libdbd-mysql [kira] lsb-release [kira] lsof [kira] netbase [kira] netcat-openbsd [kira] openssh-client [kira] python-numpy [kira] python3-numpy [kira] python-yaml [kira] python3-yaml [kira] systemd-sysv [kira] python-is-python2 [kira] python2-dev [kira] python2-dbg [kira] ############################################################################# # Development tools in our devshell. ############################################################################# clang [devshell] dirmngr [devshell] gdb [devshell] gdbserver [devshell] joe [devshell] lcov [devshell] libc6-dbg [devshell] libglib2.0-0-dbgsym [devshell] libjemalloc-dev [devshell] libjemalloc2-dbgsym [devshell] libssl3-dbgsym [devshell] linux-perf [devshell] locales [devshell] lsof [devshell] netcat-openbsd [devshell] python3-dev [devshell] python3-dbg [devshell] python3-dbg [devshell] strace [devshell] valgrind [devshell] openssh-client [devshell] astyle [devshell] snmptrapd [devshell] dwarves [devshell] syslog-ng-syslog-ng-4.4.0/dbld/pip_packages.manifest000066400000000000000000000006241450431004300224400ustar00rootroot00000000000000# pip packages for kira tests distro [kira] [python2, python3] hy [kira] [python3] hyrule [kira] [python3] requests [kira] [python2, python3] syslog-ng-syslog-ng-4.4.0/dbld/pkg-tarball000077500000000000000000000006421450431004300204100ustar00rootroot00000000000000#!/bin/bash # MODE is passed via the environment . /dbld/functions.sh cd /source SYSLOGNG_DIR=syslog-ng-${VERSION} SYSLOGNG_TARBALL=${SYSLOGNG_DIR}.tar.gz cd /build rm -rf $SYSLOGNG_DIR tar xfz $SYSLOGNG_TARBALL cd $SYSLOGNG_DIR echo ${VERSION} > VERSION /dbld/generate-debian-directory $MODE /dbld/generate-rpm-specfile $MODE cd .. tar cfz $SYSLOGNG_TARBALL $SYSLOGNG_DIR capture_artifacts $SYSLOGNG_TARBALL syslog-ng-syslog-ng-4.4.0/dbld/prepare-image-build000077500000000000000000000006531450431004300220250ustar00rootroot00000000000000#!/bin/sh set -x set -e IMAGE_PLATFORM=$1 OS_GROUP=$(echo ${IMAGE_PLATFORM} | cut -d"-" -f1) DBLD_DIR=dbld EXTRA_FILES_DIR="${DBLD_DIR}/extra-files/${IMAGE_PLATFORM}" mkdir -p ${EXTRA_FILES_DIR} || true [ -f ${DBLD_DIR}/images/${OS_GROUP}.prepare.sh ] && . ${DBLD_DIR}/images/${OS_GROUP}.prepare.sh || true [ -f ${DBLD_DIR}/images/${IMAGE_PLATFORM}.prepare.sh ] && . ${DBLD_DIR}/images/${IMAGE_PLATFORM}.prepare.sh || true syslog-ng-syslog-ng-4.4.0/dbld/prepare-release000077500000000000000000000073771450431004300213000ustar00rootroot00000000000000#!/bin/bash set -e cd /source VERSION=$1 OLD_VERSION=`cat VERSION` OLD_MAJOR=$(echo $OLD_VERSION | cut -d. -f1) OLD_MINOR=$(echo $OLD_VERSION | cut -d. -f2) OLD_PATCH=$(echo $OLD_VERSION | cut -d. -f3) NEW_MAJOR=$(echo $VERSION | cut -d. -f1) NEW_MINOR=$(echo $VERSION | cut -d. -f2) NEW_PATCH=$(echo $VERSION | cut -d. -f3) USER_EMAIL=$(git config --get user.email || echo "noemail@set.any.where") USER_NAME=$(git config --get user.name || echo "unknown user") VERSION_FILE_LIST="README.md doc/man/*.xml scl/syslog-ng.conf docker/syslog-ng.conf contrib/openbsd-packaging/syslog-ng.conf packaging/debian/syslog-ng.conf packaging/rhel/syslog-ng.conf" function update_version() { echo Updating VERSION file echo $VERSION > VERSION } function update_packaging_debian() { echo Updating Debian packaging DEBFULLNAME=$USER_NAME DEBEMAIL=$USER_EMAIL debchange --distribution unstable --newversion "$VERSION-1" -c packaging/debian/changelog "New upstream release $VERSION" } function update_packaging_rhel() { echo Updating RHEL packaging sed -i -e "s/^Version: [0-9.]*$/Version: $VERSION/g" packaging/rhel/syslog-ng.spec sed -i -e "/^%changelog/ a * `date '+%a %b %e %Y'` $USER_NAME <$USER_EMAIL> - $VERSION-1\n- updated to $VERSION\n" packaging/rhel/syslog-ng.spec } function update_version_refs_in_source() { echo Updating version references in source files ESCAPED_OLD_MAJOR_AND_MINOR=$(echo $OLD_MAJOR.$OLD_MINOR | sed -e 's/[]\/$*.^[]/\\&/g') && ESCAPED_NEW_MAJOR_AND_MINOR=$(echo $NEW_MAJOR.$NEW_MINOR | sed -e 's/[\/&]/\\&/g') && git ls-files $VERSION_FILE_LIST | xargs sed -i "s/$ESCAPED_OLD_MAJOR_AND_MINOR/$ESCAPED_NEW_MAJOR_AND_MINOR/g" } function update_versioning_h() { echo Updating versioning.h VERSIONING_H="lib/versioning.h" if grep -E "^#define VERSION_${NEW_MAJOR}_${NEW_MINOR} +\"syslog-ng ${NEW_MAJOR}.${NEW_MINOR}\"$" ${VERSIONING_H}; then echo "VERSION_${NEW_MAJOR}_${NEW_MINOR} is already defined." else sed -E -i "/^#define VERSION_${OLD_MAJOR}_${OLD_MINOR} +\"syslog-ng ${OLD_MAJOR}.${OLD_MINOR}\"$/a#define VERSION_${NEW_MAJOR}_${NEW_MINOR} \"syslog-ng ${NEW_MAJOR}.${NEW_MINOR}\"" ${VERSIONING_H} fi OLD_HEX=$(grep "#define VERSION_VALUE_${OLD_MAJOR}_${OLD_MINOR}" ${VERSIONING_H} | grep -o "0x.*$") NEW_HEX=$(printf "0x%04X" $((${NEW_MAJOR} * 256 + ${NEW_MINOR})) | tr "[:upper:]" "[:lower:]") if grep -E "^#define VERSION_VALUE_${NEW_MAJOR}_${NEW_MINOR} +${NEW_HEX}$" ${VERSIONING_H}; then echo "VERSION_VALUE_${NEW_MAJOR}_${NEW_MINOR} is already defined." else sed -E -i "/^#define VERSION_VALUE_${OLD_MAJOR}_${OLD_MINOR} +${OLD_HEX}$/a#define VERSION_VALUE_${NEW_MAJOR}_${NEW_MINOR} ${NEW_HEX}" ${VERSIONING_H} fi sed -E -i "s/^#define VERSION_VALUE_CURRENT +VERSION_VALUE_${OLD_MAJOR}_${OLD_MINOR}$/#define VERSION_VALUE_CURRENT VERSION_VALUE_${NEW_MAJOR}_${NEW_MINOR}/g" ${VERSIONING_H} sed -E -i "s/^#define VERSION_STR_CURRENT +\"${OLD_MAJOR}.${OLD_MINOR}\"$/#define VERSION_STR_CURRENT \"${NEW_MAJOR}.${NEW_MINOR}\"/g" ${VERSIONING_H} sed -E -i "s/^#define VERSION_PRODUCT_CURRENT +VERSION_${OLD_MAJOR}_${OLD_MINOR}$/#define VERSION_PRODUCT_CURRENT VERSION_${NEW_MAJOR}_${NEW_MINOR}/g" ${VERSIONING_H} } function perform_updates() { update_version && \ update_packaging_debian && \ update_packaging_rhel && \ update_version_refs_in_source && \ update_versioning_h } if [ "$VERSION" = "" ]; then echo "Please supply version number as first argument" exit 1 fi if ! git diff-index --quiet HEAD; then echo "This script only operates on a clean git tree and git is required" exit 1 fi if perform_updates; then echo "The proposed version changes have been saved as local changes. Review and commit them or abort using 'git reset --hard'." else echo "Updating the files have failed, falling back to the original state." git reset --hard fi syslog-ng-syslog-ng-4.4.0/dbld/release/000077500000000000000000000000001450431004300177005ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dbld/release/.gitignore000066400000000000000000000003541450431004300216720ustar00rootroot00000000000000# The directory is kept due to docker creating the directory # if not exists with root permission. If the directory exists, # docker will not change the permission. # Ignore everything in this directory * # Except this file !.gitignore syslog-ng-syslog-ng-4.4.0/dbld/rpm000077500000000000000000000022211450431004300170010ustar00rootroot00000000000000#!/bin/bash . /dbld/functions.sh RPMBUILD=${HOME}/rpmbuild RPMBUILD_SOURCES=${RPMBUILD}/SOURCES function setup_dirs() { mkdir -p $RPMBUILD_SOURCES rm -rf /build/${IMAGE_PLATFORM} && mkdir -p /build/${IMAGE_PLATFORM} } function copy_rpm_packaging_src_files_to_build_folder() { # CzP's spec file expect these files in the pwd # where the build was initiated rm -rf syslog-ng-${VERSION} && tar xvf syslog-ng-${VERSION}.tar.gz find /build/syslog-ng-${VERSION}/packaging/rhel/ -type f | grep --invert-match '\.spec$' | xargs -i cp {} /build/ } function prepare_source() { copy_rpm_packaging_src_files_to_build_folder cp syslog-ng-${VERSION}.tar.gz $RPMBUILD_SOURCES } function capture_rpms() { mv $RPMBUILD/RPMS/*/*${VERSION}*.rpm /build/${IMAGE_PLATFORM} mv $RPMBUILD/SRPMS/*${VERSION}*.rpm /build/${IMAGE_PLATFORM} echo "Your rpms are in /build/${IMAGE_PLATFORM}, also available on the host in \$(top_srcdir)/dbld/build/${IMAGE_PLATFORM}" capture_artifacts /build/${IMAGE_PLATFORM}/*.rpm } cd /build setup_dirs prepare_source rpm_run_build_command rpmbuild --define '_dbld 1' -ta syslog-ng-${VERSION}.tar.gz capture_rpms syslog-ng-syslog-ng-4.4.0/dbld/rules000077500000000000000000000250011450431004300173360ustar00rootroot00000000000000#!/usr/bin/make -f BUILDER_IMAGES= \ centos-7 \ fedora-37 \ debian-stretch \ debian-buster \ debian-bullseye \ debian-bookworm \ debian-testing \ debian-sid \ ubuntu-focal \ ubuntu-jammy \ ubuntu-lunar \ kira \ tarball IMAGES=${BUILDER_IMAGES} devshell DEFAULT_IMAGE ?= ubuntu-jammy TARBALL_IMAGE ?= tarball DEFAULT_DEB_IMAGE=ubuntu-jammy DEFAULT_RPM_IMAGE=centos-7 DOCKER=docker CONTAINER_REGISTRY ?= ghcr.io/syslog-ng MODE ?= snapshot VERSION ?= $(shell MODE=${MODE} scripts/version.sh) DOCKER_RUN_ARGS=-e USER_NAME_ON_HOST=$(shell whoami) \ --network=host --privileged \ --ulimit nofile=1024:1024 \ -v $(ROOT_DIR):/source \ -v $(DBLD_DIR):/dbld \ -v $(DBLD_DIR)/build:/build \ -v $(DBLD_DIR)/install:/install \ -e CONFIGURE_OPTS="$${CONFIGURE_OPTS:-$(CONFIGURE_OPTS)}" \ -e CCACHE_DIR=/build/ccache \ -e MODE=$(MODE) \ -e VERSION=$(VERSION) \ -e PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ -e GRADLE_USER_HOME=/build/gradle-home \ -e GRADLE_PROJECT_CACHE_DIR=/build/gradle-cache \ -e GRADLE_FLAGS=--build-cache \ $(if $(wildcard ${HOME}/.gitconfig),-v ${HOME}/.gitconfig:/build/.gitconfig) DOCKER_BUILD_ARGS= ROOT_DIR=$(shell pwd) DBLD_DIR=$(ROOT_DIR)/dbld BUILD_DIR=$(DBLD_DIR)/build RELEASE_DIR=$(DBLD_DIR)/release TARBALL_BASENAME=syslog-ng-$(VERSION).tar.gz TARBALL=$(BUILD_DIR)/$(TARBALL_BASENAME) GIT=$(shell which git || echo false) GIT_RELEASE_TAG=syslog-ng-$(VERSION) CONFIGURE_OPTS=--enable-debug --enable-manpages --with-python=3 --prefix=/install $(CONFIGURE_ADD) DBLD_RULES=$(MAKE) --no-print-directory -f $(DBLD_DIR)/rules DOCKER_SHELL=$(DOCKER) run $(DOCKER_RUN_ARGS) --rm -ti ${CONTAINER_REGISTRY}/dbld-$* /dbld/shell -include dbld/rules.conf help: @echo "This script allows you to build release/snapshot artifacts, such " @echo "as rpm, deb packages and tarballs in controlled environments (e.g. " @echo "within docker containers)." @echo "" @echo "Please create the required docker image first using the 'image' target" @echo "then you can build syslog-ng binaries or do development using the " @echo "targets described below." @echo "" @echo "Supported OSs are: $(IMAGES)" @echo "" @echo "Packaging targets:" @echo " deb: generate debs in dbld/build for $(DEFAULT_DEB_IMAGE)" @echo " rpm: generate RPMs in dbld/build for $(DEFAULT_RPM_IMAGE)" @echo " deb-: generate debs in dbld/build for the specified OS" @echo " rpm-: generate rpms in dbld/build for the specified OS" @echo "" @echo "Docker images:" @echo " image: generate the default docker image" @echo " image-: generate docker image with a specific OS for building syslog-ng" @echo " images: generate all docker images" @echo "" @echo "Development:" @echo " bootstrap: bootstrap source from a git clone (e.g. autogen.sh and friends)" @echo " shell: start a shell in the specified OS" @echo " login: start a 2nd shell alongside an already running one" @echo " root-login: start a 2nd shell (as root) alongside an already running one" @echo " tarball: generate a tarball in a controlled environment (e.g. docker)" @echo " pkg-tarball: generate a tarball that includes deb/rpm packaging files" @echo " prepare-release VERSION=x.y.z: prepare the source tree for release, does not commit" @echo " release VERSION=x.y.z: generate a release tarball/deb package in a controlled environment (e.g. docker)" @echo "" @echo "Notable Make variables:" @echo " CONFIGURE_ADD -- add this to the configure command line in bootstrap" @echo " DEFAULT_IMAGE -- override the default image, currently $(DEFAULT_IMAGE)" @echo " TARBALL_IMAGE -- override the default image where the tarball is generated, currently $(TARBALL_IMAGE)" @echo "" bootstrap: bootstrap-$(DEFAULT_IMAGE) bootstrap-%: setup $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/bootstrap make-%: setup $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$(DEFAULT_IMAGE) /dbld/make $(MAKE_ARGS) $* tarball-from-root: setup @if [ -f $(ROOT_DIR)/../$(TARBALL_BASENAME) ] && [ ! -f $(TARBALL) ]; then \ cp $(ROOT_DIR)/../$(TARBALL_BASENAME) $(TARBALL); \ fi tarball: tarball-$(TARBALL_IMAGE) tarball-%: tarball-from-root @echo "Checking $(TARBALL) if it is up-to-date..."; \ if [ -f $(TARBALL) ]; then \ TARBALL_CHANGES=`find $(ROOT_DIR) -newer $(TARBALL) | sed -e 's,^$(ROOT_DIR),,' | grep -v -f $(DBLD_DIR)/tarball-changes.ignore | tee $(BUILD_DIR)/tarball-changed-files.txt | wc -l`; \ fi; \ if [ ! -f $(TARBALL) ] || [ "$${TARBALL_CHANGES}" -gt 0 ]; then \ if [ -f $(TARBALL) ]; then \ echo "Rebuilding, because these contents have changed since the tarball" && \ cat $(BUILD_DIR)/tarball-changed-files.txt; \ else \ echo "Rebuilding, because tarball $(TARBALL) not found"; \ fi; \ echo "Git status follows:" && \ ( $(GIT) status || echo "Git not found..." ) && \ $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/tarball; \ else \ echo "Tarball $(TARBALL) is up to date (except files excluded by $(DBLD_DIR)/tarball-changes.ignore)"; \ fi pkg-tarball: pkg-tarball-$(TARBALL_IMAGE) # # pkg-tarball-%: # # NOTE: first check if the tarball is already a pkg-tarball (containing # packaging files). This might happen if we try to reuse a cached tarball # and we can spare some time by avoiding the pulling of the tarball image as # well as not having to run the scripts that add the packaging files # pkg-tarball-%: tarball-% @if ! tar --strip-components=1 --show-transformed-names -tvf $(TARBALL) | grep ' debian/rules$$' > /dev/null; then \ $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/pkg-tarball; \ fi package: package-$(DEFAULT_IMAGE) package-%: pkg-tarball $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/package deb: deb-$(DEFAULT_DEB_IMAGE) deb-%: pkg-tarball $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/deb rpm: rpm-$(DEFAULT_RPM_IMAGE) rpm-%: pkg-tarball $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$* /dbld/rpm validate-tree-clean: @if ! $(GIT) diff-index --quiet HEAD; then \ echo "Your source tree has changed, this operation requires a clean git tree."; \ exit 1; \ fi validate-version-format: @if [ "$$(echo $(VERSION) | sed -e 's/^[0-9]\+\.[0-9]\+.[0-9]\+//')" != "" ]; then \ echo "The version number you specified $(VERSION) is not a valid version for a RELEASE. Please supply one using VERSION= via the command line"; \ exit 1; \ fi prepare-release: setup validate-tree-clean validate-version-format $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$(TARBALL_IMAGE) /dbld/prepare-release $(VERSION) validate-release: validate-tree-clean validate-version-format $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -i ${CONTAINER_REGISTRY}/dbld-$(TARBALL_IMAGE) /dbld/validate-release-version $(VERSION) @if $(GIT) rev-parse --verify -q "$(GIT_RELEASE_TAG)" > /dev/null; then \ echo "Your git tree already has $(GIT_RELEASE_TAG), this might indicate a duplicate release, please remove that first."; \ exit 1; \ fi # # release: # # the order of these is important, so invoke ourselves recursively # instead of using make dependencies, which can be reordered in parallel builds # release: validate-release ARTIFACT_DIR=$(RELEASE_DIR)/$(VERSION) && \ rm -rf "$$ARTIFACT_DIR" && mkdir -p "$$ARTIFACT_DIR" && rm -rf $(TARBALL) && \ $(DBLD_RULES) MODE=release VERSION=$(VERSION) pkg-tarball && \ echo "Building the release was successful, artifacts stored in $$ARTIFACT_DIR" && \ $(DBLD_RULES) MODE=release VERSION=$(VERSION) tag-release tag-release: $(GIT) tag $(GIT_RELEASE_TAG) clean: rm -rf $(BUILD_DIR)/* run: run-$(DEFAULT_IMAGE) run: RUN_COMMAND=echo Specify RUN_COMMAND to do something sensible here run-%: setup $(DOCKER) run $(DOCKER_RUN_ARGS) --rm -ti ${CONTAINER_REGISTRY}/dbld-$* bash -c "$(RUN_COMMAND)" shell: shell-$(DEFAULT_IMAGE) shell-%: setup $(DOCKER_SHELL) images: $(foreach image,$(IMAGES), image-$(image)) image: image-$(DEFAULT_IMAGE) image-kira: image-ubuntu-focal image-devshell: image-tarball image-tarball: image-debian-testing image-%: $(DBLD_DIR)/prepare-image-build $* && \ $(DOCKER) build $(DOCKER_BUILD_ARGS) --build-arg=ARG_IMAGE_PLATFORM=$* --build-arg=COMMIT=$$($(GIT) rev-parse --short HEAD || echo "") --build-arg=CONTAINER_REGISTRY=${CONTAINER_REGISTRY} --network=host -t ${CONTAINER_REGISTRY}/dbld-$* -f $(DBLD_DIR)/images/$*.dockerfile $(DBLD_DIR) push-images: $(foreach image,$(IMAGES), push-image-$(image)) push-image-%: @echo "Pushing image: $*" $(DOCKER) push ${CONTAINER_REGISTRY}/dbld-$* pull-images: $(foreach image,$(BUILDER_IMAGES), pull-image-$(image)) pull-image: pull-image-$(DEFAULT_IMAGE) pull-image-%: $(DOCKER) pull ${CONTAINER_REGISTRY}/dbld-$* cache-image-%: @IMAGE=${CONTAINER_REGISTRY}/dbld-$*:latest; \ IMAGE_ID=$$($(DOCKER) images -q $$IMAGE | head -1); \ WATCHED_FILES="dbld packaging/rhel/syslog-ng.spec packaging/debian/control"; \ if [ "$$IMAGE_ID" = "" ]; then \ $(DBLD_RULES) pull-image-$*; \ fi; \ IMAGE_ID=$$($(DOCKER) images -q $$IMAGE | head -1); \ if [ "$$IMAGE_ID" != "" ]; then \ image_commit=$$($(DOCKER) inspect --format '{{ index .Config.Labels "COMMIT"}}' $$IMAGE_ID); \ dbld_changes=$$( \ ($(GIT) cat-file -e $${image_commit:-NO_COMMIT_LABEL_IN_DBLD_IMAGE}^{commit} \ && $(GIT) diff $${image_commit} -- $${WATCHED_FILES} | wc -l \ || echo 1) \ ); \ else \ dbld_changes=1; \ fi; \ if [ "$${dbld_changes}" -gt 0 ]; then \ echo "Triggering rebuild of $$IMAGE, as dbld directory changed since the build of the image, or the " \ "cached image has no COMMIT label, or couldn't fetch from dockerhub or couldn't find git" && \ $(DBLD_RULES) image-$*; \ else \ echo "DBLD version in image matches, not initiating rebuild..."; \ fi exec: exec-$(DEFAULT_IMAGE) exec: EXEC_COMMAND=echo Specify EXEC_COMMAND to do something sensible here exec-%: setup @container=`$(DOCKER) ps | grep dbld-$* | head -1 | cut -d ' ' -f1`; \ $(DOCKER) exec -ti $$container $(EXEC_COMMAND) login: login-$(DEFAULT_IMAGE) login-%: EXEC_COMMAND=gosu $(shell whoami) /dbld/shell login-%: exec-% @true root-login: root-login-$(DEFAULT_IMAGE) root-login-%: EXEC_COMMAND=bash root-login-%: exec-% @true setup: @mkdir -p dbld/build || true @mkdir -p dbld/install || true @mkdir -p dbld/release || true list-builder-images: @echo ${BUILDER_IMAGES} syslog-ng-syslog-ng-4.4.0/dbld/shell000077500000000000000000000012161450431004300173150ustar00rootroot00000000000000#!/bin/bash echo -e "\n\nWelcome to the syslog-ng developer's shell... ($IMAGE_PLATFORM)\n" echo -e "You can find the source in /source, you can build the source using:\n" echo -e "\t\$ cd /build" echo -e "\t\$ /source/configure" echo -e "\t\$ make" echo -e "If configure is not yet available, run '/dbld/bootstrap' (in the container) or" echo -e "'./dbld/rules bootstrap' (on the host) or manually execute autogen.sh in the " echo -e "source dir.\n" if [ "$IMAGE_PLATFORM" != "devshell" ]; then echo -e "NOTE: the 'devshell' dbld image is more developer friendly, you might want to use that" fi cd /source debian_chroot="dbld" HOME=/build exec bash syslog-ng-syslog-ng-4.4.0/dbld/tarball000077500000000000000000000007421450431004300176320ustar00rootroot00000000000000#!/bin/bash . /dbld/functions.sh cd /source SYSLOGNG_DIR=syslog-ng-${VERSION} SYSLOGNG_TARBALL=${SYSLOGNG_DIR}.tar.gz ./autogen.sh # dist-build might be set to read-only by distcheck [ -d /build/dist-build ] && chmod +w -R /build/dist-build rm -rf /build/dist-build mkdir /build/dist-build cd /build/dist-build /source/configure --enable-manpages make dist mv ${SYSLOGNG_TARBALL} /build echo "Your tarball is in /build, also available on the host in \$(top_srcdir)/dbld/build" syslog-ng-syslog-ng-4.4.0/dbld/tarball-changes.ignore000066400000000000000000000000211450431004300225050ustar00rootroot00000000000000^/dbld ^/.git ^$ syslog-ng-syslog-ng-4.4.0/dbld/validate-release-version000077500000000000000000000022441450431004300231020ustar00rootroot00000000000000#!/bin/bash set -e cd /source VERSION=$1 MAJOR=$(echo ${VERSION} | cut -d. -f1) MINOR=$(echo ${VERSION} | cut -d. -f2) function validate_VERSION_file() { if [ "`cat VERSION`" != "${VERSION}" ]; then echo "The VERSION file in the root of the source tree does not have the version number to be released ${VERSION}. Please commit a version bump change first (or use prepare-release)." exit 1 fi } function grep_pattern_in_versioning_h() { VERSIONING_H="lib/versioning.h" PATTERN=$1 if ! grep --perl-regexp "${PATTERN}" ${VERSIONING_H} > /dev/null; then echo "${PATTERN} was not found in ${VERSIONING_H}" exit 1 fi } function validate_versioning_h_file() { grep_pattern_in_versioning_h "^#define VERSION_${MAJOR}_${MINOR} \"syslog-ng ${MAJOR}.${MINOR}\"$" grep_pattern_in_versioning_h "^#define VERSION_VALUE_${MAJOR}_${MINOR} 0x[a-f0-9]{4}$" grep_pattern_in_versioning_h "^#define VERSION_VALUE_CURRENT +VERSION_VALUE_${MAJOR}_${MINOR}$" grep_pattern_in_versioning_h "^#define VERSION_STR_CURRENT +\"${MAJOR}.${MINOR}\"$" grep_pattern_in_versioning_h "^#define VERSION_PRODUCT_CURRENT VERSION_${MAJOR}_${MINOR}$" } validate_VERSION_file validate_versioning_h_file syslog-ng-syslog-ng-4.4.0/dev-requirements.txt000066400000000000000000000002171450431004300214130ustar00rootroot00000000000000-r requirements.txt pycodestyle isort pylint astroid logilab-common<=0.63.0 prometheus-client psutil pytest pytest-mock pre-commit virtualenv syslog-ng-syslog-ng-4.4.0/dev-utils/000077500000000000000000000000001450431004300172675ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/000077500000000000000000000000001450431004300242105ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/Makefile.am000066400000000000000000000007501450431004300262460ustar00rootroot00000000000000EXTRA_DIST += \ dev-utils/plugin_skeleton_creator \ dev-utils/plugin_skeleton_creator/create_plugin.sh \ dev-utils/plugin_skeleton_creator/plugin_template_CMakeLists.txt \ dev-utils/plugin_skeleton_creator/plugin_template_grammar.ym \ dev-utils/plugin_skeleton_creator/plugin_template_Makefile.am \ dev-utils/plugin_skeleton_creator/plugin_template_parser.c \ dev-utils/plugin_skeleton_creator/plugin_template_parser.h \ dev-utils/plugin_skeleton_creator/plugin_template_plugin.c syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/create_plugin.sh000077500000000000000000000076401450431004300273770ustar00rootroot00000000000000#!/bin/bash ############################################################################# # Copyright (c) 2016 Balabit # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# top_srcdir="$(git rev-parse --show-toplevel)" current_year="$(date +%Y)" git_user_name="$(git config --get user.name)" year_and_author="$current_year $git_user_name" function print_help { echo "This script helps to create new plugin by creating a skeleton" echo "Parameters:" echo -e "\t-n\tName of the plugin (required)" echo -e "\t-k\tThe keyword in config file (default: name of the plugin)" echo -e "\t-t\tType of the plugin (default: LL_CONTEXT_DESTINATION)" echo -e "\t-d\tPlugin root dir (default: ${top_srcdir}/modules)" echo -e "\t-h\tPrint this help message" } plugin_name='' plugin_key='' plugin_type=LL_CONTEXT_DESTINATION plugin_root="${top_srcdir}/modules" template_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" help=0 file_list="plugin_template_grammar.ym plugin_template_Makefile.am plugin_template_CMakeLists.txt plugin_template_parser.c plugin_template_parser.h plugin_template_plugin.c" while getopts "k:n:t:d:h" opt; do case ${opt} in h) help=1 ;; n) plugin_name="${OPTARG}" ;; t) plugin_type="${OPTARG}" ;; k) plugin_key="${OPTARG}" ;; d) plugin_root="${OPTARG}" ;; esac done if test "${help}" -gt 0; then print_help exit 0 fi if [ -z "${plugin_name}" ]; then echo "Please set the plugin name" print_help exit 1 fi plugin_dir=${plugin_root}/${plugin_name} if ! [ -d "${plugin_root}" ]; then echo "Plugin root directory does not exists: ${plugin_root}" echo "Please set with -d parameter" print_help exit 1 fi if [ -d "${plugin_dir}" ]; then echo "Plugin already exists: ${plugin_dir}" exit 1 fi if [ -z "${plugin_key}" ]; then plugin_key=${plugin_name} fi echo "plugin name = ${plugin_name}" echo "plugin type = ${plugin_type}" echo "plugin key = ${plugin_key}" mkdir "${plugin_dir}" for filename in ${file_list}; do plugin_name_under_score=$(echo "${plugin_name}" | sed "s/-/_/g") plugin_name_under_score_uppercase="${plugin_name_under_score^^}" if [ "${filename}" == "plugin_template_Makefile.am" ]; then dst_filename="Makefile.am" elif [ "${filename}" == "plugin_template_CMakeLists.txt" ]; then dst_filename="CMakeLists.txt" else dst_filename=$(echo ${filename} | sed "s/plugin_template_/${plugin_name}-/g") fi dst_filename="${plugin_dir}"/"${dst_filename}" cp "${template_dir}/${filename}" "${dst_filename}" sed -i "s/@PLUGIN_NAME@/${plugin_name}/g" "${dst_filename}" sed -i "s/@PLUGIN_NAME_US@/${plugin_name_under_score}/g" "${dst_filename}" sed -i "s/@PLUGIN_NAME_USUC@/${plugin_name_under_score_uppercase}/g" "${dst_filename}" sed -i "s/@PLUGIN_TYPE@/${plugin_type}/g" "${dst_filename}" sed -i "s/@PLUGIN_KEY@/${plugin_key}/g" "${dst_filename}" sed -i "s/@YEAR_AND_AUTHOR@/${year_and_author}/g" "${dst_filename}" done echo "Done: new plugin skeleton is created in ${plugin_dir}" syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_CMakeLists.txt000066400000000000000000000005321450431004300322210ustar00rootroot00000000000000module_switch(ENABLE_@PLUGIN_NAME_USUC@ "Enable @PLUGIN_NAME@") if (NOT ENABLE_@PLUGIN_NAME_USUC@) return() endif() set(@PLUGIN_NAME_USUC@_SOURCES @PLUGIN_NAME@-parser.h @PLUGIN_NAME@-plugin.c @PLUGIN_NAME@-parser.c ) add_module( TARGET @PLUGIN_NAME_US@ GRAMMAR @PLUGIN_NAME@-grammar SOURCES ${@PLUGIN_NAME_USUC@_SOURCES} ) syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_Makefile.am000066400000000000000000000023221450431004300315140ustar00rootroot00000000000000module_LTLIBRARIES += modules/@PLUGIN_NAME@/lib@PLUGIN_NAME@.la modules_@PLUGIN_NAME_US@_lib@PLUGIN_NAME_US@_la_SOURCES = \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-grammar.y \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-parser.c \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-parser.h \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-plugin.c BUILT_SOURCES += \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-grammar.y \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-grammar.c \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-grammar.h EXTRA_DIST += \ modules/@PLUGIN_NAME@/@PLUGIN_NAME@-grammar.ym \ modules/@PLUGIN_NAME@/CMakeLists.txt modules_@PLUGIN_NAME_US@_lib@PLUGIN_NAME_US@_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/@PLUGIN_NAME@ \ -I$(top_builddir)/modules/@PLUGIN_NAME@ modules_@PLUGIN_NAME_US@_lib@PLUGIN_NAME_US@_la_LIBADD = $(MODULE_DEPS_LIBS) modules_@PLUGIN_NAME_US@_lib@PLUGIN_NAME_US@_la_LDFLAGS = $(MODULE_LDFLAGS) modules_@PLUGIN_NAME_US@_lib@PLUGIN_NAME_US@_la_DEPENDENCIES= $(MODULE_DEPS_LIBS) modules/@PLUGIN_NAME@ modules/@PLUGIN_NAME@/ mod-@PLUGIN_NAME@: modules/@PLUGIN_NAME@/lib@PLUGIN_NAME@.la .PHONY: modules/@PLUGIN_NAME@/ mod-@PLUGIN_NAME@ syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_grammar.ym000066400000000000000000000027731450431004300314670ustar00rootroot00000000000000/* * Copyright (c) @YEAR_AND_AUTHOR@ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "@PLUGIN_NAME@-parser.h" } %code { #include "cfg-grammar-internal.h" #include "cfg-parser.h" #include "syslog-names.h" #include "messages.h" #include "plugin.h" #include } %define api.prefix {@PLUGIN_NAME_US@_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %% start : @PLUGIN_TYPE@ first_rule { YYACCEPT; } ; first_rule : ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_parser.c000066400000000000000000000030571450431004300311260ustar00rootroot00000000000000/* * Copyright (c) @YEAR_AND_AUTHOR@ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "driver.h" #include "cfg-parser.h" #include "@PLUGIN_NAME@-grammar.h" extern int @PLUGIN_NAME_US@_debug; int @PLUGIN_NAME_US@_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword @PLUGIN_NAME_US@_keywords[] = { { NULL } }; CfgParser @PLUGIN_NAME_US@_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &@PLUGIN_NAME_US@_debug, #endif .name = "@PLUGIN_NAME@", .keywords = @PLUGIN_NAME_US@_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) @PLUGIN_NAME_US@_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(@PLUGIN_NAME_US@_, @PLUGIN_NAME_USUC@_, LogDriver **) syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_parser.h000066400000000000000000000022411450431004300311250ustar00rootroot00000000000000/* * Copyright (c) @YEAR_AND_AUTHOR@ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef @PLUGIN_NAME_USUC@_PARSER_H_INCLUDED #define @PLUGIN_NAME_USUC@_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser @PLUGIN_NAME_US@_parser; CFG_PARSER_DECLARE_LEXER_BINDING(@PLUGIN_NAME_US@_, @PLUGIN_NAME_USUC@_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/dev-utils/plugin_skeleton_creator/plugin_template_plugin.c000066400000000000000000000032041450431004300311220ustar00rootroot00000000000000/* * Copyright (c) @YEAR_AND_AUTHOR@ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser @PLUGIN_NAME_US@_parser; static Plugin @PLUGIN_NAME_US@_plugins[] = { { .type = @PLUGIN_TYPE@, .name = "@PLUGIN_KEY@", .parser = &@PLUGIN_NAME_US@_parser, }, }; gboolean @PLUGIN_NAME_US@_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, @PLUGIN_NAME_US@_plugins, G_N_ELEMENTS(@PLUGIN_NAME_US@_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "@PLUGIN_NAME_US@", .version = SYSLOG_NG_VERSION, .description = "Please fill this description", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = @PLUGIN_NAME_US@_plugins, .plugins_len = G_N_ELEMENTS(@PLUGIN_NAME_US@_plugins), }; syslog-ng-syslog-ng-4.4.0/dist.conf.in000066400000000000000000000005541450431004300175760ustar00rootroot00000000000000# default environment parameters SNAPSHOT_VERSION=${SNAPSHOT_VERSION:-@SNAPSHOT_VERSION@} SOURCE_REVISION=${SOURCE_REVISION:-@SOURCE_REVISION@} BROCHURE_VERSION=${BROCHURE_VERSION:-@BROCHURE_VERSION@} COMBINED_VERSION=${COMBINED_VERSION:-@COMBINED_VERSION@} TECHNICAL_VERSION=${TECHNICAL_VERSION:-@TECHNICAL_VERSION@} RELEASE_TYPE=${RELEASE_TYPE:-@RELEASE_TYPE@} syslog-ng-syslog-ng-4.4.0/doc/000077500000000000000000000000001450431004300161205ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/doc/ChangeLog.0000066400000000000000000000425001450431004300200310ustar00rootroot000000000000002005-01-16 Balazs Scheidler * configure.in: take CFLAGS environment variable into consideration when running configure, link eventlog and glib statically * src/fdread.c, src/fdwrite.c: handle EINTR by repeating the read system call * src/logreader, src/logwriter.c: handle EAGAIN correctly 2005-01-15 Balazs Scheidler * src/afsocket.c (afsocket_sd_accept): added g_fd_set_nonblock for new sockets 2005-01-09 Balazs Scheidler * src/logsource.c: new file, separated flow control related functions from logreader * src/logreader.c: LogReader is derived from LogSource * src/afinter.c: substituted the pipe used for internal messages with a GQueue 2005-01-05 Balazs Scheidler * configure.in: added checks for -ldoor, -lsocket, -lnsl and getopt.h * other files: fixed a couple of Solaris specific warnings 2004-12-31 Balazs Scheidler * src/macros.c: added PRI and MSGONLY macros * src/templates.c: added support for braces around macros for $example: "{MSG}" 2004-12-29 Balazs Scheidler * src/afprog.c (afprogram_dd_init): call setsid before launching child, (afprogram_dd_deinit): deinit & unref self->writer here instead of in afprogram_dd_free, * src/center.c (log_center_queue): do not supply self as user_data pointer to the ack_block callback as that would require adding a reference to self * src/dgroup.c (log_dest_group_queue): do not supply self as user_data pointer to the ack_block callback as that would require adding a reference to self * src/logreader.c: instead of using self->window_size use self->options->window_size so that the window is shared between all LogReaders using the same options, (log_reader_handle_line): add reference to self before supplying it as an argument to the ack_block callback function, (log_reader_msg_ack): unref the supplied logreader argument 2004-12-27 Balazs Scheidler * src/afsocket.c (afsocket_sd_deinit): break circular reference between self->reader and self, (afsocket_sd_notify): do not destroy/unref sender in NC_CLOSE, as afsocket_sd_close_connection already does that, (afsocket_sd_init, afsocket_sd_deinit): removed static, (afsocket_sd_free_instance): renamed from afsocket_sd_free, removed static, created a new afsocket_sd_free function at the same time which is set as the free_fn of AFSocketSourceDriver * src/afunix.c: implemented user/group/perm settings * src/cfg-grammar.y: added support for log-prefix * src/cfg.c: changed default timestamp format to BSD for compatibility * src/filter.c: fixed AND and OR operator evaluation, the operands were not correctly saved at initialization time, thus NULL was referenced at evaluation time * src/logreader.c: added log_prefix support for all log readers * src/logwriter.c: use log_msg_drop instead of a simple log_msg_unref * src/main.c: fixed SIGCHLD handling, loop while waitpid returns > 0, added tzset() call 2004-12-27 Balazs Scheidler * src/affile.c (affile_sd_deinit): make sure to break circular reference between self->reader and self, fixes possible memory leak, (affile_sd_free): call log_drv_free_instance * src/afinter.c (afinter_sd_deinit): break circular reference between self->reader and self * src/afprog.c (afprog_sd_free): added log_drv_free_instance * src/afsocket.c (afsocket_sd_deinit): break circular reference between self->reader and self, (afsocket_sd_free): added log_drv_free_instance, (afsocket_dd_free): -"- * src/afuser.c (afuser_dd_queue): free queued message, (afuser_dd_free): added log_drv_free_instance * src/cfg-grammar.y: unref log driver after appending to avoid memory leaks * src/cfg.c (cfg_reload_config): fixed possible memory leak when cfg_init fails (free persist), (persist_config_free): added missing free for hashtable * src/dgroup.c (log_dest_group_queue): make sure each driver gets its own reference to msg as each will free it on its own, also added an explicit unref at the end of the function (log_dest_group_new): added missing call to log_pipe_init_instance * src/gsockaddr.c: removed all low-level g_message invocation, errors should be reported by the caller * src/logpipe.c: added assertions to _ref and _unref * src/main.c (main_loop_run): added a missing g_main_loop_unref to avoid memory leaks, (main): call msg_syslog_started at the end of initialization to force messages into the system log * src/messages.c (msg_syslog_started): new function to indicate that initialization is finished, messages will be written to stderr instead of the internal() source if syslog is not yet started to let the administrator see important failure messages, (msg_deinit): free the event log context, only close the error pipe if it was really opened 2004-08-20 Balazs Scheidler * src/messages.c: adapted to the latest changes in the eventlog, now it actually compiles again and shows some signs of operation 2003-01-22 Balazs Scheidler * src/logwriter.c: support per-destination time stamp formatting options (keep_timestamp, tz_convert, ts_format) * src/logreader.c: support LR_STRICT flag (specifies LP_STRICT when parsing messages), new per-source option time_zone which specifies the sender's timezone * src/macros.c: support time_zone when formatting a message * src/templates.c: support time_zone specification for templates * src/logmsg.c: added timezone handling, the possibility to parse RFC3339 timestamps in incoming messages * src/cfg.c, src/cfg-grammar.y: added timestamp & timezone specific options * src/afsocket.c: strict RFC3164 mode does not allow RFC3339 timestamps, kept alive file descriptors are stored in persist offseted by +1, so NULL value is not possible * src/afinet.c: UDP uses strict RFC3164 timestamps * src/affile.c: added warning about template_escape() if the template used is not specified inline 2002-12-31 Balazs Scheidler * src/afsocket.c (afsocket_sd_set_keep_alive, afsocket_sd_set_listener_keep_alive): new functions to set the appropriate flags in self, (afsocket_sd_kill_connection): new function, kills and unrefs the given AFSocketSourceConnection object, (afsocket_sd_init, afsocket_sd_deinit): support persistent connections * src/cfg-grammar.y: the inline template definition stores the inline-ness in a gboolean attribute * src/cfg.c: implemented file/directory uid/gid/perm functions, (persist_config_add, persist_config_fetch): new functions * src/filter.c: store the marked matches in global variables, so macro expansion can reference it * src/macros.c: support variables $1 - $9 * src/misc.c: moved resolve_user & family functions here * src/main.c: use resolve_* functions from misc.c * src/afinet.c (afinet_sd_new): set flags to AFSOCKET_KEEP_ALIVE | AFSOCKET_LISTENER_KEEP_ALIVE * src/affile.c (affile_set_template_escape): modify the inline template object instead of a flag in self 2002-11-15 Balazs Scheidler * src/templates.c: make LogTemplate refcounted * src/logwriter.c (log_writer_format_log): support for file_template & proto_template * src/logreader.c: instead of relying on ourselves to let output buffers flush, we use glib source priority mechanism (the exact change was to return TRUE when a complete line is available in prepare), fixed MARK processing * src/cfg.c: file_template & proto_template support * src/cfg-lex.l: added two new options, file_template and proto_template, they specify the ID of a template which will be used by default for file/protocol outputs * src/gsockaddr.c: changed return values from G_IO_ERROR_* to G_IO_STATUS_* (glib 2 style) * src/afsocket.c: changed to match gsockaddr.c changes, fixed a bug that cause message loss between reconnections (self->log_writer was reinitialized before each reconnect) 2002-09-16 Balazs Scheidler * src/afprog.c (afprogram_dd_exit): new function, called when a child exited, calls deinit & init to restart the program (afprogram_dd_init): call child_manager_register(), so the program() destination supports restarting the program * src/afsocket.c: pass LR_PKTTERM flag for AFSOCKET_DGRAM sockets * src/cfg-grammar.y: new token KW_FOLLOW_FREQ, it is a reader option and specifies that the file should be followed using the given frequence (a'la tail -f ) * src/cfg-lex.l: renamed keyword 'mark' to 'mark_freq' * src/cfg.c: initialize follow_freq to -1 * src/children.c, src/children.h: new files which implement process children handling, it makes it possible to register callbacks for SIGCHLD * src/logmsg.c: added 'log parsing flags', prefixed LP_*, which modifies the way log messages are parsed, removed some specialized log_msg_new_*() functions, (log_msg_new_mark): new function, generates a MARK message * src/logreader.c: added follow file option, added packet terminated log processing (for SOCK_DGRAM sources), self->source_id was changed to a GSource *, and renamed to self->source, changed initialization and deinitialization code accordingly * src/main.c: initialize children.c, and call the necessary entry point upon SIGCHLD 2002-08-03 Balazs Scheidler * src/logreader.c, src/logreader.h: runtime variable log message size support * src/cfg.c, src/cfg.h: template storage support * src/cfg-grammar.y: add support for template keywords, add support for log_msg_size * src/templates.c, src/templates.h: new files for defineable templates 2002-07-28 Balazs Scheidler * src/syslog-ng.h: added LOG_PRIORITY_* defines * src/messages.c: initialize msg_pipe to {-1,-1} to let the internal() driver know that internal message pipe has not been initialized * src/logwriter.h (LogWriterOptions): moved fifo_size to here, added declaration for log_writer_options_* functions * src/logwriter.c (log_writer_watch_new): set priority to LOG_PRIORITY_WRITER (log_writer_queue): use log_fifo_size from options, added some more detail to message reporting queue full (log_writer_new): removed initialization of log_fifo_size, it is used from writer_options instead (log_writer_options_defaults): new function (log_writer_options_init): new function * src/logreader.h (LogReaderOptions): added fetch_limit (LogReader): added prev_addr field (to hold the sockaddr of the previous buffer, added declaration for log_reader_options_defaults, log_reader_options_init * src/logreader.c (log_reader_watch_new): set source priority to LOG_PRIORITY_READER (log_reader_iterate_buf): implemented fetch_limit option, fixed sockaddr handling when something remains in the buffer (log_reader_options_defaults, log_reader_options_init): new functions * src/logmsg.c (log_msg_ack_block_end): fixed memory leak, instead of simply removing the list entry, delete it * src/cfg.h (GlobalConfig): added fields log_iw_size and log_fetch_limit * src/cfg.c (cfg_new): set default options for log_iw_size and log_fetch_limit * src/cfg-lex.l: added keywords for log_iw_size and log_fetch_limit * src/cfg-grammar.y: cleaned up token section, added options log_iw_size, log_fetch_limit, fixed log_fifo_size * src/center.c (log_center_queue): pass a reference of msg further, otherwise msg was freed too early * src/afsocket.c (g_listen_source_new): set priority to LOG_PRIORITY_LISTEN (g_connect_source_new): set priority to LOG_PRIORITY_CONNECT (afsocket_sd_init): call log_reader_options_init (afsocket_sd_init_instance): call log_reader_options_defaults instead of setting reader options directly (afsocket_dd_init): call log_writer_options_init (afsocket_dd_init_instance): call log_writer_options_defaults * src/afprog.c (afprogram_dd_init): call log_writer_options_init (afprogram_dd_new): call log_writer_options_defaults * src/afinter.c (afinter_sd_init): call log_reader_options_init, handle the case when internal messages are written to stderr instead of the log (afinter_sd_new): call log_reader_options_defaults * src/affile.c (affile_sd_init): call log_reader_options_init (affile_dd_new): call log_reader_options_defaults (affile_dw_deinit): fixed memory leak, unref self->writer when deinitialized (affile_dd_init): call log_writer_options_init (affile_dd_queue): handle the case when the dw cannot be initialized (affile_dd_new): call log_writer_options_defaults 2002-07-27 Balazs Scheidler * src/main.c (sig_segv_handler): new function, handles SIGSEGV signals * src/macros.c (result_append): instead of using g_string_sprintfa to append an escaped char, append it using g_string_append_c (supposed to be faster) * src/logmsg.c (log_msg_ref, log_msg_unref): added assert() calls to check whether ref_cnt has reached zero * src/afsocket.c (afsocket_sc_free): bugfix, set self->owner->connections to the value returned by g_list_remove(), this one caused major headache to find * src/affile.c (affile_dd_queue): free filename if dw is already allocated 2002-06-30 Balazs Scheidler * src/main.c: support for memtrace added * src/logwriter.c, src/logwriter.h: use fd_write objects instead of simple fds * src/logreader.c, src/logreader.h: use fd_read objects instead of simple fds * src/logmsg.c (log_msg_ack_block_end): fixed memory leak, free the allocated memory block * src/fdread.c, src/fdread.h:: new files which implement file descriptor reading * src/fdwrite.c, src/fdwrite.h:: new files which implement file descriptor writing * src/cfg-grammar.y: pass AFSOCKET_LOCAL flag to unix domain socket sources * src/afsocket.c: removed finalize function from g_connect & g_listen sources, pass fd_read to log_reader, and fd_write to log_writer instead of plain fds * src/affile.c, src/afinter.c, src/afprog.c: pass fd_read object to log_reader_new, and fd_write to log_writer instead of plain fds * src/memtrace.c, src/memtrace.h: ported from Zorp * src/Makefile.am: added memtrace.c & memtrace.h * configure.in: added --enable-mem-trace switch 2002-06-15 Balazs Scheidler * afsocket.c: ported to glib-2.0 * logreader.c: ported to glib-2.0 * logwriter.c: LogWriterOptions split from the main structure, ported to glib-2.0 * affile.h: moved AFFileSourceDriver and AFFileDestDriver here, so the parser can use reader_options/writer_options fields directly * cfg-grammar.y: make log_reader and log_writer options separate rules, so it is easier to add common rules for all source/destination driver * configure.in: use glib-2.0 and pkgconfig 2002-06-08 Balazs Scheidler * src/messages.c: debug messages are never written to syslog as internal message as it would drain the system (for example every incoming log message is reported as a debug message, they are always written to stderr instead * src/cfg-grammar.y, src/cfg-lex.l: added support for flow controlled message paths * src/center.h: LC_FLOW_CONTROL new flag * src/center.c: sources are also stored in a g_ptr_array in addition to the hash table to make it easier to perform iterative tasks (g_hash_table_foreach requires a function pointer), and source references are also resolved at init time. * src/logreader.c, src/center.c, src/dgroup.c, src/logwriter.c, src/afuser.c: implemented flow control * src/logpipe.h: added path_flags argument to queue() as it specifies whether the sender wants ack or not (used by flow control), * src/logreader.h: separated log reader specific options to another structure (LogReaderOptions), to make it easier to specify reader options from the configuration 2002-05-13 Balazs Scheidler * src/messages.h, src/messages.c: added support for verbose_flag and debug_flag, and implemented internal message handling * src/logreader.c: added new flag LR_NOCLOSE to avoid closing the fd if the logreader is destroyed, added LR_INTERNAL for processing internal messages, and LR_NOPARSE to avoid parsing incoming message * src/afinter.c: implemented internal messages driver 2002-05-09 Balazs Scheidler * src/afprog.c: added the ability to respawn the child program once it exited * src/messages.h: added msg_debug macro * src/main.c: added processing most of the command line options, added the ability to go into background, chroot, setuid, setgid etc. * src/afunix.c: implemented afunix sources and destinations * src/logpipe.h: added NC_WRITE_ERROR, renamed NC_CLOSE_ERROR to NC_READ_ERROR, changed referrences appropriately, (log_pipe_append): new function * src/afinet.c: implemented hostname and service lookup, implemented reconnection after a timeout, implemented EOF detection when the channel is idle * src/logwriter.c, src/logreader.c: added new argument named control where notify messages are sent, log readers have no explicit 'next' argument anymore, pipes are constructed using log_pipe_append instead * src/affile.c: implemented destination file reaping 2002-04-04 Balazs Scheidler * affile, afpipe and afinet fixes * do not leak memory on -HUP syslog-ng-syslog-ng-4.4.0/doc/ChangeLog.1000066400000000000000000001572061450431004300200440ustar00rootroot00000000000000# do not edit -- automatically generated by arch changelog # not-id: automatic-ChangeLog--bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0 # 2006-02-11 07:31:40 GMT Balazs Scheidler patch-86 Summary: fixed possible 64 bit compatibility problem Revision: syslog-ng--mainline--2.0--patch-86 * src/logwriter.c (log_writer_queue, log_writer_flush_log): use GPOINTER_TO_UINT/GUINT_TO_POINTER macros instead of casting the values by hand modified files: ChangeLog src/logwriter.c src/logwriter.h 2006-01-25 17:13:29 GMT Balazs Scheidler patch-85 Summary: added support for hostname resolution (fixes: #8036) Revision: syslog-ng--mainline--2.0--patch-85 2006-01-25 Balazs Scheidler * src/afinet.c: support an optional self->dest_addr * src/afsocket.c (afsocket_dd_init): fail if self->dest_addr is NULL, (afsocket_sd_init): fail if self->bind_addr is NULL * src/gsockaddr.c (g_sockaddr_inet_new_resolve): new function, resolves a hostname and stores the result in a GSockAddr, modified files: ChangeLog src/afinet.c src/afinet.h src/afsocket.c src/gsockaddr.c src/gsockaddr.h 2006-01-20 10:01:44 GMT Balazs Scheidler patch-84 Summary: added stats counter sharing and a way to disable stats counter Revision: syslog-ng--mainline--2.0--patch-84 2006-01-20 Balazs Scheidler * src/stats.c (stats_register_counter): added shared parameter to specify that the given counter can be shared * src/logwriter.h (LogWriterOptions): added flags member and two flags LWOF_NO_STATS, LWOF_SHARED_STATS * src/logwriter.c (log_writer_options_init): converted fixed_stamp parameter to a flag word, the actual value is LWOF_FIXED_STAMP, (log_writer_init): don't register a stats counter if LWOF_NO_STAMP is specified * src/af*.c: changed the call of log_writer_options_init() modified files: ChangeLog src/affile.c src/afprog.c src/afsocket.c src/logwriter.c src/logwriter.h src/stats.c src/stats.h 2006-01-13 13:17:29 GMT Balazs Scheidler patch-83 Summary: added compatibility option for stats Revision: syslog-ng--mainline--2.0--patch-83 2006-01-13 Balazs Scheidler * src/cfg-lex.l: added a "stats" keyword to be compatible with 1.6.x modified files: ChangeLog src/cfg-lex.l 2005-12-31 14:09:13 GMT Balazs Scheidler patch-82 Summary: fixed EOF detected messages for UDP destinations where the target is unreachable Revision: syslog-ng--mainline--2.0--patch-82 2005-12-31 Balazs Scheidler * src/afsocket.c (afsocket_dd_init): don't set LW_DETECT_EOF for UDP destinations * src/logwriter.c (log_writer_fd_dispatch): EOF is detected only if G_IO_IN is detected and not for G_IO_ERR as it might be set for UDP destinations when they are unreachable modified files: ChangeLog src/afsocket.c src/logwriter.c 2005-12-20 20:52:38 GMT Balazs Scheidler patch-81 Summary: perparations for an 1.9.8 release Revision: syslog-ng--mainline--2.0--patch-81 modified files: ChangeLog NEWS VERSION 2005-12-20 20:34:51 GMT Balazs Scheidler patch-80 Summary: fixed UDP destination driver initialization Revision: syslog-ng--mainline--2.0--patch-80 2005-12-20 Balazs Scheidler * src/afsocket.c (afsocket_dd_connected): only check socket error state for stream sockets as UDP connections succeed immediately, (afsocket_dd_reconnect): if g_connect returns immediate success (UDP connections) set self->fd to sock modified files: ChangeLog src/afsocket.c 2005-12-05 20:24:45 GMT Balazs Scheidler patch-79 Summary: fix time conversion to the specified timezone Revision: syslog-ng--mainline--2.0--patch-79 2005-12-05 Balazs Scheidler * src/logmsg.c (log_stamp_format): instead of substracting the timezone offset substract it (credit for reporting goes to Andy), * src/macros.c (log_macro_expand): -"- * src/logmsg.c (log_msg_parse): time zone specifies can be more than 12 hours, fixed. modified files: ChangeLog src/logmsg.c src/macros.c 2005-12-03 16:42:19 GMT Balazs Scheidler patch-78 Summary: include VERSION in the dist Revision: syslog-ng--mainline--2.0--patch-78 modified files: ChangeLog Makefile.am 2005-12-03 16:34:15 GMT Balazs Scheidler patch-77 Summary: fixed MARK support Revision: syslog-ng--mainline--2.0--patch-77 2005-12-03 Balazs Scheidler * doc/reference/syslog-ng.xml: added some more words on mark_freq() and stats_freq(), actually fixed the documentation as these options were renamed for consistency * src/afinter.c: move MARK implementation to here instead of logreader, there's no point in creating MARK messages in the name of all of our sources, we need to generate a single MARK message in our name if there's no traffic * src/main.c: removed the use of obsolete GLib functions modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/afinter.c src/afinter.h src/center.c src/logreader.c src/logreader.h src/main.c 2005-12-03 15:49:30 GMT Balazs Scheidler patch-76 Summary: minor documentation updates, updated NEWS, bumped VERSION to 1.9.7 Revision: syslog-ng--mainline--2.0--patch-76 modified files: ChangeLog NEWS VERSION doc/reference/syslog-ng.xml 2005-12-03 15:29:36 GMT Balazs Scheidler patch-75 Summary: fixed a possible segmentation fault during HUPs Revision: syslog-ng--mainline--2.0--patch-75 2005-12-03 Balazs Scheidler * src/afsocket.c (afsocket_sc_init): fixed DGRAM socket initialization to actually process incoming data in packets (the LR_PKTTERM flag was missed), (afsocket_sd_deinit): don't free the connection list items when iterating the list as connections are removed from the list when they are freed, the loop there only needs to break the circular references modified files: ChangeLog src/afsocket.c 2005-12-03 11:23:55 GMT Balazs Scheidler patch-74 Summary: added VERSION file Revision: syslog-ng--mainline--2.0--patch-74 new files: .arch-ids/VERSION.id VERSION modified files: ChangeLog 2005-12-03 11:23:46 GMT Balazs Scheidler patch-73 Summary: added debianization files, misc build fixes Revision: syslog-ng--mainline--2.0--patch-73 2005-12-03 Balazs Scheidler * debian/*: added debianization files * configure.in: added VERSION file instead of having the actual VERSION inline, added CURRDATE to make it possible to generate debian/changelog automatically new files: debian/.arch-ids/=id debian/.arch-ids/README.Debian.id debian/.arch-ids/changelog.in.id debian/.arch-ids/control.id debian/.arch-ids/copyright.id debian/.arch-ids/rules.id debian/.arch-ids/syslog-ng.conf.example.id debian/.arch-ids/syslog-ng.conf.id debian/.arch-ids/syslog-ng.default.id debian/.arch-ids/syslog-ng.docs.id debian/.arch-ids/syslog-ng.files.id debian/.arch-ids/syslog-ng.init.id debian/.arch-ids/syslog-ng.logcheck.ignore.id debian/.arch-ids/syslog-ng.logrotate.example.id debian/.arch-ids/syslog-ng.logrotate.id debian/.arch-ids/syslog-ng.postinst.id debian/.arch-ids/syslog-ng.postrm.id debian/.arch-ids/syslog-ng.preinst.id debian/README.Debian debian/changelog.in debian/control debian/copyright debian/rules debian/syslog-ng.conf debian/syslog-ng.conf.example debian/syslog-ng.default debian/syslog-ng.docs debian/syslog-ng.files debian/syslog-ng.init debian/syslog-ng.logcheck.ignore debian/syslog-ng.logrotate debian/syslog-ng.logrotate.example debian/syslog-ng.postinst debian/syslog-ng.postrm debian/syslog-ng.preinst modified files: ChangeLog Makefile.am configure.in new directories: debian debian/.arch-ids 2005-11-25 15:25:19 GMT Balazs Scheidler patch-72 Summary: fixed Solaris STREAMS based log device support Revision: syslog-ng--mainline--2.0--patch-72 2005-11-25 Balazs Scheidler * src/afsocket.c (afsocket_dd_format_stats_name): fix compiler warning about uninitialized driver_name, the switch statement covers every possible case * src/afstreams.c: fix compilation issues, it now actually compiles and works on Solaris (tested on Solaris 9) modified files: ChangeLog configure.in src/afsocket.c src/afstreams.c 2005-11-23 16:31:48 GMT Balazs Scheidler patch-71 Summary: fixed timezone calculation Revision: syslog-ng--mainline--2.0--patch-71 2005-11-23 Balazs Scheidler * src/misc (get_local_timezone_ofs): fixed timezone calculation again, * tests/unit/test_zone.c: added some missing testcases for timezones over 12 hours (New Zealand) * tests/unit/test_filters.c: fixed facility testing as the code was changed modified files: ChangeLog src/misc.c tests/unit/test_filters.c tests/unit/test_zone.c 2005-11-15 15:35:15 GMT Balazs Scheidler patch-70 Summary: fixed the detetion of Solaris STREAMS support, fixed segfault when it was not compiled in Revision: syslog-ng--mainline--2.0--patch-70 modified files: ChangeLog configure.in src/afstreams.c 2005-11-03 17:03:26 GMT Balazs Scheidler patch-69 Summary: fixed log message concatenation in certain cases Revision: syslog-ng--mainline--2.0--patch-69 2005-11-03 Balazs Scheidler * src/templates.c (log_template_format): truncate the string before formatting a log message modified files: ChangeLog src/templates.c 2005-10-24 08:40:59 GMT Balazs Scheidler patch-68 Summary: readded syslog-ng.h as it was missed from the distribution Revision: syslog-ng--mainline--2.0--patch-68 modified files: ChangeLog src/Makefile.am 2005-10-22 21:29:23 GMT Balazs Scheidler patch-67 Summary: stats.c & stats.h were not commited in the previous patch Revision: syslog-ng--mainline--2.0--patch-67 new files: src/.arch-ids/stats.c.id src/.arch-ids/stats.h.id src/stats.c src/stats.h modified files: ChangeLog 2005-10-22 21:28:46 GMT Balazs Scheidler patch-66 Summary: added per-destination dropped counters and some bugfixes Revision: syslog-ng--mainline--2.0--patch-66 2005-10-22 Balazs Scheidler * src/stats.{c,h}: new files, a simple framework for named statistical counters, currently only used for per-destination dropped counters * src/message.c, src/messages.h (msg_event): the function was split to msg_event_create and msg_event_send functions and macros were changed accordingly, the reason is that the STATS message uses dynamic message tags * src/main.c (stats_timer): new function to issue statistics message using the stats framework * src/logwriter.h (LogWriterOptions): added stats_name member which is used when registering the dropped counters, (LogWriter): added dropped_messages member to point to our private dropped counter * src/logwriter.c (log_writer_init): register dropped counter, (log_writer_free): deregister dropped counter, (log_writer_options_init): store the name of the dropped counter, added a warning message for the flush_lines > fifo_size case as this will not work, (log_writer_flush_log): call log_writer_broken when an error occurs, (log_writer_broken): changed argument list to be usable from log_writer_flush_log, log message moved out of the function as it might be called from different places, (log_writer_queue): increment dropped counter, (log_writer_fd_prepare, log_writer_fd_check): fixed flush_timeout handling * src/Makefile.am: moved headers to SOURCES from EXTRA_DIST (I like it better this way (tm)) * src/logpipe.h, src/logmsg.h: don't include glib.h directly, use syslog-ng.h instead * src/misc.c (format_zone_info): readded ':' to zone offset formatting, which was missed in the previous patch, fixed the sign for zone offsets * src/logmsg.c (log_stamp_format): the buffer for the zone offset was not large enough to hold the readded ':' * src/cfg-grammar.y, src/cfg-lex.l: added global stats_freq option * src/afprog.c, src/affile.c, src/afprog.c: added dropped stats support * src/afsocket.c: added dropped stats support, (afsocket_dd_connected): do not reinit the writer, (afsocket_dd_init): do not create a new LogWriter instance every time, but reuse the previous one instead, (afsocket_dd_free): fix memory leak by freeing self->writer removed files: src/.arch-ids/sdriver.c.id src/sdriver.c modified files: ChangeLog src/Makefile.am src/affile.c src/afprog.c src/afsocket.c src/cfg-grammar.y src/cfg-lex.l src/logmsg.c src/logmsg.h src/logpipe.h src/logwriter.c src/logwriter.h src/main.c src/messages.c src/messages.h src/misc.c 2005-10-22 17:20:32 GMT Balazs Scheidler patch-65 Summary: do not use the LOG_FAC macro as it is not portable Revision: syslog-ng--mainline--2.0--patch-65 2005-10-22 Balazs Scheidler * src/filter.c: do not use the LOG_FAC macro, it is not available on Solaris * doc/reference/syslog-ng.xml: added documentation on the alternate syntax of the facility() filter modified files: ChangeLog doc/reference/syslog-ng.xml src/filter.c 2005-10-21 16:07:47 GMT Balazs Scheidler patch-64 Summary: test commit for syslog-ng-commit message Revision: syslog-ng--mainline--2.0--patch-64 modified files: ChangeLog src/logmsg.c 2005-10-18 15:40:14 GMT Balazs Scheidler patch-63 Summary: added a note on empty source/destination statements Revision: syslog-ng--mainline--2.0--patch-63 modified files: ChangeLog doc/reference/syslog-ng.xml 2005-10-15 16:36:43 GMT Balazs Scheidler patch-62 Summary: fixed non-null terminated utmp username handling Revision: syslog-ng--mainline--2.0--patch-62 2005-10-15 Balazs Scheidler * src/afuser.c: instead of assuming that names in utmp are NUL terminated (which turned out not to be true), limit the length of comparison to sizeof(ut->ut_name) modified files: ChangeLog src/afuser.c 2005-10-15 16:15:57 GMT Balazs Scheidler patch-61 Summary: preparation for the 1.9.6 release Revision: syslog-ng--mainline--2.0--patch-61 modified files: ChangeLog NEWS configure.in 2005-10-15 16:04:45 GMT Balazs Scheidler patch-60 Summary: fixed problems in syslog priority filter, added unit test for most built-in filters Revision: syslog-ng--mainline--2.0--patch-60 2005-10-15 Balazs Scheidler * src/filter.c (filter_facility_eval): added facility value -> bitmap position cache for improved performance, (filter_level_eval): fixed filter evaluation (the function erroneously used the same values for the internal valid bitmap and the syslog header priority value), a similar search through sl_levels is required as was already present for facility filtering, also the same cache mechanism was added for improved performance * tests/unit/test_filter.c: new unit test file, tests most easily testable filters, AND/OR operations and negation new files: tests/unit/.arch-ids/test_filters.c.id tests/unit/test_filters.c modified files: ChangeLog configure.in src/filter.c tests/unit/Makefile.am tests/unit/test_msgparse.c 2005-10-15 14:25:22 GMT Balazs Scheidler patch-59 Summary: timezone DST fixes Revision: syslog-ng--mainline--2.0--patch-59 2005-10-15 Balazs Scheidler * configure.in: removed check for the global timezone variable * src/misc.c (get_local_timezone_ofs): use tm->tm_gmtoff if available and the difference between the results of gmtime and localtime if not, this should be a portable way to determine the correct timezone offset, (format_zone_info): new function to format a timezone offset in a way similar to strftime %z * src/logmsg.c (log_stamp_format): use the new format_zone_info function * src/macros.c (log_macro_expand): always use the new format_zone_info function instead of strftime * doc/reference/syslog-ng.xml: TZ is now equivalent to TZOFFSET new files: tests/unit/.arch-ids/test_zone.c.id tests/unit/test_zone.c modified files: ChangeLog configure.in doc/reference/syslog-ng.xml src/logmsg.c src/macros.c src/misc.c src/misc.h tests/unit/Makefile.am tests/unit/test_msgparse.c 2005-10-07 16:16:35 GMT Balazs Scheidler patch-58 Summary: added a missing "return" Revision: syslog-ng--mainline--2.0--patch-58 2005-10-07 Balazs Scheidler * src/misc.c (get_local_timezone_ofs): added a missing return modified files: ChangeLog src/misc.c 2005-10-05 13:48:34 GMT Balazs Scheidler patch-57 Summary: check for gmt_off in struct tm and detect timezone accordingly Revision: syslog-ng--mainline--2.0--patch-57 2005-10-05 Balazs Scheidler * configure.in: added a test for tm_gmtoff in struct tm as it is not present on Solaris * src/misc.c: use the old global timezone based timezone detection code if tm_gmtoff is not present in "struct tm" modified files: ChangeLog configure.in src/misc.c 2005-10-01 21:39:51 GMT Balazs Scheidler patch-56 Summary: fixed facility/priority filters Revision: syslog-ng--mainline--2.0--patch-56 modified files: ChangeLog src/filter.c 2005-09-26 09:16:38 GMT Balazs Scheidler patch-55 Summary: contrib subdirectory and its contents copied from syslog-ng 1.6.x Revision: syslog-ng--mainline--2.0--patch-55 new files: contrib/.arch-ids/=id contrib/.arch-ids/Makefile.am.id contrib/.arch-ids/README.id contrib/.arch-ids/init.d.HP-UX.id contrib/.arch-ids/init.d.RedHat-7.3.id contrib/.arch-ids/init.d.RedHat.id contrib/.arch-ids/init.d.SuSE.id contrib/.arch-ids/init.d.SunOS.id contrib/.arch-ids/init.d.solaris.id contrib/.arch-ids/relogger.pl.id contrib/.arch-ids/syslog-ng.conf.HP-UX.id contrib/.arch-ids/syslog-ng.conf.RedHat.id contrib/.arch-ids/syslog-ng.conf.SunOS.id contrib/.arch-ids/syslog-ng.conf.doc.id contrib/.arch-ids/syslog-ng.vim.id contrib/.arch-ids/syslog2ng.id contrib/Makefile.am contrib/README contrib/fedora-packaging/.arch-ids/=id contrib/fedora-packaging/.arch-ids/syslog-ng.conf.id contrib/fedora-packaging/.arch-ids/syslog-ng.init.id contrib/fedora-packaging/.arch-ids/syslog-ng.logrotate.id contrib/fedora-packaging/.arch-ids/syslog-ng.sysconfig.id contrib/fedora-packaging/syslog-ng.conf contrib/fedora-packaging/syslog-ng.init contrib/fedora-packaging/syslog-ng.logrotate contrib/fedora-packaging/syslog-ng.sysconfig contrib/init.d.HP-UX contrib/init.d.RedHat contrib/init.d.RedHat-7.3 contrib/init.d.SuSE contrib/init.d.SunOS contrib/init.d.solaris contrib/relogger.pl contrib/rhel-packaging/.arch-ids/=id contrib/rhel-packaging/.arch-ids/syslog-ng.conf.id contrib/rhel-packaging/.arch-ids/syslog-ng.init.id contrib/rhel-packaging/.arch-ids/syslog-ng.logrotate.id contrib/rhel-packaging/syslog-ng.conf contrib/rhel-packaging/syslog-ng.init contrib/rhel-packaging/syslog-ng.logrotate contrib/syslog-ng.conf.HP-UX contrib/syslog-ng.conf.RedHat contrib/syslog-ng.conf.SunOS contrib/syslog-ng.conf.doc contrib/syslog-ng.vim contrib/syslog2ng modified files: ChangeLog Makefile.am configure.in new directories: contrib contrib/.arch-ids contrib/fedora-packaging contrib/fedora-packaging/.arch-ids contrib/rhel-packaging contrib/rhel-packaging/.arch-ids 2005-08-30 07:35:56 GMT Balazs Scheidler patch-54 Summary: fixed template-escape processing for inline templates Revision: syslog-ng--mainline--2.0--patch-54 2005-08-30 Balazs Scheidler * src/affile.c (affile_dd_set_file_template, affile_dd_set_template_escape, affile_dd_set_fsync): removed as templates are logwriter specific options, (affile_dd_new): do not allocate 'templates' variable, (affile_dd_free): do not free 'templates' * src/affile.h (AFFileDestDriver): removed template variable as it was not used * src/cfg-grammar.y (dest_writer_option): template_escape and fsync were erroneously calling affile specific functions, fixed that * src/logwriter.c (log_writer_options_set_template_escape): new function, basically transformed from affile_dd_set_template_escape modified files: ChangeLog src/affile.c src/affile.h src/cfg-grammar.y src/logwriter.c 2005-08-29 07:56:11 GMT Balazs Scheidler patch-53 Summary: added configure test for regexec() function Revision: syslog-ng--mainline--2.0--patch-53 modified files: ChangeLog configure.in 2005-08-08 07:37:15 GMT Balazs Scheidler patch-52 Summary: fixed test_msgparse program to work on BSDs Revision: syslog-ng--mainline--2.0--patch-52 2005-08-08 Balazs Scheidler * tests/unit/test_msgparse.c (main): do not use "timezone" as a global variable as it is a function on BSD derived platforms modified files: ChangeLog tests/unit/test_msgparse.c 2005-08-07 17:31:23 GMT Balazs Scheidler patch-51 Summary: fixed file uid/gid setting and some gcc4 problems Revision: syslog-ng--mainline--2.0--patch-51 2005-08-07 Balazs Scheidler * src/affile.c: fixed affile_dd_set_{file,dir}_{uid,gid} * src/*.h: added complete prototypes for all functions modified files: ChangeLog src/affile.c src/affile.h src/afinter.h src/cfg.h src/memtrace.h src/messages.h src/misc.c src/misc.h 2005-08-04 12:28:36 GMT Balazs Scheidler patch-50 Summary: fixed mark_freq problem Revision: syslog-ng--mainline--2.0--patch-50 2005-08-04 Balazs Scheidler * src/logreader.c (log_reader_fd_prepare): make sure make_target is initialized before going to the poll loop first modified files: ChangeLog src/logreader.c 2005-08-04 11:11:39 GMT Balazs Scheidler patch-49 Summary: deprecated sync_freq, introduced flush_lines instead, fixed a faction of seconds formatting problem Revision: syslog-ng--mainline--2.0--patch-49 2005-08-04 Balazs Scheidler * doc/reference/syslog-ng.xml: added documentation on the new flush_lines and flush_timeout options * src/affile.c (affile_dd_set_sync_freq): removed sync_freq support, did not work anyway, introduced flush_lines & flush_timeout instead * src/afinet.c (afinet_dd_set_sync_freq): removed * src/cfg-grammar.y: added flush options * src/cfg.c: -"- * src/logwriter.c: added flush_lines and flush_timeout support * src/logmsg.c: fixed time fraction formatting NEWS * NEWS.hu * modified files: ChangeLog doc/reference/syslog-ng.xml src/affile.c src/affile.h src/afinet.c src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/logmsg.c src/logwriter.c src/logwriter.h 2005-07-30 20:48:37 GMT Balazs Scheidler patch-48 Summary: further fixes to the previous patch to unify tcp/udp codepaths in afsocket, test program fixes Revision: syslog-ng--mainline--2.0--patch-48 2005-07-30 Balazs Scheidler * src/afinter.c (afinter_source_dispatch): do not dispatch message if it is NULL (might happen if several internal sources are defined) * src/afsocket.c (afsocket_sc_queue): removed bogus internal error message, (afsocket_sd_init): added error handling around listen() * tests/functional/func_test.py: added AF_INET testing (udp & tcp) NEWS * NEWS.hu * modified files: ChangeLog src/afinter.c src/afsocket.c tests/functional/func_test.py 2005-07-30 20:20:50 GMT Balazs Scheidler patch-47 Summary: fixed stupid UDP initialization problem and updated a unit test program Revision: syslog-ng--mainline--2.0--patch-47 2005-07-30 Balazs Scheidler * src/afsocket.c (afsocket_sd_init): fixed stupid mistake in UDP initialization code * tests/unit/test_msgparse.c: adapted to the new timezone parsing code (msg has the local timezone by default instead of -1) NEWS * NEWS.hu * modified files: ChangeLog src/afsocket.c tests/unit/test_msgparse.c 2005-07-28 13:39:43 GMT Balazs Scheidler patch-46 Summary: added cfg-lex.c and cfg-grammar.c to the distribution Revision: syslog-ng--mainline--2.0--patch-46 modified files: ChangeLog src/Makefile.am 2005-07-28 13:37:23 GMT Balazs Scheidler patch-45 Summary: small Makefile fixes and a flex compatibility fix Revision: syslog-ng--mainline--2.0--patch-45 2005-07-28 Balazs Scheidler * src/Makefile.am: added cfg-lex.c and cfg-grammar.c to MAINTAINER_CLEAN_FILES * src/cfg-lex.l: removed YY_NO_UNPUT as it was not standard (reported by Roberto Nibali) modified files: ChangeLog src/Makefile.am src/cfg-lex.l 2005-07-26 09:23:24 GMT Balazs Scheidler patch-44 Summary: use the same code path for SOCK_STREAM and SOCK_DGRAM sockets Revision: syslog-ng--mainline--2.0--patch-44 2005-07-26 Balazs Scheidler * src/afsocket.c (afsocket_sd_init, afsocket_sd_deinit): unified SOCK_STREAM and SOCK_DGRAM code-paths, do not use a separate reader for SOCK_DGRAM, use AFSocketSourceConnection instead for both types, (afsocket_sd_format_persist_name): new function, to format a persistent config name, instead of doing it inline every time modified files: ChangeLog src/afsocket.c src/afsocket.h 2005-07-26 09:21:15 GMT Balazs Scheidler patch-43 Summary: timezone portability fixes for BSDs Revision: syslog-ng--mainline--2.0--patch-43 2005-07-26 Balazs Scheidler * src/misc.c (get_local_timezone_ofs): added a time_t when argument, the timezone will be returned for that given time in UTC, the algorithm to return a timezone does not rely on the timezone and daytime global variables as those are Linux specific * src/macros.c (log_macro_expand): pass the appropriate time for get_local_timezone_ofs() * src/logmsg.c (log_msg_parse, log_msg_init): -"- * src/affile.c (affile_dd_queue): -"- NEWS * NEWS.hu * modified files: ChangeLog src/affile.c src/logmsg.c src/macros.c src/misc.c src/misc.h 2005-07-07 09:43:49 GMT Balazs Scheidler patch-42 Summary: updated NEWS file and version number in configure.in Revision: syslog-ng--mainline--2.0--patch-42 modified files: ChangeLog NEWS configure.in 2005-07-07 09:33:10 GMT Balazs Scheidler patch-41 Summary: fix match references Revision: syslog-ng--mainline--2.0--patch-41 2005-07-07 Balazs Scheidler * src/templates.c (log_template_compile): fix match references not to include the reference number itself modified files: ChangeLog src/templates.c 2005-07-07 09:15:47 GMT Balazs Scheidler patch-40 Summary: fixed possible memory/fd leak when a filename contains macros Revision: syslog-ng--mainline--2.0--patch-40 2005-07-07 Balazs Scheidler * src/logwriter.c (log_writer_deinit): fixed memory/fd leak, unref self->source as well as destroy it modified files: ChangeLog src/logwriter.c 2005-06-30 08:58:24 GMT Balazs Scheidler patch-39 Summary: fixed use_time_recvd() option handling, documentation updates Revision: syslog-ng--mainline--2.0--patch-39 2005-06-30 Balazs Scheidler * doc/reference/syslog-ng.xml: updated documentation, removed non-existing template timezone option, separate Macros section, added a table on common destination options, added prefixed time related macros without documentation, added DEPRECATED notice to use_time_recvd(), added documentation on ts_format * src/affile.c: use the value for the global use_time_recvd() option when expanding a filename * src/logwriter.c: use the value for the global use_time_recvd() option when expanding the log message modified files: ChangeLog doc/reference/syslog-ng.xml src/affile.c src/affile.h src/logwriter.c src/logwriter.h 2005-06-27 09:27:36 GMT Balazs Scheidler patch-38 Summary: fix file/directory permission handling Revision: syslog-ng--mainline--2.0--patch-38 2005-06-27 Balazs Scheidler * src/affile.c (affile_dw_init): use the file/dir permissions set by the user modified files: ChangeLog src/affile.c 2005-06-27 09:13:38 GMT Balazs Scheidler patch-37 Summary: removed a nested function from affile.c Revision: syslog-ng--mainline--2.0--patch-37 2005-06-27 Balazs Scheidler * src/affile.c (affile_dd_reap_writers): gcc4 does not like nested functions, do not use that modified files: ChangeLog src/affile.c 2005-06-24 07:57:18 GMT Balazs Scheidler patch-36 Summary: added sync() alias for sync_freq() to maintain 1.6.x compatibility Revision: syslog-ng--mainline--2.0--patch-36 2005-06-24 Balazs Scheidler * src/cfg-lex.l: added sync() alias for sync_freq() to maintain compatibility with 1.6.x modified files: ChangeLog src/cfg-lex.l 2005-06-23 08:50:45 GMT Balazs Scheidler patch-35 Summary: added WEEK macro to macro expansion Revision: syslog-ng--mainline--2.0--patch-35 2005-06-23 Balazs Scheidler * src/macros.c, src/macros.h: added support for WEEK, R_WEEK and S_WEEK macros * doc/reference/syslog-ng.xml: added documentation on the WEEK macro NEWS * NEWS.hu * modified files: ChangeLog doc/reference/syslog-ng.xml src/macros.c src/macros.h 2005-06-05 00:00:28 GMT Balazs Scheidler patch-34 Summary: timezone cleanup and fixes, fixed name resolving for socket sources Revision: syslog-ng--mainline--2.0--patch-34 2005-06-05 Balazs Scheidler * doc/reference/syslog-ng.xml: added a section on timezones * src/cfg-grammar.y, src/cfg-lex.l: removed timezone options from templates, removed zone_offset_set variables, a timezone value of -1 indicates unset state instead, (tz_convert) use explicit timezone specification instead, (recv-time-zone, send-time-zone): new keywords to specify default incoming/outgoing timezones * src/affile.c: adapted to the latest log_template_format() changes * src/cfg.c (cfg_tz_convert_value): removed, (cfg_new): initialize sent/recv timezones * src/fdread.c: fixed a bug in recvfrom, the length for the sockaddr structure was incorrectly specified * src/logmsg.c (log_stamp_format): instead of tz_convert use zone_offset, fixed a problem in zone formatting, (log_msg_parse): a value of -1 indicates "unspecified" zone for incoming messages, use get_local_time_zone_ofs() function instead of referencing the timezone variable directly, (log_msg_init): use get_local_time_zone_ofs() * src/logreader.c (log_reader_handle_line): use only set the timezone associated with the incoming message if it has no timezone setting, (log_reader_options_defaults, log_reader_options_init): inherit default value for zone_offset from recv_zone_offset in the global configuration * src/logwriter.c: adapted to log_template_format changes, inherit zone_offset from send_zone_offset * src/macros.c: added STAMP, R_STAMP and S_STAMP macros to represent the message timestamp formatted as specified by the ts_format() global option, (log_macro_expand): added ts_format argument, and the implementation of the STAMP macro * src/misc.c (get_local_timezone_ofs): new function, calculates and returns the current timezone offset in seconds * src/templates.c (log_template_format): added ts_format and zone_offset arguments NEWS * NEWS.hu * modified files: ChangeLog doc/reference/syslog-ng.xml src/affile.c src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/fdread.c src/logmsg.c src/logmsg.h src/logreader.c src/logreader.h src/logwriter.c src/logwriter.h src/macros.c src/macros.h src/misc.c src/misc.h src/templates.c src/templates.h tests/unit/test_msgparse.c tests/unit/test_template.c 2005-06-04 18:23:57 GMT Balazs Scheidler patch-33 Summary: added static linking option to configure, small fixes Revision: syslog-ng--mainline--2.0--patch-33 2005-06-04 Balazs Scheidler * configure.in: added --enable-static-linking option * src/cfg-lex.l: fixed problem that caused keyword recognition problems, words that began with a reserved word were erroneously recognized as the reserved word (user vs usertty) * src/cfg.c: added error checking for file_template and proto_template options * src/logmsg.c (log_msg_init): always set frac_present to TRUE, (log_msg_parse): frac_present is set to FALSE if there was a timestamp which did not contain fractions removed files: .arch-ids/aclocal.m4.id aclocal.m4 modified files: .arch-inventory ChangeLog configure.in src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/logmsg.c src/syslog-ng.h 2005-05-19 06:44:44 GMT Balazs Scheidler patch-32 Summary: configure.in and some warning fixes Revision: syslog-ng--mainline--2.0--patch-32 2005-05-19 Balazs Scheidler * configure.in: removed no-define from AM_INIT_AUTOMAKE as this made PACKAGE and VERSION preprocessor symbols undefined * src/macros.c: fixed uninitialized variable for MSGONLY processing * src/cfg.c: fixed two type-punned pointer references modified files: ChangeLog configure.in src/cfg.c src/macros.c 2005-05-19 06:41:45 GMT Balazs Scheidler patch-31 Summary: treat use_fqdn correctly when getting local hostname Revision: syslog-ng--mainline--2.0--patch-31 2005-05-19 Balazs Scheidler * src/misc.c (getlonghostname): new function, returns the fully qualified domain name for localhost, (resolve_hostname): use the new getlonghostname, if use_fqdn was TRUE NEWS * NEWS.hu * modified files: ChangeLog src/misc.c src/misc.h 2005-04-27 08:09:44 GMT Balazs Scheidler patch-30 Summary: cleaned up tla inventory files Revision: syslog-ng--mainline--2.0--patch-30 new files: .arch-ids/.arch-inventory.id .arch-inventory src/.arch-ids/.arch-inventory.id src/.arch-inventory modified files: ChangeLog {arch}/=tagging-method 2005-04-27 08:06:42 GMT Balazs Scheidler patch-29 Summary: Solaris portability fixes Revision: syslog-ng--mainline--2.0--patch-29 2005-04-27 Balazs Scheidler * configure.in: added ld detection code to discover static linking arguments * tests/unit/test_msgparse.c: added * tests/unit/Makefile.am: instead of noinst, use check prefix to avoid building the testprograms during regular builds modified files: ChangeLog configure.in tests/unit/Makefile.am tests/unit/test_msgparse.c 2005-04-21 08:51:33 GMT Balazs Scheidler patch-28 Summary: fixed a docbug in doc/reference/syslog-ng.xml Revision: syslog-ng--mainline--2.0--patch-28 modified files: ChangeLog doc/reference/syslog-ng.xml 2005-04-16 11:12:27 GMT Balazs Scheidler patch-27 Summary: added dist.conf and added automatic substitution of some dynamic variables in the documentation Revision: syslog-ng--mainline--2.0--patch-27 new files: .arch-ids/dist.conf.in.id dist.conf.in doc/.arch-ids/docvars.xml.in.id doc/docvars.xml.in modified files: ChangeLog configure.in doc/Makefile.am doc/reference/syslog-ng.xml 2005-04-16 10:11:49 GMT Balazs Scheidler patch-26 Summary: removed "reference/" the root path for the reference syslog-ng.html.tar.gz Revision: syslog-ng--mainline--2.0--patch-26 modified files: ChangeLog doc/Makefile.am 2005-04-15 08:10:10 GMT Balazs Scheidler patch-25 Summary: Configure fix to --enable-dynamic-linking Revision: syslog-ng--mainline--2.0--patch-25 2005-04-15 Balazs Scheidler * configure.in: do not enforce static glib if --enable-dynamic-linking was specified modified files: ChangeLog configure.in 2005-04-03 11:24:28 GMT Balazs Scheidler patch-24 Summary: fixed release numbers in NEWS Revision: syslog-ng--mainline--2.0--patch-24 modified files: ChangeLog NEWS 2005-04-03 11:22:50 GMT Balazs Scheidler patch-23 Summary: updated NEWS file, bumped version to 1.9.4 Revision: syslog-ng--mainline--2.0--patch-23 modified files: ChangeLog NEWS configure.in 2005-04-03 11:21:55 GMT Balazs Scheidler patch-22 Summary: improved configure tests Revision: syslog-ng--mainline--2.0--patch-22 2005-04-03 Balazs Scheidler * configure.in: improved configure tests modified files: ChangeLog configure.in 2005-03-04 15:53:33 GMT Balazs Scheidler patch-21 Summary: added template unit tests Revision: syslog-ng--mainline--2.0--patch-21 new files: tests/unit/.arch-ids/test_template.c.id tests/unit/test_template.c modified files: ChangeLog 2005-03-04 15:53:16 GMT Balazs Scheidler patch-20 Summary: fixed reference generation Revision: syslog-ng--mainline--2.0--patch-20 modified files: ChangeLog doc/Makefile.am 2005-02-28 16:45:16 GMT Balazs Scheidler patch-19 Summary: Fixed (filename, logoutput) template compilation Revision: syslog-ng--mainline--2.0--patch-19 2005-02-28 Balazs Scheidler * src/templates.c (log_template_compile, log_template_format): fixed a problem in template comilation as it messed up the formatted string modified files: ChangeLog configure.in src/Makefile.am src/syslog-ng.conf src/templates.c tests/unit/Makefile.am 2005-02-28 08:57:20 GMT Balazs Scheidler patch-18 Summary: Changed g_queue_get_length to g_queue_is_empty as it makes syslog-ng compatible with glib 2.2 Revision: syslog-ng--mainline--2.0--patch-18 2005-02-28 Balazs Scheidler * src/afinter.c: instead of using "!!g_queue_get_length()" use "!g_queue_is_empty()" modified files: ChangeLog src/afinter.c 2005-02-12 23:05:09 GMT Balazs Scheidler patch-17 Summary: Updated documentation (manpages) Revision: syslog-ng--mainline--2.0--patch-17 modified files: ChangeLog configure.in doc/man/syslog-ng.8 doc/man/syslog-ng.conf.5 src/main.c 2005-01-22 00:50:50 GMT Balazs Scheidler patch-16 Summary: removed doc/reference/make.sh from dist as it is not needed Revision: syslog-ng--mainline--2.0--patch-16 modified files: ChangeLog doc/Makefile.am 2005-01-22 00:48:47 GMT Balazs Scheidler patch-15 Summary: added some missing files to tla Revision: syslog-ng--mainline--2.0--patch-15 new files: doc/.arch-ids/Makefile.am.id doc/Makefile.am doc/examples/.arch-ids/=id doc/examples/.arch-ids/syslog-ng.conf.sample.id doc/examples/.arch-ids/syslog-ng.conf.solaris.id doc/examples/syslog-ng.conf.sample doc/examples/syslog-ng.conf.solaris doc/man/.arch-ids/=id doc/man/.arch-ids/syslog-ng.8.id doc/man/.arch-ids/syslog-ng.conf.5.id doc/man/syslog-ng.8 doc/man/syslog-ng.conf.5 doc/reference/.arch-ids/=id doc/reference/.arch-ids/syslog-ng.xml.id doc/reference/.arch-ids/syslog-ng.xsl.id doc/reference/syslog-ng.xml doc/reference/syslog-ng.xsl modified files: ChangeLog new directories: doc/examples doc/examples/.arch-ids doc/man doc/man/.arch-ids doc/reference doc/reference/.arch-ids 2005-01-22 00:47:35 GMT Balazs Scheidler patch-14 Summary: Updated NEWS file, released syslog-ng 1.9.3 Revision: syslog-ng--mainline--2.0--patch-14 2005-01-22 Balazs Scheidler * NEWS: updated with 1.9.3 release information * configure.in: bumped version to 1.9.3 modified files: ChangeLog NEWS configure.in 2005-01-22 00:32:06 GMT Balazs Scheidler patch-13 Summary: added automatic regeneration of the ChangeLog file Revision: syslog-ng--mainline--2.0--patch-13 new files: .arch-ids/ChangeLog.id ChangeLog 2005-01-22 00:27:18 GMT Balazs Scheidler patch-12 Summary: Readded and updated documentation from 1.6 Revision: syslog-ng--mainline--2.0--patch-12 2005-01-22 Balazs Scheidler * src/cfg-lex.l: renamed padding to pad_size to make it compatible with 1.6.x, the '-' character in keywords is taken equivalent to '_', fixed C code indentation to match GNU coding style new files: doc/.arch-ids/=id doc/security/.arch-ids/=id doc/security/.arch-ids/bof-2002-09-27.txt.id doc/security/.arch-ids/dos-2000-11-22.txt.id doc/security/bof-2002-09-27.txt doc/security/dos-2000-11-22.txt modified files: ChangeLog.0 Makefile.am configure.in src/cfg-grammar.y src/cfg-lex.l tests/functional/Makefile.am renamed files: .arch-ids/ChangeLog.id ==> .arch-ids/ChangeLog.0.id ChangeLog ==> ChangeLog.0 new directories: doc doc/.arch-ids doc/security doc/security/.arch-ids 2005-01-16 17:48:51 GMT Balazs Scheidler patch-11 Summary: added some missing files to tla Revision: syslog-ng--mainline--2.0--patch-11 new files: tests/functional/.arch-ids/=id tests/functional/.arch-ids/Makefile.am.id tests/functional/.arch-ids/func_test.py.id tests/functional/Makefile.am tests/functional/func_test.py tests/unit/.arch-ids/Makefile.am.id tests/unit/.arch-ids/test_msgparse.c.id tests/unit/Makefile.am tests/unit/test_msgparse.c new directories: tests/functional tests/functional/.arch-ids 2005-01-16 17:47:43 GMT Balazs Scheidler patch-10 Summary: added copyright info, beginnings of a testsuite, fixed some configure problems Revision: syslog-ng--mainline--2.0--patch-10 2005-01-16 Balazs Scheidler * configure.in: take CFLAGS environment variable into consideration when running configure, link eventlog and glib statically * src/fdread.c, src/fdwrite.c: handle EINTR by repeating the read system call * src/logreader, src/logwriter.c: handle EAGAIN correctly new files: .arch-ids/COPYING.id COPYING tests/.arch-ids/Makefile.am.id tests/Makefile.am removed files: tests/.arch-ids/test_msgparse.c.id tests/Makefile.am tests/test_msgparse.c modified files: README configure.in src/Makefile.am src/fdread.c src/fdwrite.c src/logreader.c src/logwriter.c renamed files: tests/.arch-ids/Makefile.am.id ==> tests/unit/.arch-ids/=id new directories: tests/unit tests/unit/.arch-ids 2005-01-15 19:19:05 GMT Balazs Scheidler patch-9 Summary: Set nonblocking mode for g_accepted sockets Revision: syslog-ng--mainline--2.0--patch-9 2005-01-15 Balazs Scheidler * src/afsocket.c (afsocket_sd_accept): added g_fd_set_nonblock for new sockets modified files: src/afsocket.c 2005-01-09 14:34:31 GMT Balazs Scheidler patch-8 Summary: fixed possible deadlocking on the internal message pipe Revision: syslog-ng--mainline--2.0--patch-8 2005-01-09 Balazs Scheidler * src/logsource.c: new file, separated flow control related functions from logreader * src/logreader.c: LogReader is derived from LogSource * src/afinter.c: substituted the pipe used for internal messages with a GQueue new files: src/.arch-ids/logsource.c.id src/.arch-ids/logsource.h.id src/logsource.c src/logsource.h modified files: src/Makefile.am src/afinter.c src/cfg-grammar.y src/logmsg.c src/logmsg.h src/logreader.c src/logreader.h src/messages.c src/messages.h 2005-01-05 12:02:01 GMT Balazs Scheidler patch-7 Summary: Fixed a couple of Solaris portability problems Revision: syslog-ng--mainline--2.0--patch-7 2005-01-05 Balazs Scheidler * configure.in: added checks for -ldoor, -lsocket, -lnsl and getopt.h * other files: fixed a couple of Solaris specific warnings modified files: configure.in src/cfg.c src/filter.c src/gsockaddr.c src/logmsg.c src/macros.c src/main.c 2005-01-03 21:12:30 GMT Balazs Scheidler patch-6 Summary: Updated NEWS file and released 1.9.2 Revision: syslog-ng--mainline--2.0--patch-6 modified files: NEWS 2004-12-31 14:38:06 GMT Balazs Scheidler patch-5 Summary: added missing macros and brace support in macro expansion Revision: syslog-ng--mainline--2.0--patch-5 2004-12-31 Balazs Scheidler * src/macros.c: added PRI and MSGONLY macros * src/templates.c: added support for braces around macros for $example: "{MSG}" modified files: ChangeLog src/macros.c src/macros.h src/syslog-ng.conf src/templates.c 2004-12-28 23:23:29 GMT Balazs Scheidler patch-4 Summary: fixed couple of bugs Revision: syslog-ng--mainline--2.0--patch-4 2004-12-29 Balazs Scheidler * src/afprog.c (afprogram_dd_init): call setsid before launching child, (afprogram_dd_deinit): deinit & unref self->writer here instead of in afprogram_dd_free, * src/center.c (log_center_queue): do not supply self as user_data pointer to the ack_block callback as that would require adding a reference to self * src/dgroup.c (log_dest_group_queue): do not supply self as user_data pointer to the ack_block callback as that would require adding a reference to self * src/logreader.c: instead of using self->window_size use self->options->window_size so that the window is shared between all LogReaders using the same options, (log_reader_handle_line): add reference to self before supplying it as an argument to the ack_block callback function, (log_reader_msg_ack): unref the supplied logreader argument modified files: ChangeLog src/afprog.c src/center.c src/cfg-lex.l src/dgroup.c src/logreader.c src/logreader.h src/logwriter.c 2004-12-27 23:27:07 GMT Balazs Scheidler patch-3 Summary: Added a lot of copyright header, docstrings, and some fixes Revision: syslog-ng--mainline--2.0--patch-3 2004-12-27 Balazs Scheidler * src/afsocket.c (afsocket_sd_deinit): break circular reference between self->reader and self, (afsocket_sd_notify): do not destroy/unref sender in NC_CLOSE, as afsocket_sd_close_connection already does that, (afsocket_sd_init, afsocket_sd_deinit): removed static, (afsocket_sd_free_instance): renamed from afsocket_sd_free, removed static, created a new afsocket_sd_free function at the same time which is set as the free_fn of AFSocketSourceDriver * src/afunix.c: implemented user/group/perm settings * src/cfg-grammar.y: added support for log-prefix * src/cfg.c: changed default timestamp format to BSD for compatibility * src/filter.c: fixed AND and OR operator evaluation, the operands were not correctly saved at initialization time, thus NULL was referenced at evaluation time * src/logreader.c: added log_prefix support for all log readers * src/logwriter.c: use log_msg_drop instead of a simple log_msg_unref * src/main.c: fixed SIGCHLD handling, loop while waitpid returns > 0, added tzset() call removed files: src/.arch-ids/cfg-grammar.c.id src/.arch-ids/cfg-grammar.h.id src/.arch-ids/cfg-lex.c.id src/cfg-grammar.c src/cfg-grammar.h src/cfg-lex.c modified files: ChangeLog configure.in src/affile.c src/affile.h src/afinet.c src/afinet.h src/afinter.c src/afinter.h src/afprog.c src/afprog.h src/afsocket.c src/afsocket.h src/afstreams.c src/afstreams.h src/afunix.c src/afunix.h src/afuser.c src/afuser.h src/center.c src/center.h src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/children.c src/children.h src/dgroup.c src/dgroup.h src/driver.c src/driver.h src/fdread.c src/fdread.h src/fdwrite.c src/fdwrite.h src/filter.c src/filter.h src/gsockaddr.c src/gsockaddr.h src/logmsg.c src/logmsg.h src/logpipe.c src/logpipe.h src/logreader.c src/logreader.h src/logwriter.c src/logwriter.h src/macros.c src/macros.h src/main.c src/memtrace.h src/messages.c src/messages.h src/misc.c src/misc.h src/sdriver.c src/sgroup.c src/sgroup.h src/syslog-names.c src/syslog-names.h src/syslog-ng.h src/templates.c src/templates.h src/utils.c src/utils.h 2004-12-26 23:24:29 GMT Balazs Scheidler patch-2 Summary: Fixed a lot of memory leaks Revision: syslog-ng--mainline--2.0--patch-2 2004-12-27 Balazs Scheidler * src/affile.c (affile_sd_deinit): make sure to break circular reference between self->reader and self, fixes possible memory leak, (affile_sd_free): call log_drv_free_instance * src/afinter.c (afinter_sd_deinit): break circular reference between self->reader and self * src/afprog.c (afprog_sd_free): added log_drv_free_instance * src/afsocket.c (afsocket_sd_deinit): break circular reference between self->reader and self, (afsocket_sd_free): added log_drv_free_instance, (afsocket_dd_free): -"- * src/afuser.c (afuser_dd_queue): free queued message, (afuser_dd_free): added log_drv_free_instance * src/cfg-grammar.y: unref log driver after appending to avoid memory leaks * src/cfg.c (cfg_reload_config): fixed possible memory leak when cfg_init fails (free persist), (persist_config_free): added missing free for hashtable * src/dgroup.c (log_dest_group_queue): make sure each driver gets its own reference to msg as each will free it on its own, also added an explicit unref at the end of the function (log_dest_group_new): added missing call to log_pipe_init_instance * src/gsockaddr.c: removed all low-level g_message invocation, errors should be reported by the caller * src/logpipe.c: added assertions to _ref and _unref * src/main.c (main_loop_run): added a missing g_main_loop_unref to avoid memory leaks, (main): call msg_syslog_started at the end of initialization to force messages into the system log * src/messages.c (msg_syslog_started): new function to indicate that initialization is finished, messages will be written to stderr instead of the internal() source if syslog is not yet started to let the administrator see important failure messages, (msg_deinit): free the event log context, only close the error pipe if it was really opened modified files: src/affile.c src/afinter.c src/afprog.c src/afsocket.c src/afstreams.c src/afuser.c src/cfg-grammar.c src/cfg-grammar.h src/cfg-grammar.y src/cfg.c src/dgroup.c src/gsockaddr.c src/logpipe.c src/main.c src/messages.c src/messages.h tests/Makefile.am 2004-12-26 20:38:30 GMT Balazs Scheidler patch-1 Summary: Removed CVS files Revision: syslog-ng--mainline--2.0--patch-1 2004-12-26 20:38:05 GMT Balazs Scheidler base-0 Summary: initial import Revision: syslog-ng--mainline--2.0--base-0 (automatically generated log message) new files: AUTHORS ChangeLog Makefile.am NEWS README aclocal.m4 autogen.sh configure.in src/Makefile.am src/affile.c src/affile.h src/afinet.c src/afinet.h src/afinter.c src/afinter.h src/afprog.c src/afprog.h src/afsocket.c src/afsocket.h src/afstreams.c src/afstreams.h src/afunix.c src/afunix.h src/afuser.c src/afuser.h src/center.c src/center.h src/cfg-grammar.c src/cfg-grammar.h src/cfg-grammar.y src/cfg-lex.c src/cfg-lex.l src/cfg.c src/cfg.h src/children.c src/children.h src/dgroup.c src/dgroup.h src/driver.c src/driver.h src/fdread.c src/fdread.h src/fdwrite.c src/fdwrite.h src/filter.c src/filter.h src/gsockaddr.c src/gsockaddr.h src/logmsg.c src/logmsg.h src/logpipe.c src/logpipe.h src/logreader.c src/logreader.h src/logwriter.c src/logwriter.h src/macros.c src/macros.h src/main.c src/memtrace.c src/memtrace.h src/messages.c src/messages.h src/misc.c src/misc.h src/sdriver.c src/sgroup.c src/sgroup.h src/syslog-names.c src/syslog-names.h src/syslog-ng.conf src/syslog-ng.h src/templates.c src/templates.h src/todo src/utils.c src/utils.h tests/Makefile.am tests/test_msgparse.c syslog-ng-syslog-ng-4.4.0/doc/ChangeLog.2000066400000000000000000002517311450431004300200430ustar00rootroot00000000000000# do not edit -- automatically generated by arch changelog # arch-tag: automatic-ChangeLog--devel@balabit.hu--other-1/syslog-ng--mainline--2.0 # 2007-04-06 09:59:15 GMT Balazs Scheidler patch-149 Summary: use stat instead of seek to determine file size Revision: syslog-ng--mainline--2.0--patch-149 * src/logreader.c (log_reader_fd_check): remove lseek based file size determination and use lseek instead, it is not glibc that is buggy, and although gdb reports invalid contents of the stat results, the program sees them correctly modified files: ChangeLog src/logreader.c 2007-04-06 09:08:49 GMT Balazs Scheidler patch-148 Summary: added support for logrotation in file sources Revision: syslog-ng--mainline--2.0--patch-148 2007-04-06 Balazs Scheidler * src/affile.c (affile_sd_open_file): new function, contains the file open code for the source driver, (affile_sd_notify): new function, registered as the notification handler for an affile source, for NC_FILE_MOVED notifications construct a new the log reader and drop the old one, (affile_sd_init): use affile_sd_open_file, (affile_sd_new): register notification handler, tell our LogReader the filename that we are following modified files: ChangeLog src/affile.c src/afsocket.c src/logpipe.h src/logreader.c src/logreader.h src/messages.h 2007-04-05 11:27:02 GMT Balazs Scheidler patch-147 Summary: fixed expansion of utf-8 characters in templates Revision: syslog-ng--mainline--2.0--patch-147 * src/macros.c (result_append): use guchar as the type of the argument instead of gchar * tests/unit/test_templates.c: use utf8 sequences in the message string to ensure that syslog-ng handles them properly modified files: ChangeLog src/macros.c tests/unit/test_template.c 2007-04-04 14:44:29 GMT Balazs Scheidler patch-146 Summary: fixed numeric localport/destport specification Revision: syslog-ng--mainline--2.0--patch-146 * src/afinet.c (afinet_set_port, afinet_sd_set_localport, afinet_dd_set_localport, afinet_dd_set_destport): removed port argument, always use 'service' and check if it's numeric * src/cfg-grammar.y: follow afinet changes modified files: ChangeLog src/afinet.c src/afinet.h src/cfg-grammar.y 2007-04-02 06:53:54 GMT Balazs Scheidler patch-145 Summary: grammar fixes for localport/port/destport parsing options Revision: syslog-ng--mainline--2.0--patch-145 * src/cfg-grammar.y: fixed grammar to parse port related options correctly modified files: ChangeLog src/cfg-grammar.y 2007-03-26 12:28:53 GMT Balazs Scheidler patch-144 Summary: preparations for 2.0.3 release Revision: syslog-ng--mainline--2.0--patch-144 modified files: ChangeLog NEWS VERSION 2007-03-26 12:28:31 GMT Balazs Scheidler patch-143 Summary: increased the minimum value for log_fifo_size to 1000 Revision: syslog-ng--mainline--2.0--patch-143 modified files: ChangeLog src/cfg.c src/logsource.h src/logwriter.c 2007-03-21 16:36:01 GMT Balazs Scheidler patch-142 Summary: fixed dns_cache_hosts() typo in documentation Revision: syslog-ng--mainline--2.0--patch-142 modified files: ChangeLog doc/reference/syslog-ng.xml 2007-03-19 17:41:46 GMT Balazs Scheidler patch-141 Summary: some more message clarification Revision: syslog-ng--mainline--2.0--patch-141 modified files: ChangeLog src/main.c 2007-03-19 17:35:37 GMT Balazs Scheidler patch-140 Summary: clarified internal message severities Revision: syslog-ng--mainline--2.0--patch-140 * src/*.c: clarified the severity value of some log messages generated by syslog-ng modified files: ChangeLog src/affile.c src/cfg-lex.l src/macros.c src/messages.h 2007-03-05 11:33:09 GMT Balazs Scheidler patch-139 Summary: clarified message priorities Revision: syslog-ng--mainline--2.0--patch-139 modified files: ChangeLog src/affile.c src/afinet.c src/cfg.c src/logwriter.c src/stats.c 2007-03-04 11:03:22 GMT Balazs Scheidler patch-138 Summary: added support for remembering input file positions Revision: syslog-ng--mainline--2.0--patch-138 * configure.in: added LARGEFILE_SOURCE & FILE_OFFSET_BITS to CPPFLAGS, export localstatedir to syslog-ng, * src/affile.c (affile_sd_format_persist_name): new function, formats the persistent name associated with the file source, (affile_sd_init): check if the current file position is available and set it if it is, (affile_sd_deinit): save the current file position, * src/afsocket.c (afsocket_sd_kill_connection_list): new function, frees a connection list, (afsocket_sd_deinit): fixed a possible SIGSEGV, a GList was freed as an AFSocketSourceDriver, I wonder how this got unnoticed so far, * src/cfg.c (persist_config_add_entry): new function, (persist_config_add): use the new add_entry function, (persist_config_add_survivor): new function, adds a surviving entry, (PersistentConfig): added saving/loading persistent config entries, * src/logreader.c (log_reader_watch_new): don't seek the file to the end-of-file now as proper file position is recovered, (log_reader_set_pos, log_reader_get_pos): new functions * src/main.c (main): added --ignore-persistent option, use a persistent configuration object around stop/start to save/restore file position information modified files: ChangeLog configure.in src/affile.c src/afsocket.c src/cfg.c src/cfg.h src/logreader.c src/logreader.h src/main.c src/syslog-ng.h 2007-03-03 14:01:24 GMT Balazs Scheidler patch-137 Summary: tightened LogMessage struct, added support for more than 9 match groups Revision: syslog-ng--mainline--2.0--patch-137 * src/logmsg.h (LogMessage): structure tightened a bit, avoid double-referencing various message-parts by inlining GString declarations, instead of allocating them at runtime to be more cache friendly, use 8 bit values for ref_cnt, flags, pri; re_matches is allocated at runtime to allow more matches * src/filter.c (filter_re_eval): dynamically allocate the msg->re_matches array, follow LogMessage changes * src/templates.c (log_template_compile): support ${} syntax for regex match replacements to allow more than 9 matches * src/afuser.c, src/logreader.c, src/logwriter.c, src/sgroup.c, src/test_msgparse.c, src/test_template.c: follow LogMessage changes modified files: ChangeLog src/afuser.c src/filter.c src/logmsg.c src/logmsg.h src/logreader.c src/logwriter.c src/macros.c src/sgroup.c src/templates.c tests/unit/test_msgparse.c tests/unit/test_template.c 2007-02-28 09:21:01 GMT Balazs Scheidler patch-136 Summary: clarified SIGTERM message Revision: syslog-ng--mainline--2.0--patch-136 * src/main.c (main_loop_run): clarified message about the reception of a SIGTERM or SIGINT signal modified files: ChangeLog src/main.c 2007-02-28 09:19:28 GMT Balazs Scheidler patch-135 Summary: updated copyright strings Revision: syslog-ng--mainline--2.0--patch-135 modified files: ChangeLog src/affile.c src/affile.h src/afinet.c src/afinet.h src/afinter.c src/afinter.h src/afprog.c src/afprog.h src/afsocket.c src/afsocket.h src/afstreams.c src/afstreams.h src/afunix.c src/afunix.h src/afuser.c src/afuser.h src/center.c src/center.h src/cfg-lex.l src/cfg.c src/cfg.h src/children.c src/children.h src/dgroup.c src/dgroup.h src/dnscache.c src/dnscache.h src/driver.c src/driver.h src/fdread.c src/fdread.h src/fdwrite.c src/fdwrite.h src/filter.c src/filter.h src/gsockaddr.c src/gsockaddr.h src/logmsg.c src/logmsg.h src/logpipe.c src/logpipe.h src/logreader.c src/logreader.h src/logsource.c src/logsource.h src/logwriter.c src/logwriter.h src/macros.c src/macros.h src/main.c src/memtrace.c src/memtrace.h src/messages.c src/messages.h src/misc.c src/misc.h src/sgroup.c src/sgroup.h src/stats.c src/stats.h src/syslog-names.c src/syslog-names.h src/syslog-ng.h src/templates.c src/templates.h src/utils.c src/utils.h 2007-02-28 09:19:00 GMT Balazs Scheidler patch-134 Summary: implemented TCP wrapper support Revision: syslog-ng--mainline--2.0--patch-134 * configure.in: added tests for libwrap * src/afsocket.c: added support for libwrap access control modified files: ChangeLog configure.in src/afsocket.c 2007-02-12 09:09:08 GMT Balazs Scheidler patch-133 Summary: added endutent() to usertty destination Revision: syslog-ng--mainline--2.0--patch-133 * src/afuser.c (afuser_dd_queue): added missing endutent call() modified files: ChangeLog src/afuser.c 2007-02-12 09:02:37 GMT Balazs Scheidler patch-132 Summary: removed 1024 byte limitation on internal messages Revision: syslog-ng--mainline--2.0--patch-132 * src/messages.c (msg_send_internal_message): use a dynamically allocated buffer instead of a buffer with a fixed size on the stack modified files: ChangeLog src/messages.c 2007-02-12 09:01:43 GMT Balazs Scheidler patch-131 Summary: added testcases for 2007 DST changes Revision: syslog-ng--mainline--2.0--patch-131 * tests/unit/test_zone.c (main): added testcases for 2007 DST changes in the USA modified files: ChangeLog tests/unit/test_zone.c 2007-02-03 17:24:40 GMT Balazs Scheidler patch-130 Summary: added dist.conf to dist Revision: syslog-ng--mainline--2.0--patch-130 modified files: ChangeLog Makefile.am configure.in 2007-02-03 17:21:21 GMT Balazs Scheidler patch-129 Summary: further portability fixes Revision: syslog-ng--mainline--2.0--patch-129 * configure.in: added check for -lresolv modified files: ChangeLog configure.in 2007-02-03 17:16:17 GMT Balazs Scheidler patch-128 Summary: portability fixes for platforms without IPv6 support Revision: syslog-ng--mainline--2.0--patch-128 * configure.in: added checks for struct sockaddr_storage * src/cfg-grammar.y: make sure it compiles even if AF_INET6 is not defined * src/cfg-lex.l: don't define udp6/tcp6 keywords if ENABLE_IPV6 is not defined * src/dnscache.c: added conditional blocks for IPv6 related code * src/misc.c (resolve_hostname): -"- * src/fdread.c (fd_do_read): use plain "struct sockaddr" if struct sockaddr_storage is not defined modified files: ChangeLog configure.in src/cfg-grammar.y src/cfg-lex.l src/dnscache.c src/fdread.c src/misc.c 2007-02-03 16:39:08 GMT Balazs Scheidler patch-127 Summary: implemented spoof-source support for both ipv4/ipv6 Revision: syslog-ng--mainline--2.0--patch-127 * configure.in: added --with-libnet and --enable-spoof-source options * src/afinet.c (afinet_dd_set_spoof_source): new function, called from the parser to enable spoof-source, (afinet_dd_init): new function, (afinet_dd_construct_ipv4_packet): -"-, (afinet_dd_construct_ipv6_packet): -"-, (afinet_dd_queue): -"-, (affile_dd_new): register new init/queue methods, * src/sgroup.h, src/dgroup.h: renamed ref/unref functions for consistency * src/cfg-lex.l, src/cfg-grammar.y: added spoof-source option * src/logwriter.c (log_writer_format_log): removed static as it is directly used by spoof-source to format messages modified files: ChangeLog README configure.in src/afinet.c src/afinet.h src/afsocket.h src/center.c src/cfg-grammar.y src/cfg-lex.l src/dgroup.h src/logwriter.c src/logwriter.h src/sgroup.h 2007-01-30 13:08:22 GMT Balazs Scheidler patch-126 Summary: added netinet/in.h to afinet.c Revision: syslog-ng--mainline--2.0--patch-126 * src/afinet.c: added inclusion of as it caused problems on HP-UX modified files: ChangeLog src/afinet.c 2007-01-29 08:56:55 GMT Balazs Scheidler patch-125 Summary: added check for getutent in configure Revision: syslog-ng--mainline--2.0--patch-125 * configure.in: added getutent() check modified files: ChangeLog configure.in src/afuser.c 2007-01-29 08:49:55 GMT Balazs Scheidler patch-124 Summary: integrated AIX packaging fixes from dev-folti Revision: syslog-ng--mainline--2.0--patch-124 Patches applied: * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-2 Fixed: AIX5.2 packaging support. (fixes: #10375) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-3 Fixes: added libevtlog-dev build dependency. (fixes: #10375) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-5 Fixed: RPM packaging for 2.0. (fixes: #nobug) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-7 Refresh: Fixed: AIX5.2 packaging support. (fixes: #10375) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-8 Refresh: Fixes: added libevtlog-dev build dependency. (fixes: #10375) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-9 Refresh: Fixed: RPM packaging for 2.0. (fixes: #nobug) * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-10 Fixed: removed duplicated install commanands from spec file. (fixes #nobug) new files: contrib/aix-packaging/.arch-ids/=id contrib/aix-packaging/.arch-ids/syslog-ng.conf.id contrib/aix-packaging/syslog-ng.conf modified files: ChangeLog contrib/Makefile.am syslog-ng.spec.bb.in new directories: contrib/aix-packaging contrib/aix-packaging/.arch-ids new patches: devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-2 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-3 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-5 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-7 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-8 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-9 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-10 2007-01-29 08:48:19 GMT Balazs Scheidler patch-123 Summary: fixed possible crash in usertty() driver Revision: syslog-ng--mainline--2.0--patch-123 * src/afuser.c (afuser_dd_queue): don't ack the message if flow control was off (fixes possible crash reported by Bryan Henderson) modified files: ChangeLog src/afuser.c 2007-01-26 09:23:49 GMT Pal Tamas patch-122 Summary: Synced to test Revision: syslog-ng--mainline--2.0--patch-122 modified files: ChangeLog 2007-01-26 07:59:36 GMT Balazs Scheidler patch-121 Summary: missed version change Revision: syslog-ng--mainline--2.0--patch-121 modified files: ChangeLog VERSION 2007-01-26 07:58:21 GMT Balazs Scheidler patch-120 Summary: preparations for 2.0.2 Revision: syslog-ng--mainline--2.0--patch-120 modified files: ChangeLog NEWS 2007-01-23 13:44:15 GMT Balazs Scheidler patch-119 Summary: fixed handling utmp entries where a full path is included as tty name Revision: syslog-ng--mainline--2.0--patch-119 * src/afuser.c (afuser_dd_queue): check if ut->ut_line starts with a '/' and use it directly if it does, otherwise prepend '/dev/' as before. modified files: ChangeLog src/afuser.c 2007-01-19 21:00:06 GMT Balazs Scheidler patch-118 Summary: fixed trailing \0 and \n characters in messages received on dgram transport Revision: syslog-ng--mainline--2.0--patch-118 * src/logmsg.c (log_msg_parse): remove trailing \n and \0 characters which are often added to the end of incoming datagrams modified files: ChangeLog src/logmsg.c 2007-01-07 16:51:40 GMT Balazs Scheidler patch-117 Summary: fixed parsing group information when not enclosed in quotes Revision: syslog-ng--mainline--2.0--patch-117 * src/cfg-grammar.y (string_or_number): use non-terminal string instead of STRING to support non-quoted group specification modified files: ChangeLog src/cfg-grammar.y 2007-01-07 16:46:34 GMT Balazs Scheidler patch-116 Summary: fixed IPv6 related portability problem in DNS cache Revision: syslog-ng--mainline--2.0--patch-116 * src/dnscache.c (dns_cache_key_hash): don't use the unportable s6_addr32 member in struct in6_addr, use an explicit cast instead modified files: ChangeLog src/dnscache.c 2006-12-22 10:07:57 GMT Balazs Scheidler patch-115 Summary: added tcp-keep-alive keyword for compatibility Revision: syslog-ng--mainline--2.0--patch-115 modified files: ChangeLog doc/reference/syslog-ng.xml src/cfg-lex.l 2006-12-22 10:06:01 GMT Balazs Scheidler patch-114 Summary: updated documentation with so_keepalive option Revision: syslog-ng--mainline--2.0--patch-114 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-12-22 10:01:22 GMT Balazs Scheidler patch-113 Summary: added so_keepalive support Revision: syslog-ng--mainline--2.0--patch-113 * src/cfg-grammar.y: added KW_SO_KEEPALIVE keyword, (socket_option): added KW_SO_KEEPALIVE rule * src/afsocket.h (SocketOptions): added keepalive member, * src/afsocket.c (afsocket_setup_socket): set SO_KEEPALIVE socket option based on the keepalive parameter modified files: ChangeLog src/afsocket.c src/afsocket.h src/cfg-grammar.y src/cfg-lex.l 2006-12-21 08:48:42 GMT Balazs Scheidler patch-112 Summary: fixed XML syntax error in refguide Revision: syslog-ng--mainline--2.0--patch-112 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-12-21 08:46:42 GMT Balazs Scheidler patch-111 Summary: bumped version to 2.0.1 Revision: syslog-ng--mainline--2.0--patch-111 modified files: ChangeLog VERSION 2006-12-21 08:45:35 GMT Balazs Scheidler patch-110 Summary: updated documentation with new dns cache options Revision: syslog-ng--mainline--2.0--patch-110 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-12-21 08:39:23 GMT Balazs Scheidler patch-109 Summary: NEWS preparations for syslog-ng 2.0.1 Revision: syslog-ng--mainline--2.0--patch-109 modified files: ChangeLog NEWS 2006-12-21 08:31:08 GMT Balazs Scheidler patch-108 Summary: obsoleted remove_if_older option in favour of overwrite_if_older Revision: syslog-ng--mainline--2.0--patch-108 * src/affile.{c,h}: renamed remove_if_older references to overwrite_if_older * src/cfg-lex.l, src/cfg-grammar.y: -"- * doc/reference/syslog-ng.xml: added overwrite_if_older documentation, added note about obsoleted remove_if_older() modified files: ChangeLog doc/reference/syslog-ng.xml src/affile.c src/affile.h src/cfg-grammar.y src/cfg-lex.l 2006-12-21 08:21:49 GMT Balazs Scheidler patch-107 Summary: documentation updates on remove_if_older() Revision: syslog-ng--mainline--2.0--patch-107 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-12-18 09:01:46 GMT Balazs Scheidler patch-106 Summary: added include misc.h to afstreams.c Revision: syslog-ng--mainline--2.0--patch-106 * src/afstreams.c: added #include "misc.h" modified files: ChangeLog src/afstreams.c 2006-12-11 09:42:40 GMT Balazs Scheidler patch-105 Summary: removed bogus timezone error message for correct timezone values Revision: syslog-ng--mainline--2.0--patch-105 * src/cfg.c (cfg_timezone_value): readded erroneously removed return statement which caused an error message for all timezone values modified files: ChangeLog src/cfg.c 2006-12-08 08:40:35 GMT Balazs Scheidler patch-104 Summary: removed 12 hour limitation from timezone offsets Revision: syslog-ng--mainline--2.0--patch-104 * src/cfg.c (cfg_timezone_value): removed 12 hours limitation as offsets may well exceed that value (maximum is 24 hours) * doc/reference/syslog-ng.xml: removed non-existing timezone() option modified files: ChangeLog doc/reference/syslog-ng.xml src/cfg.c 2006-12-02 22:20:39 GMT Balazs Scheidler patch-103 Summary: added minimum version checking for glib/eventlog, also fixed a portability problem with non-gcc compilers in configure Revision: syslog-ng--mainline--2.0--patch-103 modified files: ChangeLog configure.in 2006-11-30 09:49:22 GMT Balazs Scheidler patch-102 Summary: fixed a typo in the documentation, added sys/socket.h to dnscache.c Revision: syslog-ng--mainline--2.0--patch-102 modified files: ChangeLog doc/reference/syslog-ng.xml src/dnscache.c 2006-11-27 10:55:47 GMT Balazs Scheidler patch-101 Summary: fixed the previously messed up commit Revision: syslog-ng--mainline--2.0--patch-101 modified files: ChangeLog src/logmsg.c 2006-11-27 10:52:40 GMT Balazs Scheidler patch-100 Summary: fixed a compilation problem in logmsg.c Revision: syslog-ng--mainline--2.0--patch-100 * src/logmsg.c (log_msg_parse): fixed a bad assignment modified files: ChangeLog src/cfg-grammar.y 2006-11-16 14:15:50 GMT Balazs Scheidler patch-99 Summary: timezone offset calculation fix Revision: syslog-ng--mainline--2.0--patch-99 * src/logmsg.c (log_stamp_format): don't use the absolute value of timezone offset, (log_msg_parse): initialize tm.tm_gmtoff using a call to localtime() instead of using memset(), fixed tv_sec calculation as it was not really UTC which it should've been. * tests/unit/test_msgparse.c: fixed time parsing testcases modified files: ChangeLog src/logmsg.c tests/unit/test_msgparse.c 2006-11-16 13:11:04 GMT Balazs Scheidler patch-98 Summary: fixed GLib static link configure test to work with non-gcc compilers Revision: syslog-ng--mainline--2.0--patch-98 * configure.in: fixed GLib static link configure test to work with non-gcc compilers modified files: ChangeLog configure.in 2006-11-08 14:18:14 GMT Balazs Scheidler patch-97 Summary: fixed up dnscache unit test program Revision: syslog-ng--mainline--2.0--patch-97 modified files: ChangeLog tests/unit/test_dnscache.c 2006-11-08 14:16:23 GMT Balazs Scheidler patch-96 Summary: implemented DNS cache and custom hosts file support Revision: syslog-ng--mainline--2.0--patch-96 * src/cfg-grammar.y: added KW_PERSIST_ONLY, KW_DNS_CACHE_HOSTS keywords, dnsmode rule, removed tripleoption and related options, added * src/cfg-lex.l: added dnscache specific new keywords, * src/cfg.c (cfg_init): added a call to dns_cache_set_params, (cfg_free): free dns_cache_hosts, * src/main.c (main): call dns_cache_init() and dns_cache_destroy() * src/misc.c (resolve_hostname): added DNS cache and persistent-only resolution support * src/sgroup.c (log_source_group_init): save dns cache params, (log_source_group_queue): pass use_dns_cache param to resolve_hostname * src/dnscache.{c,h}: new files new files: src/.arch-ids/dnscache.c.id src/.arch-ids/dnscache.h.id src/dnscache.c src/dnscache.h tests/unit/.arch-ids/test_dnscache.c.id tests/unit/test_dnscache.c modified files: ChangeLog src/Makefile.am src/affile.h src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/main.c src/misc.c src/misc.h src/sgroup.c src/sgroup.h tests/unit/Makefile.am 2006-11-08 14:11:00 GMT Balazs Scheidler patch-95 Summary: don't fail at startup if network connection is down Revision: syslog-ng--mainline--2.0--patch-95 * src/afsocket.c (afsocket_open_socket): added an error message if socket creation failed, (afsocket_dd_start_reconnect_timer): new function, deregisters and starts a new reconnect timer, (afsocket_dd_connected): use afsocket_dd_start_reconnect_timer, (afsocket_dd_start_connect): renamed from afsocket_dd_reconnect, removed explicit timer registration, (afsocket_dd_reconnect): new function, calls _start_connect and registers the reconnect timer if that fails, (afsocket_dd_init): afsocket_dd_reconnect does not return a value now modified files: ChangeLog src/afsocket.c 2006-11-08 10:10:37 GMT Balazs Scheidler patch-94 Summary: increased listener source priorities Revision: syslog-ng--mainline--2.0--patch-94 * src/syslog-ng.h (LOG_PRIORITY_LISTEN): increased priority to match LOG_PRIORITY_READER as otherwise a continous input flow can starve accept() modified files: ChangeLog src/syslog-ng.h 2006-11-08 09:53:59 GMT Balazs Scheidler patch-93 Summary: set the pipe for program destinations to nonlbocking mode Revision: syslog-ng--mainline--2.0--patch-93 * src/afprog.c (afprogram_dd_init): set the pipe fd to nonblocking mode to avoid a possible hang modified files: ChangeLog src/afprog.c 2006-10-28 16:07:36 GMT Balazs Scheidler patch-92 Summary: implemented the missing remove_if_older option Revision: syslog-ng--mainline--2.0--patch-92 * src/affile.c (affile_dw_init): check if the file exists and is older than the value for remove_if_older, if it is unlink it, (affile_dd_set_remove_if_older): new function to set remove_if_older value, * src/cfg-grammar.y (dest_affile_option): added KW_REMOVE_IF_OLDER rule * src/cfg-lex.l: added keyword for KW_REMOVE_IF_OLDER modified files: ChangeLog src/affile.c src/affile.h src/cfg-grammar.y src/cfg-lex.l 2006-10-28 15:37:15 GMT Balazs Scheidler patch-91 Summary: preparations for 2.0.0 Revision: syslog-ng--mainline--2.0--patch-91 modified files: ChangeLog NEWS VERSION 2006-10-28 07:24:49 GMT Balazs Scheidler patch-90 Summary: fixed process restarting and some other minor fixes Revision: syslog-ng--mainline--2.0--patch-90 * src/afprog.c (afprogram_dd_exit): check that the current pid is equal to the process that was exited, as the EPIPE handling code might have already done our job, (afprogram_dd_init): don't leave the read side of the pipe twice with the process, removed a call to g_fd_set_cloexec() as it's not needed and was too late anyway, should've been before fork, * src/gsockaddr.c (g_sockaddr_unix_format): the kernel sometimes returns only an address family for unix socket names, and we printed a lot of garbage instead of "anonymous" in this case * src/logwriter.c (log_writer_broken): move log_pipe_deinit() before log_pipe_notify(), this was changed in rc3 with a changelog that it should not matter, however it does matter :P as it might have left the writer in an unpolled state modified files: ChangeLog src/afprog.c src/gsockaddr.c src/logwriter.c 2006-10-27 15:15:30 GMT Balazs Scheidler patch-89 Summary: integrated solaris build scripts from dev-folti (fixes: #10358) Revision: syslog-ng--mainline--2.0--patch-89 Patches applied: * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--base-0 tag of devel@balabit.hu--other-1/syslog-ng--mainline--2.0--patch-87 * devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-1 Added support for solaris 8/9 and rhel 3/4 packaging. (fixes: #10358) new files: .arch-ids/syslog-ng.spec.bb.in.id solbuild/.arch-ids/=id solbuild/.arch-ids/Makefile.am.id solbuild/.arch-ids/admin.id solbuild/.arch-ids/depend.id solbuild/.arch-ids/pkginfo.in.id solbuild/.arch-ids/pkgmaker.sh.id solbuild/.arch-ids/prototype-maker.sh.id solbuild/.arch-ids/rules.conf.id solbuild/.arch-ids/rules.id solbuild/.arch-ids/space.id solbuild/.arch-ids/syslog-ng.init.d.id solbuild/Makefile.am solbuild/admin solbuild/depend solbuild/pkginfo.in solbuild/pkgmaker.sh solbuild/prototype-maker.sh solbuild/rules solbuild/rules.conf solbuild/space solbuild/syslog-ng.init.d syslog-ng.spec.bb.in modified files: ChangeLog Makefile.am configure.in new directories: solbuild solbuild/.arch-ids new patches: devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--base-0 devel@balabit.hu--other-1/syslog-ng--dev-folti--2.0--patch-1 2006-10-27 15:10:36 GMT Balazs Scheidler patch-88 Summary: fixed some compilation warnings under gcc4 Revision: syslog-ng--mainline--2.0--patch-88 * src/affile.c (affile_dd_init): added some casts to suppress some warnings * src/gsockaddr.c (g_accept): use socklen_t instead of int as a second argument to accept modified files: ChangeLog src/affile.c src/gsockaddr.c 2006-10-25 08:36:58 GMT Balazs Scheidler patch-87 Summary: documentation updates merged from the tech-writer team Revision: syslog-ng--mainline--2.0--patch-87 Patches applied: * devel@balabit.hu--other-1/syslog-ng--documentation--2.0--patch-1 Updated reference guide, still needs work, see FIXMEs * devel@balabit.hu--other-1/syslog-ng--documentation--2.0--patch-2 Updates and fixes from Bazsi modified files: ChangeLog doc/reference/syslog-ng.xml new patches: devel@balabit.hu--other-1/syslog-ng--documentation--2.0--patch-1 devel@balabit.hu--other-1/syslog-ng--documentation--2.0--patch-2 2006-10-24 11:37:43 GMT Balazs Scheidler patch-86 Summary: updated VERSION number Revision: syslog-ng--mainline--2.0--patch-86 modified files: ChangeLog VERSION 2006-10-24 11:37:16 GMT Balazs Scheidler patch-85 Summary: preparations for 2.0rc4 Revision: syslog-ng--mainline--2.0--patch-85 modified files: ChangeLog NEWS 2006-10-21 20:41:41 GMT Balazs Scheidler patch-84 Summary: fixed possible NULL deref on destination connection broken, fixed EOF detection Revision: syslog-ng--mainline--2.0--patch-84 2006-10-21 Balazs Scheidler * src/logwriter.c (log_writer_fd_prepare): when EOF detection is enabled specify G_IO_IN and G_IO_HUP in addition to normal flags, (log_writer_fd_dispatch): input on the destination fd is taken as EOF, (log_writer_broken): _deinit is moved after the call to notify, should not matter at all however the reference counting depends on the fact that log_pipe_notify() will not be called after _deinit finishes, in this specific case it would not really matter, (log_writer_deinit): remove unref of self->control, (log_writer_new): self->control is a borrowed reference, don't increase refcount modified files: ChangeLog src/logwriter.c 2006-10-06 11:49:45 GMT Balazs Scheidler patch-83 Summary: added syslog-multicast client to contrib Revision: syslog-ng--mainline--2.0--patch-83 new files: contrib/.arch-ids/syslog-mc.id contrib/syslog-mc modified files: ChangeLog contrib/README 2006-09-14 12:35:49 GMT Balazs Scheidler patch-82 Summary: preparations for 2.0rc3 Revision: syslog-ng--mainline--2.0--patch-82 modified files: ChangeLog NEWS VERSION 2006-09-14 12:34:44 GMT Balazs Scheidler patch-81 Summary: fixed a possible SEGFAULT caused by one of the leak fixes, when output templates() are used Revision: syslog-ng--mainline--2.0--patch-81 2006-09-14 Balazs Scheidler * src/logwriter.c (log_writer_options_init): save options->template before calling log_writer_options_destroy and restore it afterwards as that is never initialized based on the configuration modified files: ChangeLog src/logwriter.c tests/functional/func_test.py 2006-09-11 10:10:09 GMT Balazs Scheidler patch-80 Summary: NEWS update Revision: syslog-ng--mainline--2.0--patch-80 modified files: ChangeLog NEWS 2006-09-11 10:06:07 GMT Balazs Scheidler patch-79 Summary: preparations for 2.0rc2 release Revision: syslog-ng--mainline--2.0--patch-79 modified files: ChangeLog VERSION 2006-09-11 10:05:05 GMT Balazs Scheidler patch-78 Summary: fixed name resolution for unix domain socket peers Revision: syslog-ng--mainline--2.0--patch-78 2006-09-11 Balazs Scheidler * src/misc.c (resolve_hostname): for UNIX domain socket peers don't try to resolve the sender address, fixes a possible abort, introduced by patch-76 modified files: ChangeLog src/misc.c tests/functional/func_test.py 2006-09-11 09:47:54 GMT Balazs Scheidler patch-77 Summary: added stats counter orphaning to fix "duplicate stats counter message" for program destinations Revision: syslog-ng--mainline--2.0--patch-77 2006-09-11 Balazs Scheidler * src/logwriter.c (log_writer_deinit): call stats_orphan_counter, (log_writer_free): removed stats_unregister_counter, fixed a memory leak by freeing all elements in the logwriter queue, (log_writer_options_init): fixed a possible memory leak by freeing the option structure contents before overwriting it with new values, * src/main.c (main_loop_run): added stats_cleanup_orphans() call * src/stats.c (stats_counter_free): new function, (stats_register_counter): added special case for orphaned counters, save "shared" value in the StatsCounter structure, (stats_orphan_counter): new function, orphanes a counter that can thus be reused by a new configuration upon the receiption of a HUP signal, (stats_unregister_counter): use stats_counter_free instead of open-coding it, (stats_cleanup_orphans): free all orphaned counters, to be called after a reload modified files: ChangeLog src/logmsg.c src/logwriter.c src/main.c src/stats.c src/stats.h 2006-09-11 09:41:42 GMT Balazs Scheidler patch-76 Summary: fixed IPv6 name resolution Revision: syslog-ng--mainline--2.0--patch-76 2006-09-11 Balazs Scheidler * src/misc.c (resolve_hostname): added IPv6 specific name resolution modified files: ChangeLog src/misc.c 2006-09-11 09:40:58 GMT Balazs Scheidler patch-75 Summary: fixed NL handling in DGRAM transports Revision: syslog-ng--mainline--2.0--patch-75 2006-09-11 Balazs Scheidler * src/logreader.c (log_reader_iterate_buf): flush input buffer regardless of embedded NLs in the case of DGRAM transports modified files: ChangeLog src/logreader.c 2006-08-09 08:01:16 GMT Balazs Scheidler patch-74 Summary: fixed another memory leak that might happen during exit Revision: syslog-ng--mainline--2.0--patch-74 * src/messages.c (msg_send_internal_message): don't allocate a LogMessage if internal_msg_queue is NULL as that can't be sent anyway modified files: ChangeLog src/messages.c 2006-08-08 19:58:08 GMT Balazs Scheidler patch-73 Summary: various memory leak fixes Revision: syslog-ng--mainline--2.0--patch-73 * src/affile.c (affile_dw_deinit): check if self->writer is NULL, (affile_dd_free): call log_writer_options_destroy as LogWriterOptions might contain dynamically allocated memory, * src/afprog.c (afprogram_dd_exit): removed log_pipe_unref, it is performed by the children handling framework, (afprogram_dd_init): use the new GDestroyNotify argument of children manager, (afprogram_dd_free): added log_writer_options_destroy call * src/afsocket.c (afsocket_dd_free): added log_writer_options_destroy call * src/children.c (ChildEntry): added callback_data_destroy member, (child_manager_child_entry_free): new function, frees a ChildEntry, (child_manager_sigchild): removed g_free, it is done by the GHashTable automatically, (child_manager_init): use g_hash_table_new_full and specify destroy notify callback for the data stored in the hashtable * src/logreader.c (log_reader_iterate_buf): assume that saddr is a borrowed reference and handle it as such, (log_reader_fetch_log): iterate_buf borrows the reference so it is our duty to free sockaddr, do so in all branches, * src/logwriter.c (log_writer_deinit): drop reference to self->control to break a circular reference, (log_writer_free): removed log_pipe_unref self->control, * src/messages.c (msg_send_internal_message): check if internal_msg_queue is null, (msg_deinit): free internal_msg_queue modified files: ChangeLog src/affile.c src/afprog.c src/afsocket.c src/children.c src/children.h src/logreader.c src/logwriter.c src/logwriter.h src/messages.c 2006-08-02 07:22:17 GMT Balazs Scheidler patch-72 Summary: Fixed possible DoS when a 0 sized packet is received via UDP Revision: syslog-ng--mainline--2.0--patch-72 * src/logreader.c (log_reader_fetch_log): don't take 0 sized packets as EOF for packet based transports like UDP * src/afsocket.c (afsocket_sc_notify): don't close the input connection on read errors for non-stream based transports modified files: ChangeLog src/afsocket.c src/logreader.c 2006-07-28 12:54:35 GMT Balazs Scheidler patch-71 Summary: fixed facility filter evaluation problem on platforms with unsigned chars (powerpc) Revision: syslog-ng--mainline--2.0--patch-71 * src/filter.c (filter_facility_eval): Fixed filter evaluation on platforms which have unsigned character type by default (powerpc) modified files: ChangeLog src/filter.c 2006-07-16 19:29:31 GMT Balazs Scheidler patch-70 Summary: added clarification of the output format of program() Revision: syslog-ng--mainline--2.0--patch-70 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-07-08 11:56:10 GMT Balazs Scheidler patch-69 Summary: NEWS update Revision: syslog-ng--mainline--2.0--patch-69 modified files: ChangeLog NEWS 2006-07-08 11:52:25 GMT Balazs Scheidler patch-68 Summary: preparations for 2.0rc1 release Revision: syslog-ng--mainline--2.0--patch-68 modified files: ChangeLog NEWS 2006-06-28 12:09:44 GMT Balazs Scheidler patch-67 Summary: fixed unix domain destination handling Revision: syslog-ng--mainline--2.0--patch-67 * src/afunix.c (afunix_dd_new): initialize bind_addr as the afsocket code assumes that it is not NULL, fixes a possible SIGSEGV modified files: ChangeLog NEWS src/afunix.c 2006-06-23 14:10:53 GMT Balazs Scheidler patch-66 Summary: fixed dir_group processing Revision: syslog-ng--mainline--2.0--patch-66 * src/affile.c (affile_dd_new): dir_gid was not initialized because of a typo, thus dir_group() did not take effect, fixed modified files: ChangeLog src/affile.c 2006-06-20 12:50:32 GMT Balazs Scheidler patch-65 Summary: bumped version to 2.0rc1 Revision: syslog-ng--mainline--2.0--patch-65 modified files: ChangeLog VERSION 2006-06-20 11:44:31 GMT Balazs Scheidler patch-64 Summary: documentation updates, flush_timeout changed to use msecs Revision: syslog-ng--mainline--2.0--patch-64 * doc/reference/syslog-ng.xml: documentation updates * src/logwriter.c (log_writer_fd_prepare): assume that the flush_timeout parameter is in msecs * src/cfg.c (cfg_init): use 10000 as default for flush_timeout() modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/cfg.c src/logwriter.c 2006-06-12 09:21:24 GMT Balazs Scheidler patch-63 Summary: support optional() for file destinations, optional destinations are only reopened after time_reopen() time has elapsed Revision: syslog-ng--mainline--2.0--patch-63 * src/affile.c (AFFileDestWriter): added time_reopen and last_open_stamp members, (affile_dw_init): store the time_reopen value from cfg, save the current time in last_open_stamp, don't fail the initialization if optional is enabled, (affile_dw_queue): reopen the destination if time_reopen() time has elapsed, drop the message if we are without a destination, * src/cfg-grammar.y (dest_affile_options): added KW_OPTIONAL parsing modified files: ChangeLog src/affile.c src/cfg-grammar.y 2006-06-12 08:47:41 GMT Balazs Scheidler patch-62 Summary: fixed evaluation of priority range filters Revision: syslog-ng--mainline--2.0--patch-62 * src/syslog-names.c (syslog_name_find_name): new inline function used by various lookup functions, (syslog_name_lookup_id_by_name): renamed from syslog_lookup_name, (syslog_name_lookup_name_by_value): renamed from syslog_lookup_value, (syslog_name_lookup_value_by_name): new function, (syslog_make_range): renamed parameters to make the code more readable * src/syslog-names.h (syslog_name_lookup_level_by_name): changed to return the _VALUE_ for syslog message levels, (syslog_name_lookup_facility_by_name): follow name changes * src/cfg-grammar.y: use the new, more readable function names in syslog-names.c * src/filter.c (filter_level_eval): we store a bitmask of the value of priorities instead of our internal ids, thus the function body was simplified a lot (and it works now :) * src/macros.c (log_macro_expand): follow function renames * tests/unit/test_filters.c: added level range tests modified files: ChangeLog src/cfg-grammar.y src/filter.c src/macros.c src/syslog-names.c src/syslog-names.h tests/unit/test_filters.c 2006-06-12 07:53:10 GMT Balazs Scheidler patch-61 Summary: portability fixes Revision: syslog-ng--mainline--2.0--patch-61 * configure.in: detect AIX and HP-UX using uname -s, instead of trying to extract platform information from the linker's version number (proved not to be reliable on HP-UX) * src/misc.c (getlonghostname, getshorthostname): use 256 characters array to store hostnames * src/sgroup.c (log_source_group_queue): -"- modified files: ChangeLog configure.in src/misc.c src/sgroup.c 2006-06-07 09:14:55 GMT Balazs Scheidler patch-60 Summary: fixed pointer conversion macros on 64 bit platforms Revision: syslog-ng--mainline--2.0--patch-60 * src/macros.c (log_macro_lookup): use GINT_TO_POINTER and GPOINTER_TO_INT macros instead of casting values directly to avoid warnings on 64 bit systems modified files: ChangeLog src/macros.c 2006-06-07 09:09:14 GMT Balazs Scheidler patch-59 Summary: do not reconnect to target immediately but wait for time_reopen first Revision: syslog-ng--mainline--2.0--patch-59 * src/afsocket.c (afsocket_dd_notify): instead of immediately scheduling a reconnect, start the reconnect timer to avoid excessive number of reconnection requests in case of a going up-and-down connection modified files: ChangeLog src/afsocket.c 2006-06-07 09:07:40 GMT Balazs Scheidler patch-58 Summary: fixed IPv6 portability problem Revision: syslog-ng--mainline--2.0--patch-58 * src/afinet.c (afinet_setup_socket): use the "official" IPV6_JOIN_GROUP name instead of IPV6_ADD_MEMBERSHIP as the latter is not defined on all platforms modified files: ChangeLog src/afinet.c 2006-06-01 09:10:00 GMT Balazs Scheidler patch-57 Summary: fixed HP-UX portability problem Revision: syslog-ng--mainline--2.0--patch-57 * src/afinet.c (afinet_setup_socket): fixed IN6_IS_ADDR_MULTICAST call as struct in6_addr definition differs on HP-UX (thanks go to Albert Chin) modified files: ChangeLog src/afinet.c 2006-05-26 19:33:31 GMT Balazs Scheidler patch-56 Summary: removed C99ism from stats.c Revision: syslog-ng--mainline--2.0--patch-56 * src/stats.c (stats_generate_log): remove C99 initializers from the initialization of tag_names to make syslog-ng compatible with vendor compilers of various commercial UNIX platforms modified files: ChangeLog src/stats.c 2006-05-26 19:30:30 GMT Balazs Scheidler patch-55 Summary: compatibility fixes for Solaris/AIX Revision: syslog-ng--mainline--2.0--patch-55 2006-05-26 Balazs Scheidler * src/afinet.c: define SOL_IP and SOL_IPV6 on platforms which use IPPROTO_* for this purpose, added the inclusion of for the definition of memset() modified files: ChangeLog src/afinet.c 2006-05-26 19:25:24 GMT Balazs Scheidler patch-54 Summary: added LEVEL_NUM and FACILITY_NUM macros to follow 1.6.x changes Revision: syslog-ng--mainline--2.0--patch-54 * src/macros.c (log_macro_expand): added code for LEVEL_NUM and FACILITY_NUM macros * tests/test_template.c: added testcase for LEVEL_NUM and FACILITY_NUM macros modified files: ChangeLog src/macros.c src/macros.h tests/unit/test_template.c 2006-05-24 08:59:44 GMT Balazs Scheidler patch-53 Summary: guard LOG_CRON with ifdef as it might not exist on some platforms Revision: syslog-ng--mainline--2.0--patch-53 * src/syslog-names.c (sl_facilities): some platforms do not define LOG_CRON modified files: ChangeLog src/syslog-names.c 2006-05-23 18:45:59 GMT Balazs Scheidler patch-52 Summary: preparations for 1.9.11 Revision: syslog-ng--mainline--2.0--patch-52 modified files: ChangeLog NEWS VERSION 2006-05-23 18:45:37 GMT Balazs Scheidler patch-51 Summary: fixed dropping input/output/error fds when going to background Revision: syslog-ng--mainline--2.0--patch-51 2006-05-23 Balazs Scheidler * src/main.c (setup_std_fds): fix inverted check for errors after opening /dev/null, also close stderr when log_to_stderr is not specified * src/afprog.c (afprogram_dd_init): removed setsid call modified files: ChangeLog src/afprog.c src/main.c 2006-05-23 18:33:25 GMT Balazs Scheidler patch-50 Summary: add program exit status information to 'child program exited' log message Revision: syslog-ng--mainline--2.0--patch-50 2006-05-23 Balazs Scheidler * src/afprog.c (afprogram_dd_exit): added program exit status information to 'child program exited' log message modified files: ChangeLog src/afprog.c 2006-05-23 18:31:55 GMT Balazs Scheidler patch-49 Summary: added direction to socket setup code, fixed multicast setup Revision: syslog-ng--mainline--2.0--patch-49 2006-05-23 Balazs Scheidler * src/afsocket.h (AFSocketDirection): new type, specifies the future communication direction on a socket, used to determine which socket options to set on a socket, * src/afsocket.c (afsocket_setup_socket): added direction parameter, (afsocket_sd_setup_socket, afsocket_dd_setup_socket): pass value for 'direction' parameter * src/afinet.c (afinet_setup_socket): added direction parameter, fixed multicast check for IPv4 addresses modified files: ChangeLog src/afinet.c src/afsocket.c src/afsocket.h 2006-05-23 18:28:52 GMT Balazs Scheidler patch-48 Summary: check that the value for time_sleep is less than 500msec Revision: syslog-ng--mainline--2.0--patch-48 2006-05-23 Balazs Scheidler * src/cfg-grammar.y (options_item, KW_TIME_SLEEP): check if the value is more than 500, and maximize its value in this case * src/main.c (main_loop_run): calculate timespec properly if time_sleep is more than 1 sec modified files: ChangeLog src/cfg-grammar.y src/main.c 2006-05-01 14:06:35 GMT Balazs Scheidler patch-47 Summary: added options to control various socket parameters and added multicast support Revision: syslog-ng--mainline--2.0--patch-47 * src/gsockaddr.h (g_sockaddr_inet6_get_address, g_sockaddr_inet6_set_address): use pointers to struct in6_addr instead of passing the structure by value * src/afsocket.c (afsocket_setup_socket): new function, set generic socket options, (afsocket_sd_accept): call setup_socket for new fds, (afsocket_sd_init): -"-, (afsocket_dd_reconnect): -"-, (afsocket_sd_setup_socket): new function, default setup_socket callback, (afsocket_sd_init_instance): added sock_options argument, set default setup_socket callback, (afsocket_dd_init_instance): added sock_options argument, set default setup_socket callback, * src/afsocket.h (AFSocketSourceDriver): added setup_socket callback, (AFSocketDestDriver): added setup_socket callback, * src/afinet.c (afinet_resolve_name): follow g_sockaddr_inet6_set_address change, (afinet_setup_socket): new function to set AF_INET & AF_INET6 specific socket options, (afinet_sd_setup_socket): new function, used as the setup_socket callback, (afinet_dd_setup_socket): new function, used as the setup_socket callback, * src/afunix.c (afunix_sd_new, afunix_dd_new): adapted to afsocket changes, * src/cfg-grammar.y (socket_option, inet_socket_option): added socket option parsing * src/cfg-lex.l: added new keywords for socket options modified files: ChangeLog doc/reference/syslog-ng.xml src/afinet.c src/afinet.h src/afsocket.c src/afsocket.h src/afunix.c src/afunix.h src/cfg-grammar.y src/cfg-lex.l src/gsockaddr.h 2006-05-01 12:38:10 GMT Balazs Scheidler patch-46 Summary: fixed Solaris portability problems, avoid multiread on STREAMS sources Revision: syslog-ng--mainline--2.0--patch-46 * configure.in: check for -lrt for nanosleep * src/afstreams.c (afstreams_sd_init): pass LR_NOMREAD flag to log_reader_new() modified files: ChangeLog configure.in src/afstreams.c 2006-04-30 20:20:44 GMT Balazs Scheidler patch-45 Summary: fixed fetching kernel messages which was broken by the multi-read patches Revision: syslog-ng--mainline--2.0--patch-45 * src/logreader.h (LR_NOMREAD): new flag, indicates that the log reader should not use multiple read() calls in a single poll loop * src/logreader.c (log_reader_fetch_log): break out of the loop if LR_NOMREAD is specified * src/affile.c (affile_sd_init): specify LR_NOMREAD modified files: ChangeLog src/affile.c src/logreader.c src/logreader.h 2006-04-23 10:35:57 GMT Balazs Scheidler patch-44 Summary: fixed endless-loop and CPU spinning if a non-existing filter is referenced in the internal() path Revision: syslog-ng--mainline--2.0--patch-44 * src/filter.c (filter_call_eval): only log the "not-found filter" error message once modified files: ChangeLog src/filter.c 2006-04-23 10:22:21 GMT Balazs Scheidler patch-43 Summary: fixed possible memory leak Revision: syslog-ng--mainline--2.0--patch-43 * src/logreader.c (log_reader_iterate_buf): drop self->prev_addr reference if it exists, previously it might have been overwritten with a new reference without dropping the old, fixes a potential GSockAddr reference leak modified files: ChangeLog src/logreader.c 2006-04-23 09:23:19 GMT Balazs Scheidler patch-42 Summary: added IPv6 support Revision: syslog-ng--mainline--2.0--patch-42 * configure.in: added --enable-ipv6 option, defaults to "yes", added checks for getaddrinfo() * src/afinet.c (afinet_set_port): added ipv6 support, (afinet_resolve_name): renamed from afinet_set_ip, use getaddrinfo() to resolve names where available, (afinet_sd_new): added af argument, use afinet_resolve_name instead of the removed g_sockaddr_inet_new_resolve() function, use a default "bind address" value if the host argument is NULL, (afinet_dd_new): added af argument, use afinet_resolve_name instead of the removed g_sockaddr_inet_new_resolve() function * src/cfg-grammar.y: added KW_UDP6 and KW_TCP6 keywords, (source_afsocket, dest_afsocket): added rules for KW_UDP6 & KW_TCP6, (dest_afinet_udp_params, dest_afinet_tcp_params): added ipv6 support, adapted to the latest changes in afinet (source_afinet_udp_params, source_afinet_tcp_params): -"- * src/cfg-lex.l: added "udp6" and "tcp6" keywords * src/gsockaddr.c (g_sockaddr_inet_new_resolve): removed this function as it is an address family independent operation now implemented in afinet.c, (g_sockaddr_inet6_check): new function to check whether a GSockAddr contains an ipv6 socket name, * src/gsockaddr.h (g_sockaddr_get_sa, g_sockaddr_inet_get_sa, g_sockaddr_inet_get_address, g_sockaddr_inet_set_address, g_sockaddr_inet_get_port, g_sockaddr_inet_set_port): new inline functions, ported from the Zorp sockaddr code, (g_sockaddr_inet6_get_sa, g_sockaddr_inet6_get_address, g_sockaddr_inet6_set_address, g_sockaddr_inet6_get_port, g_sockaddr_inet6_set_port): new functions, similar to IPv6 counterparts modified files: ChangeLog configure.in src/afinet.c src/afinet.h src/cfg-grammar.y src/cfg-lex.l src/gsockaddr.c src/gsockaddr.h 2006-04-20 12:07:17 GMT Balazs Scheidler patch-41 Summary: fixed off-by-one in flush_lines() calculation Revision: syslog-ng--mainline--2.0--patch-41 * src/logwriter.c (log_writer_fd_prepare): flush_lines(1) required two lines to be flushed, modified the condition so that: flush_lines(0) that output buffering is off, flush_lines(1) is basically equivalent, every single individual line is flushed, flush_lines(2) flushes the output buffer if two lines are already available modified files: ChangeLog src/logwriter.c 2006-04-20 11:57:20 GMT Balazs Scheidler patch-40 Summary: added close-on-exec flag to all opened fds to avoid their inheritance to child processes Revision: syslog-ng--mainline--2.0--patch-40 * src/af*.c: call g_fd_set_cloexec for all new fds * src/misc.c (g_fd_set_cloexec): new function, sets FD_CLOEXEC flag for an fd modified files: ChangeLog src/affile.c src/afprog.c src/afsocket.c src/afstreams.c src/misc.c src/misc.h 2006-04-19 18:47:12 GMT Balazs Scheidler patch-39 Summary: change file owner/group independently Revision: syslog-ng--mainline--2.0--patch-39 * src/affile.c (affile_open_file): change owner/group independently modified files: ChangeLog src/affile.c 2006-04-19 18:44:34 GMT Balazs Scheidler patch-38 Summary: don't try to chmod/chown files that do not exist Revision: syslog-ng--mainline--2.0--patch-38 * src/affile.c (affile_open_file): don't call chmod/chown when opening the file failed modified files: ChangeLog src/affile.c 2006-04-10 21:36:12 GMT Balazs Scheidler patch-37 Summary: fixed a compilation warning Revision: syslog-ng--mainline--2.0--patch-37 modified files: ChangeLog src/cfg-grammar.y 2006-04-10 21:33:37 GMT Balazs Scheidler patch-36 Summary: preparations for 1.9.10, this time for real Revision: syslog-ng--mainline--2.0--patch-36 modified files: ChangeLog NEWS 2006-04-10 21:32:30 GMT Balazs Scheidler patch-35 Summary: display an error message instead of a failed assertion when the user specifies conflicting sources Revision: syslog-ng--mainline--2.0--patch-35 * src/cfg.c (persist_config_add): don't store the value if it is NULL, display an error message instead of a failed assertion if the persistent name conflicts modified files: ChangeLog src/cfg.c 2006-04-10 20:59:32 GMT Balazs Scheidler patch-34 Summary: don't treat parse flags as keywords Revision: syslog-ng--mainline--2.0--patch-34 * src/cfg-grammar.y: removed KW_NO_PARSE and KW_KERNEL tokens, (source_reader_option_flags): use IDENTIFIER instead of using separate keywords and call lookup_parse_flag to convert the textual representation of parse flags to flag values, * src/cfg-lex.l (keywords): removed no_parse and kernel keywords, (lookup_parse_flag): new function, returns the flag value associated with the text representation * src/cfg.c (cfg_init): fixed possible segfault when bad_hostname regexp was not specified modified files: ChangeLog src/cfg-grammar.y src/cfg-lex.l src/cfg.c 2006-04-10 20:47:03 GMT Balazs Scheidler patch-33 Summary: implemented bad_hostname and check_hostname options Revision: syslog-ng--mainline--2.0--patch-33 * src/cfg-grammar.y: added KW_BAD_HOSTNAME and KW_CHECK_HOSTNAME tokens * src/cfg-lex.l: added keywords for KW_BAD_HOSTNAME and KW_CHECK_HOSTNAME * src/cfg.c (cfg_bad_hostname_set): new function, set global bad_hostname regexp, (cfg_init): compile bad_hostname_re * src/log.c (log_msg_parse): added bad_hostname regexp param, and an implementation of check_hostname() and bad_hostname(), (log_msg_init): avoid a time(NULL) call, (log_msg_new): added bad_hostname parameter, (log_reader_options_init): set options->options and options->bad_hostname based on the values stored in GlobalConfig * tests/unit/test_msgparse.c: added testcases for check_hostname() and bad_hostname() * src/*.c, src/*.h: followed changes modified files: ChangeLog NEWS src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/logmsg.c src/logmsg.h src/logreader.c src/logreader.h src/messages.c tests/unit/test_filters.c tests/unit/test_msgparse.c tests/unit/test_template.c 2006-04-09 08:02:44 GMT Balazs Scheidler patch-32 Summary: fixed timestamp calculation on timezone barriers Revision: syslog-ng--mainline--2.0--patch-32 * src/logmsg.c (log_msg_parse): fixed timestamp calculation where a timezone information was specified, see the comment for details, * tests/unit/test_msgparse.c: added some more testcases with timestamps around the DST switch * tests/unit/test_template.c: fixed the timezone offset of the arbitrary timestamp chosen in the testcases modified files: ChangeLog src/logmsg.c src/misc.c tests/unit/test_msgparse.c tests/unit/test_template.c 2006-04-07 14:27:52 GMT Balazs Scheidler patch-31 Summary: accept negative numbers as NUMBER in the lexer Revision: syslog-ng--mainline--2.0--patch-31 2006-04-07 Balazs Scheidler * src/cfg-lex.l: accept negative numbers in the lexer modified files: ChangeLog src/cfg-lex.l 2006-04-06 10:20:41 GMT Balazs Scheidler patch-30 Summary: added a paragraph to the documentation clarifying pipe and /proc/kmsg Revision: syslog-ng--mainline--2.0--patch-30 modified files: ChangeLog doc/reference/syslog-ng.xml 2006-04-02 10:11:57 GMT Balazs Scheidler patch-29 Summary: updated NEWS file, preparations for 1.9.10 Revision: syslog-ng--mainline--2.0--patch-29 * VERSION: bumped version to 1.9.10 modified files: ChangeLog NEWS VERSION 2006-04-01 08:03:10 GMT Balazs Scheidler patch-28 Summary: fixed large file support Revision: syslog-ng--mainline--2.0--patch-28 * configure.in: check for O_LARGEFILE * src/affile.c: use O_LARGEFILE when available modified files: ChangeLog configure.in src/affile.c 2006-03-26 17:38:09 GMT Balazs Scheidler patch-27 Summary: fixed priority level filtering Revision: syslog-ng--mainline--2.0--patch-27 * src/cfg-grammar.y (filter_level): fixed priority level based filtering, spotted and reported by Jakub Bogusz modified files: ChangeLog src/cfg-grammar.y 2006-03-22 15:39:58 GMT Balazs Scheidler patch-26 Summary: fixed a possible segmentation fault on write errors Revision: syslog-ng--mainline--2.0--patch-26 * src/logwriter.c (log_writer_flush_log): return from the function on error instead of looping with line == NULL, this fixes a possible SIGSEGV, when some messages sit in the queue while the destination goes away modified files: ChangeLog src/logwriter.c 2006-03-18 22:08:50 GMT Balazs Scheidler patch-25 Summary: reimplemented netmask() filter which was missing from 1.9.9 Revision: syslog-ng--mainline--2.0--patch-25 * src/cfg-grammar.y, src/cfg-lex.l: added KW_NETMASK * src/filter.c (filter_netmask_new): new function to construct a netmask filter, cidr "address/prefix" and "address/address" formats are accepted * src/logmsg.h: fixed a warning by declaring log_msg_clear_matches function * doc/reference/syslog-ng.xml: added a notice on redefining template() for network destinations * tests/unit/test_filter.c: added unit tests for netmask filter modified files: ChangeLog doc/reference/syslog-ng.xml src/cfg-grammar.y src/cfg-lex.l src/filter.c src/filter.h src/logmsg.h tests/unit/test_filters.c 2006-03-13 23:12:08 GMT Balazs Scheidler patch-24 Summary: fixed regexp match space macro expansion Revision: syslog-ng--mainline--2.0--patch-24 * src/filter.c (filter_re_eval): added msg parameter, instead of using the re_matches array, use a per-message store * src/logmsg.h (LogMessage): added re_matches * src/macros.c (log_macro_expand): use per-message re_matches array modified files: ChangeLog src/filter.c src/filter.h src/logmsg.c src/logmsg.h src/macros.c src/main.c 2006-03-13 17:16:08 GMT Balazs Scheidler patch-23 Summary: fail the testprogram if the pidfile could not be found Revision: syslog-ng--mainline--2.0--patch-23 modified files: ChangeLog tests/functional/func_test.py 2006-03-13 16:37:17 GMT Balazs Scheidler patch-22 Summary: stats_freq is only taken into account if the value is larger than 0 Revision: syslog-ng--mainline--2.0--patch-22 * src/main.c (main_loop_run): take changed stats_freq into account after a SIGHUP, stats_freq == 0 means to disable stats messages altogether modified files: ChangeLog src/main.c 2006-03-13 10:40:55 GMT Balazs Scheidler patch-21 Summary: added %option noyywrap to cfg-lex.l Revision: syslog-ng--mainline--2.0--patch-21 * src/cfg-lex.l: added %option noyywrap to cfg-lex.l modified files: ChangeLog src/cfg-lex.l 2006-02-28 18:47:01 GMT Balazs Scheidler patch-20 Summary: fixed possible abort in program destination Revision: syslog-ng--mainline--2.0--patch-20 * src/afprog.c (afprogram_dd_deinit): don't drop the reference to self->writer, only deinit it, (afprogram_dd_free): drop the reference to self->writer, * src/main.c (main_loop_run): change the loop so that it actually processes exited children modified files: ChangeLog src/afprog.c src/main.c 2006-02-26 09:39:39 GMT Balazs Scheidler patch-19 Summary: really release 1.9.9 Revision: syslog-ng--mainline--2.0--patch-19 modified files: ChangeLog tests/functional/func_test.py 2006-02-26 09:38:42 GMT Balazs Scheidler patch-18 Summary: fixed a possible heap overflow introduced by the patches from 2006-02-24 Revision: syslog-ng--mainline--2.0--patch-18 * src/logreader.c (log_reader_fetch_log): recalculate the available buffer size before calling read() again, this is a possible heap overflow which was introduced by devel@balabit.hu--other-1/syslog-ng--mainline--2.0--patch-14 ChangeLog is in patch-15, this was never released however modified files: ChangeLog src/logreader.c 2006-02-26 08:50:05 GMT Balazs Scheidler patch-17 Summary: preparations for an 1.9.9 release Revision: syslog-ng--mainline--2.0--patch-17 modified files: ChangeLog NEWS VERSION src/logmsg.c 2006-02-26 08:47:15 GMT Balazs Scheidler patch-16 Summary: added time_sleep() option to add a fixed latency to the poll loop Revision: syslog-ng--mainline--2.0--patch-16 * src/cfg-grammar.y: added KW_TIME_SLEEP processing * src/cfg-lex.l: added keyword for KW_TIME_SLEEP * src/main.c: wait using nanosleep if time_sleep() is set * doc/reference/syslog-ng.xml: added documentation on time_sleep and a section in the tuning part to explain it a little further modified files: ChangeLog doc/reference/syslog-ng.xml src/cfg-grammar.y src/cfg-lex.l src/cfg.h src/main.c 2006-02-24 16:24:14 GMT Balazs Scheidler patch-15 Summary: added missing ChangeLog from previous patchset Revision: syslog-ng--mainline--2.0--patch-15 * src/fdread.c (fd_do_read): added retrying on EINTR * src/logreader.c (log_reader_iterate_buf): added msg_count argument instead of the local variable as log_reader_iterate_buf might be called multiple times and we do not want to fetch more than fetch_limit() messages in total, (log_reader_fetch_log): added loop to iterate over up to fetch_limit messages without going back to the mainloop modified files: ChangeLog 2006-02-24 16:19:33 GMT Balazs Scheidler patch-14 Summary: added reference/syslog-ng.txt to EXTRA_DIST Revision: syslog-ng--mainline--2.0--patch-14 modified files: ChangeLog doc/Makefile.am src/fdread.c src/logreader.c 2006-02-24 16:13:38 GMT Balazs Scheidler patch-13 Summary: added syslog-ng.txt generation to Makefile Revision: syslog-ng--mainline--2.0--patch-13 modified files: ChangeLog doc/Makefile.am 2006-02-12 13:37:21 GMT Balazs Scheidler patch-12 Summary: fixed second fraction processing so that it actually shows up in output Revision: syslog-ng--mainline--2.0--patch-12 * src/afsocket.h: removed AFSOCKET_PROTO_RFC3164, it might be readded later when multiple protocols will be added, but for now it only clutters the code * src/cfg-grammar.y (KW_TIMESTAMP): moved keep_timestamp processing to the readers, logwriters always reformat the timestamp based on the parsed value, keep_timestamp(no) overwrites the timestamp in the message with the received time, (KW_FRAC_DIGITS): added a way to specify second fraction precision, it now defaults to zero, e.g. no fraction information is added, * src/logmsg.c (log_stamp_format): added support for unix and full timestamps, added frac_digits argument (LogStamp): removed frac_present member, if the user requests second fragments one is always generated, if this information is not available 0 is assumed * src/cfg.c (cfg_ts_format_value): added support for unix and full timestamps, (cfg_new): frac_digits is initialized to 0, keep_timestamp to TRUE * src/logreader.c (log_reader_handle_line): overwrite the message timestamp if keep_timestamp if FALSE, (log_reader_options_init): use the global keep_timestamp setting is one is not specified * src/logwriter.c (log_writer_format_log): always regenerate the timestamp if no template was specified, as there's no point in using the original date in the message as it clutters logs and might confuse receivers, (LWOF_FIXED_STAMP): removed, this is the default behaviour which can be overridden by using templates * src/macros.c (log_macro_expand): use log_stamp_format for all date/time formatting instead of open-coding them, DATE uses the BSD timestamp, regardless of the value of ts_format * src/test_template.c: fixed testprogram modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/affile.c src/afinet.c src/afsocket.c src/afsocket.h src/cfg-grammar.y src/cfg-lex.l src/cfg.c src/cfg.h src/logmsg.c src/logmsg.h src/logreader.c src/logreader.h src/logwriter.c src/logwriter.h src/macros.c src/macros.h src/templates.c src/templates.h tests/unit/test_template.c 2006-02-11 19:29:56 GMT Balazs Scheidler patch-11 Summary: readded HOST_FROM, FULLHOST_FROM, SOURCEIP macros, extended unit test program Revision: syslog-ng--mainline--2.0--patch-11 * src/gsockaddr.c (g_sockaddr_inet_check): new function, returns TRUE if the specified address is GSockAddrInet * src/logmsg.c (log_msg_parse): fixed timezone parsing in ISODATE timestamps, (log_msg_init): added host_from member, (log_msg_free): free host_from * src/macros.c (log_macro_expand): added FULLHOST_FROM, HOST_FROM, SOURCEIP implementation, fixed DATE macros * src/misc.c (resolve_hostname): instead of returning a newly allocated GString, store the result in the one passed as parameter * src/sgroup.c (log_source_group_queue): set host_from member in log message * tests/unit/test_msgparse.c: fixed offset/timestamp value * tests/unit/test_template.c: greatly extended to cover all possible macros, resulting fixes are above :) modified files: ChangeLog NEWS src/gsockaddr.c src/gsockaddr.h src/logmsg.c src/logmsg.h src/macros.c src/macros.h src/misc.c src/misc.h src/sgroup.c tests/unit/test_msgparse.c tests/unit/test_template.c 2006-02-11 17:31:08 GMT Balazs Scheidler patch-10 Summary: fixed possible segmentation fault on SIGHUP Revision: syslog-ng--mainline--2.0--patch-10 * src/afsocket.c (afsocket_sc_set_owner): new function, changes all references to a new AFSocketSourceDriver (this happens accross SIGHUPs), (afsocket_sd_set_listener_keep_alive): removed, there's no separate LISTENER_KEEP_ALIVE setting, (afsocket_sd_init): instead of simply changing the next-hop log-pipe of connections call afsocket_sc_set_owner which changes less explicit references * src/cfg-grammar.y (yyparser_reset): new function, resets all 'last_' variables as they are not referenced and might contain pointers to stale data * src/logpipe.c (log_pipe_free_instance): function body moved to log_pipe_unref to clear some clutter in backtraces and both functions are only a couple of lines anyway * src/logreader.c (log_reader_set_options): new function, allows the caller to change the pointer to the options structure modified files: ChangeLog NEWS src/afinet.c src/afsocket.c src/afsocket.h src/afunix.c src/cfg-grammar.y src/cfg.c src/logpipe.c src/logreader.c src/logreader.h src/logsource.c src/logsource.h src/main.c 2006-02-11 17:22:06 GMT Balazs Scheidler patch-9 Summary: memtrace improvements Revision: syslog-ng--mainline--2.0--patch-9 * src/memtrace.c: added backtrace to add/delblock messages modified files: ChangeLog src/memtrace.c 2006-02-11 13:41:36 GMT Balazs Scheidler patch-8 Summary: added some more unit testcases for filter testing Revision: syslog-ng--mainline--2.0--patch-8 modified files: ChangeLog tests/unit/test_filters.c 2006-02-11 13:07:54 GMT Balazs Scheidler patch-7 Summary: added "kernel" flag to log reader flags Revision: syslog-ng--mainline--2.0--patch-7 2006-02-11 Balazs Scheidler * src/cfg-lex.l, src/cfg-grammar.y: added "kernel" keyword * src/logmsg.c (log_msg_parse): default to kern.crit for kernel messages * src/macros.c: fixed PRI macro as it included the hostname as well modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/cfg-grammar.y src/cfg-lex.l src/logmsg.c src/logmsg.h src/logreader.c src/logreader.h src/macros.c 2006-02-11 12:44:37 GMT Balazs Scheidler patch-6 Summary: added PID macro and its documentation Revision: syslog-ng--mainline--2.0--patch-6 * src/macros.c (log_expand_macro): added support for PID modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/macros.c src/macros.h 2006-02-11 12:00:14 GMT Balazs Scheidler patch-5 Summary: added normalize_hostnames() option (fixes: #6294) Revision: syslog-ng--mainline--2.0--patch-5 2006-02-11 Balazs Scheidler * src/cfg-lex.l, src/cfg-grammar.y: added normalize_hostnames option * src/sgroup.c: implement normalize_hostnames * src/logmsg.c (log_msg_parse): removed STRICT check from RFC3339 timestamp parsing * doc/reference/syslog-ng.xml: updated modified files: ChangeLog NEWS doc/reference/syslog-ng.xml src/cfg-grammar.y src/cfg-lex.l src/cfg.h src/logmsg.c src/misc.c src/misc.h src/sgroup.c src/sgroup.h 2006-02-11 10:57:43 GMT Balazs Scheidler patch-4 Summary: Added processed counters for source/destination groups and the log center (fixes: #5368) Revision: syslog-ng--mainline--2.0--patch-4 * src/affile.c (affile_dd_format_stats_name): readded this function to generate a unique stats ID for the specific destination driver instance, (affile_dd_init): use NO_STATS for files only, * src/center.c (log_center_init): added received/queued counters, (log_center_queue): increment counters * src/sgroup.c, src/dgroup.c: added processed counters * src/stats.c, src/stats.h: added SC_TYPE_PROCESSED, make sure that counters are interpreted in their proper namespace, (stats_unregister_counter): added missing "type" argument modified files: ChangeLog NEWS src/affile.c src/center.c src/center.h src/dgroup.c src/dgroup.h src/driver.c src/logwriter.c src/sgroup.c src/sgroup.h src/stats.c src/stats.h 2006-02-11 08:43:32 GMT Balazs Scheidler patch-3 Summary: added optional() parameter to pipe/unix drivers (fixes: #4999) Revision: syslog-ng--mainline--2.0--patch-3 * src/driver.h: added optional member (fixes: #4999) * src/cfg-lex.l: added optional keyword (fixes: #4999) * src/cfg-grammar.y: added optional keyword to pipe and unix domain socket based source drivers (fixes: #4999) * src/afsocket.c (afsocket_sd_init): do not fail if binding failed and optional is TRUE (fixes: #4999) * src/affile.c (affile_sd_init): do not fail if opening failed and optional is TRUE (fixes: #4999) modified files: ChangeLog doc/reference/syslog-ng.xml src/affile.c src/afsocket.c src/cfg-grammar.y src/cfg-lex.l src/driver.h 2006-02-11 08:16:00 GMT Balazs Scheidler patch-2 Summary: implemented filter debugging (fixes: #3988) Revision: syslog-ng--mainline--2.0--patch-2 * src/filter.c (log_filter_rule_eval): new function, previously rule->root was manipulated directly which was not nice, filter rule debugging messages are put here (fixes: #3988), (filter_expr_eval): uninlined, added debugging messages (fixes: #3988), (filter_expr_free): uninlined (*_new): set self->type to be used in log messages properly (fixes: #3988) modified files: ChangeLog src/center.c src/filter.c src/filter.h 2006-02-11 07:53:02 GMT Balazs Scheidler patch-1 Summary: integrated last pending patch from bazsi's archive, started new ChangeLog Revision: syslog-ng--mainline--2.0--patch-1 * tla archives were switched, syslog-ng now uses devel@balabit.hu--other-1, the old ChangeLog file was archived as ChangeLog.1 * integrated a last pending patch from the old archive to fix a possible 64bit compatibility issue new files: .arch-ids/ChangeLog.1.id .arch-ids/ChangeLog.id ChangeLog ChangeLog.1 removed files: .arch-ids/ChangeLog.id ChangeLog modified files: src/logwriter.c src/logwriter.h new patches: bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-86 2006-01-27 09:17:47 GMT Attila SZALAY base-0 Summary: tag of bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-85 Revision: syslog-ng--mainline--2.0--base-0 (automatically generated log message) new patches: bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--base-0 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-1 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-2 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-3 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-4 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-5 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-6 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-7 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-8 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-9 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-10 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-11 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-12 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-13 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-14 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-15 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-16 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-17 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-18 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-19 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-20 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-21 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-22 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-23 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-24 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-25 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-26 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-27 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-28 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-29 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-30 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-31 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-32 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-33 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-34 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-35 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-36 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-37 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-38 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-39 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-40 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-41 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-42 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-43 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-44 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-45 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-46 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-47 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-48 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-49 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-50 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-51 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-52 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-53 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-54 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-55 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-56 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-57 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-58 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-59 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-60 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-61 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-62 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-63 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-64 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-65 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-66 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-67 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-68 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-69 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-70 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-71 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-72 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-73 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-74 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-75 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-76 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-77 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-78 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-79 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-80 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-81 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-82 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-83 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-84 bazsi@balabit.hu--bazsi-1/syslog-ng--mainline--2.0--patch-85 syslog-ng-syslog-ng-4.4.0/doc/Makefile.am000066400000000000000000000047101450431004300201560ustar00rootroot00000000000000xsd_DATA = \ doc/xsd/patterndb-1.xsd \ doc/xsd/patterndb-2.xsd \ doc/xsd/patterndb-3.xsd \ doc/xsd/patterndb-4.xsd \ doc/xsd/patterndb-5.xsd \ doc/xsd/patterndb-6.xsd EXTRA_DIST += \ doc/man/dqtool.1.xml \ doc/man/loggen.1.xml \ doc/man/pdbtool.1.xml \ doc/man/persist-tool.1.xml \ doc/man/syslog-ng-debun.1.xml \ doc/man/syslog-ng-ctl.1.xml \ doc/man/syslog-ng.8.xml \ doc/man/syslog-ng.conf.5.xml \ doc/man/slogencrypt.1.xml \ doc/man/slogkey.1.xml \ doc/man/slogverify.1.xml \ doc/man/secure-logging.7.xml \ doc/man/update-manpages.sh \ doc/security/bof-2002-09-27.txt \ doc/security/dos-2000-11-22.txt \ doc/xsd/examples/patterndb-1.xml \ $(xsd_DATA) manpages = \ doc/man/dqtool.1 \ doc/man/loggen.1 \ doc/man/pdbtool.1 \ doc/man/persist-tool.1 \ doc/man/syslog-ng-debun.1 \ doc/man/syslog-ng-ctl.1 \ doc/man/syslog-ng.8 \ doc/man/syslog-ng.conf.5 \ doc/man/slogencrypt.1 \ doc/man/slogkey.1 \ doc/man/slogverify.1 \ doc/man/secure-logging.7 # "dist" will always need the manpages, so we either need the documentation # tools, or the make dist needs to run from a release tarball, which ships # the manual pages. EXTRA_DIST += $(manpages) if ENABLE_MANPAGES_INSTALL man_MANS += $(manpages) endif if ENABLE_MANPAGES # we only clean manpages if we have the ability to regenerate them CLEANFILES += $(manpages) sysconfdir_e = $(shell echo "${sysconfdir}" | sed -e "s,-,\\\\\\\\-,g") prefix_e = $(shell echo "${prefix}" | sed -e "s,-,\\\\\\\\-,g") doc/man/%: doc/man/%.xml $(AM_V_at) $(NOOP) # Removing all XML whitespaces, workaround for the bug in $(AM_V_at) $(NOOP) # docbook-xsl v1.79.1. See https://sourceforge.net/p/docbook/bugs/1381/ $(AM_V_GEN)sed -e '1h;2,$$H;$$!d;g' -e 's/>[[:space:]][[:space:]]*$@.tmp && mv $@.tmp $@ else doc/man/%: doc/man/%.xml @echo "Error: unable to generate manual pages" @echo "" @echo "The generation manual pages was not enabled using --enable-manpages to configure and generated " @echo "versions do not seem to be available (which should be if you are building from a release tarball) " @echo "or the man page sources were changed." @echo "" @echo "Either build from an official release tarball or install documentation tools and run configure with --enable-manpages" @exit 1 endif syslog-ng-syslog-ng-4.4.0/doc/man/000077500000000000000000000000001450431004300166735ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/doc/man/.gitignore000066400000000000000000000000261450431004300206610ustar00rootroot00000000000000/syslog-ng-ose-guides syslog-ng-syslog-ng-4.4.0/doc/man/dqtool.1.xml000066400000000000000000000133671450431004300210700ustar00rootroot00000000000000 The dqtool tool manual page dqtool 1 4.4 dqtool Display the contents of a disk-buffer file created with dqtool command options Description NOTE: The dqtool application is distributed with the system logging application, and is usually part of the syslog-ng package. The latest version of the syslog-ng application is available at the official syslog-ng website. This manual page is only an abstract, for the complete documentation of syslog-ng, see The Administrator Guide. The dqtool application is a utility that can be used to display and format the messages stored in a disk-buffer file. The cat command cat options file Use the cat command to display the log messages stored in the disk-buffer (also called disk-queue) file, and also information from the header of the disk queue file. The messages are printed to the standard output (stdout), so it is possible to use grep and other tools to find particular log messages, e.g., dqtool cat /var/log/messages.lgs |grep 192.168.1.1. The cat command has the following options: --debug or -d Print diagnostic and debugging messages to stderr. --help or -h Display a brief help message. --template=<template> or -t Format the messages using the specified template. --verbose or -v Print verbose messages to stderr. --version or -V Display version information. Example:./dqtool cat ../var/syslog-ng-00000.qf The output looks like: Disk-buffer state loaded; filename='../var/syslog-ng-00000.qf', qout_length='65', qbacklog_length='0', qoverflow_length='9205', qdisk_length='0' Mar 3 10:52:05 tristram localprg[1234]: seq: 0000011630, runid: 1267609923, stamp: 2010-03-03T10:52:05 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD Mar 3 10:52:05 tristram localprg[1234]: seq: 0000011631, runid: 1267609923, stamp: 2010-03-03T10:52:05 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD Files /opt/syslog-ng/bin/dqtool See also syslog-ng.conf(5) syslog-ng(8) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/loggen.1.xml000066400000000000000000000367661450431004300210510ustar00rootroot00000000000000 The loggen manual page loggen 1 4.4 loggen Generate syslog messages at a specified rate loggen options target port Description NOTE: The loggen application is distributed with the syslog-ng system logging application, and is usually part of the syslog-ng package. The latest version of the syslog-ng application is available at the official syslog-ng website. This manual page is only an abstract, for the complete documentation of syslog-ng, see The syslog-ng Administrator Guide. The loggen application is tool to test and stress-test your syslog server and the connection to the server. It can send syslog messages to the server at a specified rate, using a number of connection types and protocols, including TCP, UDP, and unix domain sockets. The messages can be generated automatically (repeating the PADDstring over and over), or read from a file or the standard input. When loggen finishes sending the messages, it displays the following statistics: average rate: Average rate the messages were sent in messages/second. count: The total number of messages sent. time: The time required to send the messages in seconds. average message size: The average size of the sent messages in bytes. bandwidth: The average bandwidth used for sending the messages in kilobytes/second. Options --active-connections <number-of-connections> Number of connections loggen will use to send messages to the destination. This option is usable only when using TCP or TLS connections to the destination. Default value: 1 The loggen utility waits until every connection is established before starting to send messages. See also the --idle-connections option. --csv or -C Send the statistics of the sent messages to stdout as CSV. This can be used for plotting the message rate. --dgram or -D Use datagram socket (UDP or unix-dgram) to send the messages to the target. Requires the --inet option as well. --dont-parse or -d Do not parse the lines read from the input files, send them as received. --help or -h Display a brief help message. --idle-connections <number-of-connections> Number of idle connections loggen will establish to the destination. Note that loggen will not send any messages on idle connections, but the connection is kept open using keep-alive messages. This option is usable only when using TCP or TLS connections to the destination. See also the --active-connections option. Default value: 0 --inet or -i Use the TCP (by default) or UDP (when used together with the --dgram option) protocol to send the messages to the target. --interval <seconds> or -I <seconds> The number of seconds loggen will run. Default value: 10 Note that when the --interval and --number are used together, loggen will send messages until the period set in --interval expires or the amount of messages set in --number is reached, whichever happens first. --ipv6 or -6 Specify the destination using its IPv6 address. Note that the destination must have a real IPv6 address. --loop-reading or -l Read the file specified in --read-file option in loop: loggen will start reading from the beginning of the file when it reaches the end of the file. --number <number-of-messages> or -n <number-of-messages> Number of messages to generate. Note that when the --interval and --number are used together, loggen will send messages until the period set in --interval expires or the amount of messages set in --number is reached, whichever happens first. --no-framing or -F Do not use the framing of the IETF-syslog protocol style, even if the syslog-proto option is set. --quiet or -Q Output statistics only when the execution of loggen is finished. If not set, the statistics are displayed every second. --permanent or -T Keep sending logs indefinitely, without time limit. --rate <message/second> or -r <message/second> The number of messages generated per second for every active connection. Default value: 1000 --read-file <filename> or -R <filename> Read the messages from a file and send them to the target. See also the --skip-tokens option. Specify - as the input file to read messages from the standard input (stdio). Note that when reading messages from the standard input, loggen can only use a single thread. The -R - parameters must be placed at end of command, like: loggen 127.0.0.1 1061 --read-file - --sdata <data-to-send> or -p <data-to-send> Send the argument of the --sdata option as the SDATA part of IETF-syslog (RFC5424 formatted) messages. Use it together with the --syslog-proto option. For example: --sdata "[test name=\"value\"] --size <message-size> or -s <message-size> The size of a syslog message in bytes. Default value: 256. Minimum value: 127 bytes, maximum value: 8192 bytes. --skip-tokens <number> Skips the specified number of space-separated tokens (words) at the beginning of every line. For example, if the messages in the file look like foo bar message, --skip-tokens 2 skips the foo bar part of the line, and sends only the message part. Works only when used together with the --read-file parameter. Default value: 0 --stream or -S Use a stream socket (TCP or unix-stream) to send the messages to the target. --syslog-proto or -P Use the new IETF-syslog message format as specified in RFC5424. By default, loggen uses the legacy BSD-syslog message format (as described in RFC3164). See also the --no-framing option. --unix </path/to/socket> or -x </path/to/socket> Use a UNIX domain socket to send the messages to the target. --use-ssl or -U Use an SSL-encrypted channel to send the messages to the target. Note that it is not possible to check the certificate of the target, or to perform mutual authentication. --version or -V Display version number of syslog-ng. Examples The following command generates 100 messages per second for ten minutes, and sends them to port 2010 of the localhost via TCP. Each message is 300 bytes long. loggen --stream --size 300 --rate 100 --interval 600 127.0.0.1 2010 The following command is similar to the one above, but uses the UDP protocol. loggen --inet --dgram --size 300 --rate 100 --interval 600 127.0.0.1 2010 Send a single message on TCP6 to the ::1 IPv6 address, port 1061: loggen --ipv6 --number 1 ::1 1061 Send a single message on UDP6 to the ::1 IPv6 address, port 1061: loggen --ipv6 --dgram --number 1 ::1 1061 Send a single message using a unix domain-socket: loggen --unix --stream --number 1 </path/to/socket> Read messages from the standard input (stdio) and send them to the localhost: loggen 127.0.0.1 1061 --read-file - Files /opt/syslog-ng/bin/loggen See also syslog-ng.conf(5) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/pdbtool.1.xml000066400000000000000000000553201450431004300212240ustar00rootroot00000000000000 The pdbtool manual page pdbtool 1 4.4 pdbtool An application to test and convert syslog-ng pattern database rules pdbtool command options Description This manual page is only an abstract, for the complete documentation of syslog-ng and pdbtool, see The syslog-ng Administrator Guide. The syslog-ng application can match the contents of the log messages to a database of predefined message patterns (also called patterndb). By comparing the messages to the known patterns, syslog-ng is able to identify the exact type of the messages, tag the messages, and sort them into message classes. The message classes can be used to classify the type of the event described in the log message. The functionality of the pattern database is similar to that of the logcheck project, but the syslog-ng approach is faster, scales better, and is much easier to maintain compared to the regular expressions of logcheck. The pdbtool application is a utility that can be used to: test messages, or specific rules convert an older pattern database to the latest database format merge pattern databases into a single file automatically create pattern databases from a large amount of log messages dump the RADIX tree built from the pattern database (or a part of it) to explore how the pattern matching works. The dictionary command dictionary options Lists every name-value pair that can be set by the rules of the pattern database. --dump-tags or -T List the tags instead of the names of the name-value pairs. --pdb <path-to-file> or -p <path-to-file> Name of the pattern database file to use. --program <programname> or -P <programname> List only the name-value pairs that can be set for the messages of the specified $PROGRAM application. The dump command dump options Display the RADIX tree built from the patterns. This shows how are the patterns represented in syslog-ng and it might also help to track down pattern-matching problems. The dump utility can dump the tree used for matching the PROGRAM or the MESSAGE parts. --debug or -d Enable debug/diagnostic messages on stderr. --pdb or -p Name of the pattern database file to use. --program or -P Displays the RADIX tree built from the patterns belonging to the ${PROGRAM} application. --program-tree or -T Display the ${PROGRAM} tree. --verbose or -v Enable verbose messages on stderr. Example and sample output:pdbtool dump -p patterndb.xml -P 'sshd''p' 'assword for' @QSTRING:@ 'from' @QSTRING:@ 'port ' @NUMBER:@ rule_id='fc49054e-75fd-11dd-9bba-001e6806451b' ' ssh' rule_id='fc55cf86-75fd-11dd-9bba-001e6806451b' '2' rule_id='fc4b7982-75fd-11dd-9bba-001e6806451b' 'ublickey for' @QSTRING:@ 'from' @QSTRING:@ 'port ' @NUMBER:@ rule_id='fc4d377c-75fd-11dd-9bba-001e6806451b' ' ssh' rule_id='fc5441ac-75fd-11dd-9bba-001e6806451b' '2' rule_id='fc44a9fe-75fd-11dd-9bba-001e6806451b' The match command match options Use the match command to test the rules in a pattern database. The command tries to match the specified message against the patterns of the database, evaluates the parsers of the pattern, and also displays which part of the message was parsed successfully. The command returns with a 0 (success) or 1 (no match) return code and displays the following information: the class assigned to the message (that is, system, violation, and so on), the ID of the rule that matched the message, and the values of the parsers (if there were parsers in the matching pattern). The match command has the following options: --color-out or -c Color the terminal output to highlight the part of the message that was successfully parsed. --debug or -d Enable debug/diagnostic messages on stderr. --debug-csv or -C Print the debugging information returned by the --debug-pattern option as comma-separated values. --debug-pattern or -D Print debugging information about the pattern matching. See also the --debug-csv option. --file=<filename-with-path> or -f Process the messages of the specified log file with the pattern database. This option allows one to classify messages offline, and to apply the pattern database to already existing logfiles. To read the messages from the standard input (stdin), specify a hyphen (-) character instead of a filename. --filter=<filter-expression> or -F Print only messages matching the specified syslog-ng filter expression. --message or -M The text of the log message to match (only the ${MESSAGE} part without the syslog headers). --pdb or -p Name of the pattern database file to use. --program or -P Name of the program to use, as contained in the ${PROGRAM} part of the syslog message. --template=<template-expression> or -T A syslog-ng template expression that is used to format the output messages. --verbose or -v Enable verbose messages on stderr. Example: The following command checks if the patterndb.xml file recognizes the Accepted publickey for myuser from 127.0.0.1 port 59357 ssh2 message: pdbtool match -p patterndb.xml -P sshd -M "Accepted publickey for myuser from 127.0.0.1 port 59357 ssh2" The following example applies the sshd.pdb pattern database file to the log messages stored in the /var/log/messages file, and displays only the messages that received a useracct tag. pdbtool match -p sshd.pdb \ –file /var/log/messages \ –filter ‘tags(“usracct”);’ The merge command merge options Use the merge command to combine separate pattern database files into a single file (pattern databases are usually stored in separate files per applications to simplify maintenance). If a file uses an older database format, it is automatically updated to the latest format (V3). See the The syslog-ng Administrator Guide for details on the different pattern database versions. --debug or -d Enable debug/diagnostic messages on stderr. --directory or -D The directory that contains the pattern database XML files to be merged. --glob or -G Specify filenames to be merged using a glob pattern, for example, using wildcards. For details on glob patterns, see man glob. This pattern is applied only to the filenames, and not on directory names. --pdb or -p Name of the output pattern database file. --recursive or -r Merge files from subdirectories as well. --verbose or -v Enable verbose messages on stderr. Example:pdbtool merge --recursive --directory /home/me/mypatterns/ --pdb /var/lib/syslog-ng/patterndb.xmlCurrently it is not possible to convert a file without merging, so if you only want to convert an older pattern database file to the latest format, you have to copy it into an empty directory. The patternize command patternize options Automatically create a pattern database from a log file containing a large number of log messages. The resulting pattern database is printed to the standard output (stdout). The pdbtool patternize command uses a data clustering technique to find similar log messages and replacing the differing parts with @ESTRING:: @ parsers. For details on pattern databases and message parsers, see the The syslog-ng Administrator Guide. The patternize command is available only in version 3.2 and later. --debug or -d Enable debug/diagnostic messages on stderr. --file=<path> or -f The logfile containing the log messages to create patterns from. To receive the log messages from the standard input (stdin), use -. --iterate-outliers or -o Recursively iterate on the log lines to cover as many log messages with patterns as possible. --named-parsers or -n The number of example log messages to include in the pattern database for every pattern. Default value: 1 --no-parse or -p Do not parse the input file, treat every line as the message part of a log message. --samples=<number-of-samples> Include a generated name in the parsers, for example, .dict.string1, .dict.string2, and so on. --support=<number> or -S A pattern is added to the output pattern database if at least the specified percentage of log messages from the input logfile match the pattern. For example, if the input logfile contains 1000 log messages and the --support=3.0 option is used, a pattern is created only if the pattern matches at least 3 percent of the log messages (that is, 30 log messages). If patternize does not create enough patterns, try to decrease the support value. Default value: 4.4 --verbose or -v Enable verbose messages on stderr. Example:pdbtool patternize --support=2.5 --file=/var/log/messages The test command test options Use the test command to validate a pattern database XML file. Note that you must have the xmllint application installed. The test command is available only in version 3.2 and later. --color-out or -c Enable coloring in terminal output. --debug or -d Enable debug/diagnostic messages on stderr. --debug or -D Print debugging information on non-matching patterns. --rule-id or -r Test only the patterndb rule (specified by its rule id) against its example. --validate Validate a pattern database XML file. --verbose or -v Enable verbose messages on stderr. Example:pdbtool test --validate /home/me/mypatterndb.pdb Files /opt/syslog-ng/ /opt/syslog-ng/etc/syslog-ng.conf See also The syslog-ng Administrator Guide syslog-ng.conf(5) syslog-ng(8) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/persist-tool.1.xml000066400000000000000000000167711450431004300222340ustar00rootroot00000000000000 The persist-tool tool manual page persist-tool 1 4.4 persist-tool Display the content of the persist file persist-tool command options Description NOTE: The persist-tool application is distributed with the syslog-ng system logging application, and is usually part of the syslog-ng package. The latest version of the syslog-ng application is available at the official syslog-ng website. This manual page is only an abstract, for the complete documentation of syslog-ng, see the The syslog-ng Administrator Guide. The persist-tool application is a utility that can be used to dump the content of the persist file, and manipulate its content. Persist-tool is a special tool for syslog-ng experts. Do use the tool unless you know exactly what you are doing. Misconfiguring it will result in irrecoverable damage to the persist file, without any warning. Limitations: The persist-state functions can be used only with syslog-ng PE 5 LTS style persist file (SLP4). Older persist files are not supported. Wildcard characters are not supported in file/directory names. The dump command dump options persist_file Use the dump command to print the current content of the persist file in JSON format to the console. The dump command has the following options: --help or -? Display a brief help message. Example: persist-tool dump /opt/syslog-ng/var/syslog-ng.persist The output looks like: run_id = { "value": "00 00 00 00 0C 00 00 00 " } host_id = { "value": "00 00 00 00 5F 49 2F 01 " } The add command add options input_file Use the add command to add or modify a specified state-entry in the persist file. The state-entry should be in the same format as the dump command displays it. If the given state-entry already exists, it will be updated. Otherwise, a new value will be added. If the given persist state is invalid, it will be skipped. To use the add command: use persist-tool dump to print the content of the current persist file, and redirect it to a file. Edit the content of this file. Use persist-tool add with this file to modify the persist. The add command has the following options: --help or -? Display a brief help message. --output-dir=<directory> or -o Required parameter. The directory where the persist file is located at. The name of the persist file stored in this directory must be syslog-ng.persist. Example:/opt/syslog-ng/bin/persist-tool add dump_persist -o . The valid output looks like: log_reader_curpos(Application) OK affile_sd_curpos(/var/aaa.txt) OK The invalid output looks like: log_reader_curpos(Application) OK wrong FAILED (error: Invalid entry syntax) affile_sd_curpos(/var/aaa.txt) OK Files /opt/syslog-ng/bin/persist-tool See also syslog-ng.conf(5) syslog-ng(8) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/secure-logging.7.xml000066400000000000000000000624471450431004300225110ustar00rootroot00000000000000 The secure logging manual page secure-logging 7 4.4 secure-logging Forward integrity and confidentiality for system logs $(slog --key-file <host key file> --mac-file <MAC file> $RAWMSG) Description Secure logging is an extension to syslog-ng providing forward integrity and confidentiality of system logs. It is implemented in form of a module and is configured as a template in the syslog-ng configuration file. The main objective of the secure logging module is to provide tamper evident logging, i.e. to adequately protect log records of an information system and to provide a sensor indicating attack attempts. The secure logging module achieves this by authentically encrypting each log record with an individual cryptographic key used only once and protecting the integrity of the whole log archive by a cryptographic authentication code. Each attempt to tamper with either an individual log record or the log archive itself will be immediately detected during log archive verification. Therefore, an attacker can no longer tamper with log records without being detected. In order to use the log file created by the secure logging module for analysis, the log file must first be decrypted and its integrity verified. This is achieved with a command line utility that is part of the secure logging module and is installed as part of the syslog-ng package. This utility can easily be integrated into the import module of existing analysis environments. The secure logging environment uses a cryptographic key for encrypting log entries. Each individual log entry is encrypted with its own key which is immediately discarded after successful encryption in order to provide forward integrity. An efficient algorithm generates the key for the next log entry based the key used for encrypting the previous log entry. The resulting chain of keys preserves forward integrity, i.e. a potential attacker cannot deduce the previous key from the current key. In order to ease log verification and analysis, a sequence number is added to each log entry. This sequence number is also added to the encryption key creating a one-to-one correspondence of the encryption key with the log entry. In order to prevent truncation attacks or deletion of individual log entries, a message authentication code (MAC) is iteratively applied to the complete log archive and stored in a separate file. It is used upon verification to check the integrity of the whole log archive. Here is an example of three short original log messages that will be sent to a destination with secure logging enabled: In order to inspect the status of the secure logging environment, one can check the sequence counter by querying the key file with the slogkey utility like this: slogkey --counter /etc/syslog-ng/host.key counter=3 ]]> Counting starts at zero. This is why the counter is set to three after processing three messages. The output of the secure logging template for the three example messages is shown below. One clearly sees the sequence number that was prepended to each message. The colon indicates the end of the sequence number and the start of the original message. As three message were processed, the sequence counter of the key will be three. The output of a successful verification run is shown below. The original log messages have been successfully restored. Additionally, the sequence counter is also prepended to the clear text messages. This helps when in analyzing problems with a particular log entry. As real log files will contain thousands of entries. the sequence counter eases identification of erroneous entries. Before the secure logging module can be used as part of an existing syslog-ng installation, several preparatory activities need to be performed. Key generation In order to bootstrap the system, an initial key k0 must be created and installed on the log host before secure logging environment is started for the first time. The newly created host key k0 has its counter set to 0 indicating that it represents the initial host key k0. This host key k0 must be kept secret and not be disclosed to third parties. It will be required to successfully decrypt and verify log archives processed by the secure logging environment. As each log entry will be encrypted with its own key, a new host key will be created after successful processing of a log entry and will replace the previous key. Therefore, the initial host key needs to be stored in a safe place before starting the secure logging environment, as it will be deleted from the log host after processing of the first log entry. The following steps must be done before starting the secure logging environment. Steps 1 and 2 are performed with the slogkey utility. See slogkey(1) for details on how to generate a master key and to derive a host key from it. Step 3 and 4 depend on the actual deployment in a target environment. Create a master key Derive an initial host key k0 from a previously created master key Store the initial host key k0 in a safe location outside of the log host Deploy the key k0 on the log host where the secure logging module will be used Configuration Secure logging is configured by adding the corresponding statements to the syslog-ng.conf file. See syslog-ng.conf(5) for information on how to configure syslog-ng using the configuration file. Details can be found in the The syslog-ng Administrator Guide. Secure logging is implemented as a template and is configured accordingly. Apart from the actual template configuration, no other settings are required in order to activate secure logging. The secure logging is activated by placing the following statement in the configuration file template("$(slog --key-file <host key file> --mac-file <MAC file> $RAWMSG)\n"); where slog The name of the secure logging template function. This name can be also be found by calling syslog-ng with the --module-registry arguments and checking the template-func property of the secure logging module in the corresponding output. --key-file or -k The host key. <host key file> is the full path of the file storing the host key on the log host. If this arguments is not supplied or does not point to a valid regular key file, syslog-ng will not start and a display a corresponding error message. --mac-file or -m The MAC file. <MAC file> is the full path of the MAC file on the log host. The file does not need to exist, as it will be automatically created upon the initial start. If the path is not correct, syslog-ng will not start and a display a corresponding error message. $RAWMSG $RAWMSG provides access to the original log message received at the source. This macro is only available if the store-raw-message flag was set for the source. Otherwise, an empty string will be passed to the secure logging template. If access to the original message is not available, e.g. if the source does not support the store-raw-message flag, then the $MSG macro can also be used. In this case, however, the integrity guarantee provided by secure logging is limited to the content that this macro provides and does not protect the complete original message. \n \n is the line separator. This is important, as the secure logging template expects log entries to be separated by a line separator. When detecting a line separator, the log entry is regarded as complete and is encrypted with the current host key. Therefore, only a single line separator is allowed. The secure logging template can be combined with any source or destination within the following limitations: Sources must be line-oriented. Secure logging uses a line separator in order to distinguish between individual log entries. Sources which provide data in a different format, e.g. in the form of raw data obtained directly from a database system, cannot currently be used with the secure logging template, as the separation of log entries is not clearly defined for this type of data. Only sources for which the store-raw-message flag is implemented and set do benefit from the integrity guarantee provided by the secure logging template. Secure logging aims at protecting the integrity of complete log messages including all associated meta-data, such as timestamps and host names. syslog-ng parses the log message into its internal format and provide easy access to parts of a message through macros. While this is convenient when rewriting log messages, it is not helpful for secure logging. syslog-ng provides the store-raw-message flag which provides access to a copy of the original log message after parsing. This is the log message processed and protected by the secure logging template. If the source does not support the store-raw-message flag, then the $MSG macro can also be used. However, in this case the integrity guarantee provided by secure logging is limited to the content that this macro provides. Log rotation of any kind cannot be used with destinations using secure logging. The reason is that log rotate will overwrite, i.e. delete previous log files. This destroys the cryptographic chain of trust of the log entries making recovery impossible. In order to allow for a an efficient handling of log files, the secure logging environment features iterative verification. Using iterative verification, a log file can be verified in steps. For this to work, the log file must first be downloaded from the log host, together with the corresponding host key and MAC file to a verification host. After this download the log file can be safely deleted from the log host. Verification is then performed on the verification host using the iterative mode of the slogverify utility. See slogverify(1) for details. The following example configuration shows the use of the secure logging template on a file destination. Log Verification In order to analyze the log file created in a secure logging environment, the log files must be decrypted and their integrity be verified. Verification requires both the initial host key k0 and the corresponding MAC file and is performed with the slogverify utility. It is not normally performed on the log host where the secure logging environment is producing log data. In a typical deployment, log files would be retrieved from the log host and transferred to a central log collector where verification it performed. As verification requires the use of the initial host key k0, it should only be performed in a trusted environment. Normal mode In normal mode, a complete log archive is verified at once. In a typical environment, this would mean retrieving a log file together with is MAC file from a log host and retrieving the corresponding initial key k0 form a safe location and supplying them to the slogverify utility. A typical call sequence for verification in normal mode would look like this slogverify --key-file host0.key --mac-file mac.dat /var/log/messages.slog /var/log/verified/messages with host0.key The initial host key k0. Supplying the initial key k0 is enough for decrypting all log entries, as the key derivation algorithm is able to generate the necessary keys for all subsequent log entries based on the initial key k0. mac.dat The MAC file from the log host. /var/log/messages.slog The file containing the encrypted log entries as retrieved from a log host. /var/log/verified/messages The file receiving the plain text log after decryption. Log files may become large and not fit into system memory. Verification is therefore performed in chunks. Each part of the log file is transferred to an internal buffer on which verification is performed. After the buffer has been processed, the next chunk is fetched. An optional buffer argument can be supplied to the slogverify utility in order to change the default buffer size of 1000 log entries to a number suitable for the system on which the verification is performed, for example slogverify --key-file host.key --mac-file mac.dat /var/log/messages.slog /var/log/verified/messages 8000 See slogverify(1) for details on verification in normal mode. Iterative mode Verification in normal mode may not be suitable for some application scenarios. Many log hosts use log rotation in order to preserve storage space. In log rotation, a threshold for the maximum amount of storage space and the number of generations is defined for different type of log files. When either storage space is exhausted or the number of generations is reached, the oldest log file will be overwritten by new incoming log data. This procedure is not possible in secure logging environment, as overwriting, i.e. deleting a log file would break the cryptographic chain that is established between the log entries. This comes as no surprise, as one of the main objectives of secure logging is to protect against deletion of log entries by a potential attacker. In order allow for a procedure similar to log rotation, the secure logging environment features an iterative mode. In iterative mode, log files can be split into different files and each of these files can be verified separately. Care must be taken when performing verification in iterative mode, as each of the different log files needs to be accompanied by a copy of the host key and the MAC files present on the system at the time of retrieval. A typical usage scenario for the iterative mode would look like this: Define a storage threshold for the secure logging file destination. In this example we assume 500MB. Let the secure logging environment produce log data that is written to the destination until 500MB are reached. Stop the secure logging environment and retrieve the log file, the host key and the MAC files from the log host. Delete the log file on the log host but leave host key and MAC file untouched. Restart the secure logging environment. Perform verification in iterative mode with the log file, the host key and the MAC just retrieved. Steps 2-6 have to repeated each time the log file reaches a size of 50 MB. Assuming that the log file parts will be named after the iteration, e.g. log.1, log.2, log.3, etc. and a similar convention is applied to the host keys and MAC files, a typical call sequence for the validation of a log file part in iterative mode after three iterations will look like this: slogverify --iterative --prev-key-file host.key.2 --prev-mac-file mac.dat.2 --mac-file mac.dat /var/log/messages.slog.3 /var/log/verified/messages.3 with host.key.2 The host key from the previous iteration. In this example, this is the second iteration. mac.dat.2 The MAC file from the previous iteration. In the example, verification is performed during the third iteration, so the MAC file from the second iteration is required. mac.dat The current MAC file from the log host. /var/log/messages.slog.3 The file part containing the encrypted log entries as retrieved from the log host during the third iteration. /var/log/verified/messages.3 The file receiving the plain text log after decryption during the third iteration. In a real deployment, the above steps would typically be automated using a scripting engine. See slogverify(1) for details on verification in iterative mode. Files /usr/bin/slogkey /usr/bin/slogencrypt /usr/bin/slogverify /etc/syslog-ng.conf See also syslog-ng.conf(5) slogkey(1) slogencrypt(1) slogverify(1) For the detailed documentation of see The syslog-ng Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. For specific information requests related to secure logging send a mail to the Airbus Secure Logging Team <secure-logging@airbus.com>. Author This manual page was written by the Airbus Secure Logging Team <secure-logging@airbus.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/slogencrypt.1.xml000066400000000000000000000136041450431004300221310ustar00rootroot00000000000000 The slogencrypt manual page slogencrypt 1 4.4 slogencrypt Encrypt existing plain text log files using the syslog-ng secure logging environment slogencrypt optionsarguments Description The slogencrypt is used to encrypt plain text log file using an existing secure logging environment. Using this utility, log files obtained from a previous installation of syslog-ng or another logging system can be transferred to a secure logging environment. The order of the log entries is preserved. Encrypting plain text log files using an existing secure logging environment, requires the current encryption key to be supplied in order to preserve consistency. General call sequence: slogencrypt -k <key file> -m <MAC file> <new key file> <new MAC file> <plain text log> <output file> [counter] Arguments new key file The file that will contain the new current encryption key after successful encryption. new MAC file The file receiving the new current message authentication code (MAC) of the secure encrypted destination after encryption. In case an existing file is supplied, new entries will be appended. input log file The plain text log file that will be encrypted using the secure logging environment. output log file The file that will contain the encrypted log entries from the supplied plain text log file after encryption. counter The current log entry counter of the secure encrypted destination after encryption. This is required if the log entries to be encrypted will be appended to an existing secure encrypted destination. Options --key-file or -k The current host key from the system where the encryption will be performed. --mac-file or -m The current MAC file from the system where the encryption will be performed. --help or -h Display a help message. Files /usr/bin/slogencrypt /etc/syslog-ng.conf See also syslog-ng.conf(5) secure-logging(7) For the detailed documentation of see The syslog-ng Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. For specific information requests related to secure logging send a mail to the Airbus Secure Logging Team <secure-logging@airbus.com>. Author This manual page was written by the Airbus Secure Logging Team <secure-logging@airbus.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/slogkey.1.xml000066400000000000000000000152131450431004300212330ustar00rootroot00000000000000 The slogkey manual page slogkey 1 4.4 slogkey Manage cryptographic keys for use with syslog-ng secure logging slogkey optionsarguments Description The slogkey utility is used to manage cryptographic keys for use with the secure logging module of syslog-ng. Use this utility to create a master key, derive a host key to be used by a secure logging configuration and to display the current sequence counter of a key. The options determine the operating mode and are mutually exclusive. Arguments The arguments depend on the operating mode. Master key generation Call sequence: slogkey --master-ḱey <filename> <filename>: The name of the file to which the master key will be written. Host key derivation Call sequence: slogkey --derive-key <master key file> <host MAC address> <host serial number> <host key file> <master key file>: The master key from which the host key will be derived. <host MAC address>: The MAC address of the host on which the key will be used. Instead of the MAC address, any other string that uniquely identifies a host can be supplied, e.g. the company inventory number. <host serial number>: The serial number of the host on which the key will be used. Instead of the serial number, any other string that uniquely identifies a host can be supplied, e.g. the company inventory number. <host key file>: The name of the file to which the host key will be written. NOTE: The newly created host key has its counter set to 0 indicating that it represents the initial host key k0. This host key must be kept secret and not be disclosed to third parties. It will be required to successfully decrypt and verify log archives processed by the secure logging environment. As each log entry will be encrypted with its own key, a new host key will be created after successful processing of a log entry and will replace the previous key. Therefore, the initial host key needs to be stored in a safe place before starting the secure logging environment, as it will be deleted from the log host after processing of the first log entry. Sequence counter display Call sequence: slogkey --counter <host key file> <host key file>: The host key file from which the sequence will be read. Options --master-key or -m Generates a mew master key. <filename> is the name of the file storing the newly generated master key. --derive-key or -d Derive a host key using a previously generated master key. --counter or -c Display the current log sequence counter of a key. --help or -h Display a help message. Files /usr/bin/slogkey /etc/syslog-ng.conf See also syslog-ng.conf(5) secure-logging(7) For the detailed documentation of see The syslog-ng Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. For specific information requests related to secure logging send a mail to the Airbus Secure Logging Team <secure-logging@airbus.com>. Author This manual page was written by the Airbus Secure Logging Team <secure-logging@airbus.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/slogverify.1.xml000066400000000000000000000160001450431004300217420ustar00rootroot00000000000000 The slogverify manual page slogverify 1 4.4 slogverify Verify cryptographically secured logs slogverify options input file output file buffers Description The slogverify utility is used to verify the integrity of cryptographically secured logs and to decrypt log entries produced in a syslog-ng secure logging environment. Normal mode: slogverify -k <host key file> -m <input MAC file> <input file> <output file> [buffers] Iterative mode: slogverify -i -p <previous host key> -r <previous MAC> -m <current MAC> <input file> <output file> [buffers] Arguments input file An encrypted log file from the syslog-ng secure logging environment that will be verified. output file The file that will contain the plain text log entries after decryption and verification. buffers Optional number of input buffers. The number of buffers can be used for performance adjustments in case the log file to be verified is very large and cannot be processed at once. It is a positive number of log entries that can be held in memory during verification. The minimum number if 10 and the maximum number is 4294967295. If this argument is not supplied the default of 1000 is used. Options --iterative or -i Iterative mode. This is useful in case the log files are periodically copied from the system on which they where generated to central collector. As log rotation, i.e. overwriting log files in order to preserve space cannot be done in a secure logging environment, the iterative mode can be used instead. This works as follows: If a certain storage limit is reached the log file together with the host key and the MAC file is copied to new destination and the old file is deleted. The verification is then performed in iterations, i.e. separately for each file that was retrieved from the log host. For this to work, it is important to always retrieve the corresponding host key and MAC files. The process can be automated, e.g. by calling slogverify in iterative mode from a script. --key-file or -k The initial host key (k0). This option is used in normal mode only. --mac-file or -m The current MAC file used. --prev-key-file or -p The host key corresponding to the previous log file. This option can be used in iterative mode only. In theory, this can be initial host key (k0) but using this key might generate warnings, as the gap between the first log entry ever (log entry 0) and the first log entry of the current log file might be large. --prev-mac-file or -r The MAC file from the previous log file. This option can only be used in iterative mode. --help or -h Display a help message. Files /usr/bin/slogverify /etc/syslog-ng.conf See also syslog-ng.conf(5) secure-logging(7) For the detailed documentation of see The syslog-ng Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. For specific information requests related to secure logging send a mail to the Airbus Secure Logging Team <secure-logging@airbus.com>. Author This manual page was written by the Airbus Secure Logging Team <secure-logging@airbus.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/syslog-ng-ctl.1.xml000066400000000000000000000216401450431004300222610ustar00rootroot00000000000000 The syslog-ng control tool manual page syslog-ng-ctl 1 4.4 syslog-ng-ctl Display message statistics and enable verbose, debug and trace modes in syslog-ng-ctl command options Description NOTE: The syslog-ng-ctl application is distributed with the system logging application, and is usually part of the syslog-ng package. The latest version of the syslog-ng application is available at the official syslog-ng website. This manual page is only an abstract, for the complete documentation of syslog-ng, see The Administrator Guide. The syslog-ng-ctl application is a utility that can be used to: enable/disable various syslog-ng messages for troubleshooting display statistics about the processed messages reload the configuration of . Enabling troubleshooting messages command options Use the syslog-ng-ctl <command> --set=on command to display verbose, trace, or debug messages. If you are trying to solve configuration problems, the verbose (and occasionally trace) messages are usually sufficient. Debug messages are needed mostly for finding software errors. After solving the problem, do not forget to turn these messages off using the syslog-ng-ctl <command> --set=off. Note that enabling debug messages does not enable verbose and trace messages. Use syslog-ng-ctl <command> without any parameters to display whether the particular type of messages are enabled or not. If you need to use a non-standard control socket to access syslog-ng, use the syslog-ng-ctl <command> --set=on --control=<socket> command to specify the socket to use. verbose Print verbose messages. If syslog-ng was started with the --stderr or -e option, the messages will be sent to stderr. If not specified, syslog-ng will log such messages to its internal source. trace Print trace messages of how messages are processed. If syslog-ng was started with the --stderr or -e option, the messages will be sent to stderr. If not specified, syslog-ng will log such messages to its internal source. debug Print debug messages. If syslog-ng was started with the --stderr or -e option, the messages will be sent to stderr. If not specified, syslog-ng will log such messages to its internal source. Example:syslog-ng-ctl verbose --set=on The stats command stats options Use the stats command to display statistics about the processed messages. The stats command has the following options: --control=<socket> or -c Specify the socket to use to access syslog-ng. Only needed when using a non-standard socket. --reset or -r Reset all statistics to zero, except for the stored counters. (The stored counters show the number of messages stored in the message queue of the destination driver, waiting to be sent to the destination.) Example:syslog-ng-ctl stats An example output: src.internal;s_all#0;;a;processed;6445 src.internal;s_all#0;;a;stamp;1268989330 destination;df_auth;;a;processed;404 destination;df_news_dot_notice;;a;processed;0 destination;df_news_dot_err;;a;processed;0 destination;d_ssb;;a;processed;7128 destination;df_uucp;;a;processed;0 source;s_all;;a;processed;7128 destination;df_mail;;a;processed;0 destination;df_user;;a;processed;1 destination;df_daemon;;a;processed;1 destination;df_debug;;a;processed;15 destination;df_messages;;a;processed;54 destination;dp_xconsole;;a;processed;671 dst.tcp;d_network#0;10.50.0.111:514;a;dropped;5080 dst.tcp;d_network#0;10.50.0.111:514;a;processed;7128 dst.tcp;d_network#0;10.50.0.111:514;a;stored;2048 destination;df_syslog;;a;processed;6724 destination;df_facility_dot_warn;;a;processed;0 destination;df_news_dot_crit;;a;processed;0 destination;df_lpr;;a;processed;0 destination;du_all;;a;processed;0 destination;df_facility_dot_info;;a;processed;0 center;;received;a;processed;0 destination;df_kern;;a;processed;70 center;;queued;a;processed;0 destination;df_facility_dot_err;;a;processed;0 Reloading the configuration command options Use the syslog-ng-ctl reload command to reload the configuration file of without having to restart the application. The syslog-ng-ctl reload works like a SIGHUP. Files /opt/syslog-ng/sbin/syslog-ng-ctl See also The syslog-ng Administrator Guide syslog-ng.conf(5) syslog-ng(8) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/syslog-ng-debun.1.xml000066400000000000000000000265331450431004300226020ustar00rootroot00000000000000 The syslog-ng-debun manual page syslog-ng-debun 1 4.4 syslog-ng-debun syslog-ng DEBUg buNdle generator syslog-ng-debun options Description NOTE: The syslog-ng-debun application is distributed with the system logging application, and is usually part of the package. The latest version of the application is available at . This manual page is only an abstract, for the complete documentation of syslog-ng, see The syslog-ng Administrator Guide. The syslog-ng-debun tool collects and saves information about your installation, making troubleshooting easier, especially if you ask help about your related problem. General Options -r Run syslog-ng-debun. Using this option is required to actually execute the data collection with syslog-ng-debun. It is needed to prevent accidentally running syslog-ng-debun. -h Display the help page. -l Do not collect privacy-sensitive data, for example, process tree, fstab, and so on. If you use with -d, then the following parameters will be used for debug mode:-Fev -R <directory> The directory where is installed instead of /opt/syslog-ng. -W <directory> Set the working directory, where the debug bundle will be saved. Default value: /tmp. The name of the created file is syslog.debun.${host}.${date}.${3-random-characters-or-pid}.tgz Debug mode options -d Start in debug mode, using the -Fedv --enable-core options. Warning! Using this option under high message load may increase disk I/O during the debug, and the resulting debug bundle can be huge. To exit debug mode, press Enter. -D <options> Start in debug mode, using the specified command-line options. To exit debug mode, press Enter. For details on the available options, see . -t <seconds> Run in noninteractive debug mode for <seconds>, and automatically exit debug mode after the specified number of seconds. -w <seconds> Wait <seconds> seconds before starting debug mode. System call tracing -s Enable syscall tracing (strace -f or truss -f). Note that using -s itself does not enable debug mode, only traces the system calls of an already running process. To trace system calls in debug mode, use both the -s and -d options. Packet capture options Capturing packets requires a packet capture tool on the host. The syslog-ng-debun tool attempts to use tcpdump on most platforms, except for Solaris, where it uses snoop. -i <interface> Capture packets only on the specified interface, for example, eth0. -p Capture incoming packets using the following filter: port 514 or port 601 or port 53 -P <options> Capture incoming packets using the specified filter. -t <seconds> Run in noninteractive debug mode for <seconds>, and automatically exit debug mode after the specified number of seconds. Examples syslog-ng-debun -r Create a simple debug bundle, collecting information about your environment, for example, list packages containing the word: syslog, ldd of your syslog-binary, and so on. syslog-ng-debun -r -l Similar to syslog-ng-debun -r, but without privacy-sensitive information. For example, the following is NOT collected: fstab, df output, mount info, ip / network interface configuration, DNS resolv info, and process tree. syslog-ng-debun -r -d Similar to syslog-ng-debun -r, but it also stops syslog-ng, then restarts it in debug mode (-Fedv --enable-core). To stop debug mode, press Enter. The output of the debug mode collected into a separate file, and also added to the debug bundle. syslog-ng-debun -r -s Trace the system calls (using strace or truss) of an already running process. syslog-ng-debun -r -d -s Restart in debug mode, and also trace the system calls (using strace or truss) of the process. syslog-ng-debun -r -p Run packet capture (pcap) with the filter: port 514 or port 601 or port 53 Also waits for pressing Enter, like debug mode. syslog-ng-debun -r -p -t 10 Noninteractive debug mode: Similar to syslog-ng-debun -r -p, but automatically exit after 10 seconds. syslog-ng-debun -r -P "host 1.2.3.4" -D "-Fev --enable-core" Change the packet-capturing filter from the default to host 1.2.3.4. Also change debugging parameters from the default to -Fev --enable-core. Since a timeout (-t) is not given, waits for pressing Enter. syslog-ng-debun -r -p -d -w 5 -t 10 Collect pcap and debug mode output following this scenario: Start packet capture with default parameters (-p) Wait 5 seconds (-w 5) Stop syslog-ng Start syslog-ng in debug mode with default parameters (-d) Wait 10 seconds (-t 10) Stop syslog-ng debugging Start syslog-ng Stop packet capturing Files /opt/syslog-ng/bin/loggen See also syslog-ng.conf(5) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/syslog-ng.8.xml000066400000000000000000000422561450431004300215160ustar00rootroot00000000000000 The syslog-ng manual page syslog-ng 8 4.4 syslog-ng syslog-ng system logger application syslog-ng options Description This manual page is only an abstract, for the complete documentation of syslog-ng, see The Administrator Guide or the official syslog-ng website. The application is a flexible and highly scalable system logging application. Typically, syslog-ng is used to manage log messages and implement centralized logging, where the aim is to collect the log messages of several devices on a single, central log server. The different devices - called syslog-ng clients - all run syslog-ng, and collect the log messages from the various applications, files, and other sources. The clients send all important log messages to the remote syslog-ng server, where the server sorts and stores them. Options --caps --caps caps Run process with the specified POSIX capability flags. If the --no-caps option is not set, and the host supports CAP_SYSLOG, uses the following capabilities: "cap_net_bind_service, cap_net_broadcast, cap_net_raw, cap_dac_read_search, cap_dac_override, cap_chown, cap_fowner=p cap_syslog=ep" If the --no-caps option is not set, and the host does not support CAP_SYSLOG, uses the following capabilities: "cap_net_bind_service, cap_net_broadcast, cap_net_raw,cap_dac_read_search, cap_dac_override, cap_chown, cap_fowner=p cap_sys_admin=ep" For example: /opt/syslog-ng/sbin/syslog-ng -Fv --caps cap_sys_admin,cap_chown,cap_dac_override,cap_net_bind_service,cap_fowner=pi Note that the capabilities are not case sensitive, the following command is also good: /opt/syslog-ng/sbin/syslog-ng -Fv --caps CAP_SYS_ADMIN,CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_NET_BIND_SERVICE,CAP_FOWNER=pi For details on the capability flags, see the following man pages: cap_from_text(3) and capabilities(7) --cfgfile <file> or -f <file> --cfgfile cfgfile Use the specified configuration file. --chroot <dir> or -C <dir> --chroot chroot Change root to the specified directory. The configuration file is read after chrooting so, the configuration file must be available within the chroot. That way it is also possible to reload the syslog-ng configuration after chrooting. However, note that the --user and --group options are resolved before chrooting. --control <file> or -c <file> Set the location of the syslog-ng control socket. Default value: /var/run/syslog-ng.ctl --debug or -d --debug debug Start syslog-ng in debug mode. --enable-core --enable-core enable-core Enable syslog-ng to write core files in case of a crash to help support and debugging. --fd-limit <number> --fd-limit fd-limit Set the minimal number of required file descriptors (fd-s). This sets how many files syslog-ng can keep open simultaneously. Default value: 4096. Note that this does not override the global ulimit setting of the host. --foreground or -F --foreground foreground Do not daemonize, run in the foreground. When running in the foreground, starts from the current directory ($CWD) so it can create core files (normally, starts from $PREFIX/var). --group <group> or -g <group> --group group Switch to the specified group after initializing the configuration file. --help or -h --help help Display a brief help message. --module-registry --module-registry module-registry Display the list and description of the available modules. Available only in and later. --no-caps --no-caps no-caps Run syslog-ng as root, without capability-support. This is the default behavior. On Linux, it is possible to run syslog-ng as non-root with capability-support if syslog-ng was compiled with the --enable-linux-caps option enabled. (Execute syslog-ng --version to display the list of enabled build parameters.) To run with specific capabilities, use the --caps option. --persist-file <persist-file> or -R <persist-file> --persist-file persist-file Set the path and name of the syslog-ng.persist file where the persistent options and data are stored. --pidfile <pidfile> or -p <pidfile> --pidfile pidfile Set path to the PID file where the pid of the main process is stored. --preprocess-into <output-file> --preprocess-into preprocess-into After processing the configuration file and resolving included files and variables, write the resulting configuration into the specified output file. Available only in and later. --process-mode <mode> --process-mode process-mode Sets how to run syslog-ng: in the foreground (mainly used for debugging), in the background as a daemon, or in safe-background mode. By default, syslog-ng runs in safe-background mode. This mode creates a supervisor process called supervising syslog-ng , that restarts syslog-ng if it crashes. --stderr or -e --stderr stderr Log internal messages of syslog-ng to stderr. Mainly used for debugging purposes in conjunction with the --foreground option. If not specified, syslog-ng will log such messages to its internal source. --syntax-only or -s --syntax-only syntax-only Verify that the configuration file is syntactically correct and exit. --user <user> or -u <user> --user user Switch to the specified user after initializing the configuration file (and optionally chrooting). Note that it is not possible to reload the syslog-ng configuration if the specified user has no privilege to create the /dev/log file. --verbose or -v --verbose verbose Enable verbose logging used to troubleshoot syslog-ng. --version or -V --version version Display version number and compilation information, and also the list and short description of the available modules. For detailed description of the available modules, see the --module-registry option. --worker-threads --worker-threads worker-threads Sets the number of worker threads can use, including the main thread. Note that certain operations in can use threads that are not limited by this option. This setting has effect only when is running in multithreaded mode. Available only in and later. See The 4.4 Administrator Guide for details. Files /opt/syslog-ng/ /opt/syslog-ng/etc/syslog-ng.conf See also syslog-ng.conf(5) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright syslog-ng-syslog-ng-4.4.0/doc/man/syslog-ng.conf.5.xml000066400000000000000000000620401450431004300224300ustar00rootroot00000000000000 The syslog-ng.conf manual page syslog-ng.conf 5 4.4 syslog-ng.conf syslog-ng configuration file syslog-ng.conf Description This manual page is only an abstract, for the complete documentation of syslog-ng, see The Administrator Guide or the official syslog-ng website. The application is a flexible and highly scalable system logging application. Typically, syslog-ng is used to manage log messages and implement centralized logging, where the aim is to collect the log messages of several devices on a single, central log server. The different devices - called syslog-ng clients - all run syslog-ng, and collect the log messages from the various applications, files, and other sources. The clients send all important log messages to the remote syslog-ng server, where the server sorts and stores them. Basic concepts of The syslog-ng application reads incoming messages and forwards them to the selected destinations. The syslog-ng application can receive messages from files, remote hosts, and other sources. destinations Log messages enter syslog-ng in one of the defined sources, and are sent to one or more destinations. log paths log statements log paths Sources and destinations are independent objects, log paths define what syslog-ng does with a message, connecting the sources to the destinations. A log path consists of one or more sources and one or more destinations: messages arriving from a source are sent to every destination listed in the log path. A log path defined in syslog-ng is called a log statement. filters Optionally, log paths can include filters. Filters are rules that select only certain messages, for example, selecting only messages sent by a specific application. If a log path includes filters, syslog-ng sends only the messages satisfying the filter rules to the destinations set in the log path. parsers rewrite rules Other optional elements that can appear in log statements are parsers and rewriting rules. Parsers segment messages into different fields to help processing the messages, while rewrite rules modify the messages by adding, replacing, or removing parts of the messages. Configuring syslog-ng The main body of the configuration file consists of object definitions: sources, destinations, logpaths define which log message are received and where they are sent. All identifiers, option names and attributes, and any other strings used in the syslog-ng configuration file are case sensitive. Object definitions (also called statements) have the following syntax: type-of-the-object identifier-of-the-object {<parameters>}; Type of the object: One of source, destination, log, filter, parser, rewrite rule, or template. Identifier of the object: A unique name identifying the object. When using a reserved word as an identifier, enclose the identifier in quotation marks. All identifiers, attributes, and any other strings used in the syslog-ng configuration file are case sensitive. Use identifiers that refer to the type of the object they identify. For example, prefix source objects with s_, destinations with d_, and so on. Repeating a definition of an object (that is, defining the same object with the same id more than once) is not allowed, unless you use the @define allow-config-dups 1 definition in the configuration file. Parameters: The parameters of the object, enclosed in braces {parameters}. Semicolon: Object definitions end with a semicolon (;). For example, the following line defines a source and calls it s_internal. source s_internal { internal(); }; The object can be later referenced in other statements using its ID, for example, the previous source is used as a parameter of the following log statement: log { source(s_internal); destination(d_file); }; The parameters and options within a statement are similar to function calls of the C programming language: the name of the option followed by a list of its parameters enclosed within brackets and terminated with a semicolon. option(parameter1, parameter2); option2(parameter1, parameter2); For example, the file() driver in the following source statement has three options: the filename (/var/log/apache/access.log), follow-freq(), and flags(). The follow-freq() option also has a parameter, while the flags() option has two parameters. source s_tail { file("/var/log/apache/access.log" follow-freq(1) flags(no-parse, validate-utf8)); }; Objects may have required and optional parameters. Required parameters are positional, meaning that they must be specified in a defined order. Optional parameters can be specified in any order using the option(value) format. If a parameter (optional or required) is not specified, its default value is used. The parameters and their default values are listed in the reference section of the particular object. Using required and optional parameters The unix-stream() source driver has a single required argument: the name of the socket to listen on. Optional parameters follow the socket name in any order, so the following source definitions have the same effect: source s_demo_stream1 { unix-stream("<path-to-socket>" max-connections(10) group(log)); }; source s_demo_stream2 { unix-stream("<path-to-socket>" group(log) max-connections(10)); }; Some options are global options, or can be set globally, for example, whether should use DNS resolution to resolve IP addresses. Global options are detailed in . options { use-dns(no); }; Objects can be used before definition. Objects can be defined inline as well. This is useful if you use the object only once (for example, a filter). For details, see . To add comments to the configuration file, start a line with # and write your comments. These lines are ignored by syslog-ng. # Comment: This is a stream source source s_demo_stream { unix-stream("<path-to-socket>" max-connections(10) group(log)); }; The syntax of log statements is as follows: log { source(s1); source(s2); ... optional_element(filter1|parser1|rewrite1); optional_element(filter2|parser2|rewrite2); ... destination(d1); destination(d2); ... flags(flag1[, flag2...]); }; The following log statement sends all messages arriving to the localhost to a remote server. source s_localhost { network(ip(127.0.0.1) port(1999)); }; destination d_tcp { network("10.1.2.3" port(1999) localport(999)); }; log { source(s_localhost); destination(d_tcp); }; The syslog-ng application has a number of global options governing DNS usage, the timestamp format used, and other general points. Each option may have parameters, similarly to driver specifications. To set global options, add an option statement to the syslog-ng configuration file using the following syntax: options { option1(params); option2(params); ... }; Using global options To disable domain name resolving, add the following line to the syslog-ng configuration file: options { use-dns(no); }; The sources, destinations, and filters available in syslog-ng are listed below. For details, see The syslog-ng Administrator Guide. Source drivers available in syslog-ng source drivers list of Name Description file() Opens the specified file and reads messages. internal() Messages generated internally in syslog-ng. network() Receives messages from remote hosts using the BSD-syslog protocol over IPv4 and IPv6. Supports the TCP, UDP, and TLS network protocols. pipe() Opens the specified named pipe and reads messages. program() Opens the specified application and reads messages from its standard output. sun-stream(), sun-streams() Opens the specified STREAMS device on Solaris systems and reads incoming messages. syslog() Listens for incoming messages using the new IETF-standard syslog protocol. system() Automatically detects which platform is running on, and collects the native log messages of that platform. systemd-journal() Collects messages directly from the journal of platforms that use systemd. systemd-syslog() Collects messages from the journal using a socket on platforms that use systemd. unix-dgram() Opens the specified unix socket in SOCK_DGRAM mode and listens for incoming messages. unix-stream() Opens the specified unix socket in SOCK_STREAM mode and listens for incoming messages.
Destination drivers available in syslog-ng destination drivers list of Name Description elasticsearch2 Sends messages to an Elasticsearch server. The elasticsearch2 driver supports Elasticsearch version 2 and newer. file() Writes messages to the specified file. hdfs() Sends messages into a file on a Hadoop Distributed File System (HDFS) node. kafka() Publishes log messages to the Apache Kafka message bus, where subscribers can access them. loggly() Sends log messages to the Loggly Logging-as-a-Service provider. logmatic() Sends log messages to the Logmatic.io Logging-as-a-Service provider. mongodb() Sends messages to a MongoDB database. network() Sends messages to a remote host using the BSD-syslog protocol over IPv4 and IPv6. Supports the TCP, UDP, and TLS network protocols. pipe() Writes messages to the specified named pipe. program() Forks and launches the specified program, and sends messages to its standard input. sql() Sends messages into an SQL database. In addition to the standard syslog-ng packages, the sql() destination requires database-specific packages to be installed. Refer to the section appropriate for your platform in . syslog() Sends messages to the specified remote host using the IETF-syslog protocol. The IETF standard supports message transport using the UDP, TCP, and TLS networking protocols. unix-dgram() Sends messages to the specified unix socket in SOCK_DGRAM style (BSD). unix-stream() Sends messages to the specified unix socket in SOCK_STREAM style (Linux). usertty() Sends messages to the terminal of the specified user, if the user is logged in.
Filter functions available in filter functions list of Name Description facility() Filter messages based on the sending facility. filter() Call another filter function. host() Filter messages based on the sending host. inlist() File-based whitelisting and blacklisting. level() or priority() Filter messages based on their priority. match() Use a regular expression to filter messages based on a specified header or content field. message() Use a regular expression to filter messages based on their content. netmask() Filter messages based on the IP address of the sending host. program() Filter messages based on the sending application. source() Select messages of the specified source statement. tags() Select messages having the specified tag.
Files /opt/syslog-ng/ /opt/syslog-ng/etc/syslog-ng.conf See also syslog-ng(8) For the detailed documentation of see The 4.4 Administrator Guide If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list. For news and notifications about of syslog-ng, visit the syslog-ng blogs. Author This manual page was written by the Balabit Documentation Team <documentation@balabit.com>. Copyright
syslog-ng-syslog-ng-4.4.0/doc/man/update-manpages.sh000077500000000000000000000033111450431004300223030ustar00rootroot00000000000000#!/usr/bin/env bash ############################################################################# # Copyright (c) 2017 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# GUIDE_REPO=syslog-ng-ose-guides PROJECT_DIR=$(dirname $(realpath ${BASH_SOURCE})) set -e echo -e "\e[33;1mDownload admin guide\e[0m" cd $PROJECT_DIR rm -rf $GUIDE_REPO git clone git@github.com:balabit/${GUIDE_REPO}.git cd $GUIDE_REPO/en echo -e "\e[33;1mBuild profiled XML source files\e[0m" make manpages echo -e "\e[33;1mUpdate manpage source files\e[0m" cd $PROJECT_DIR rm *.xml for new_file in $GUIDE_REPO/en/out/tmp/man/*.profiled.xml; do original=$(basename ${new_file/.profiled/}) echo "Updating file '$original'" cp "$new_file" "./$original" done rm -rf $GUIDE_REPO echo -e "\e[33;1mDONE.\e[0m" git status syslog-ng-syslog-ng-4.4.0/doc/security/000077500000000000000000000000001450431004300177675ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/doc/security/bof-2002-09-27.txt000066400000000000000000000042761450431004300223440ustar00rootroot00000000000000 BalaBit security advisory Advisory ID: BB-2002/01 Package: syslog-ng Versions affected: versions prior to and including 1.5.20 Problem type: buffer overflow Exploitable: yes Date: 2002-09-27 1) Background syslog-ng is a portable syslog implementation. Its highlights include regexp based log selection, TCP transport and more. For more information: http://www.balabit.hu/en/downloads/syslog-ng/ 2) Problem description To make it easier to specify message destinations, syslog-ng supports macros in destination filenames as the following log snippet shows: destination d_messages_by_host { file("/var/log/$HOST/messages"); }; The same syntax is used when specifying the contents of destination files: destination d_special_messages { file("/var/log/messages" template("$ISODATE $HOST $MSG\n")); }; The problem lies in the way macro expansion handles constant characters. (ie everything other than macro references). As syslog-ng expands macros it uses a buffer, and a variable called 'left', which contains the number of characters available in the buffer. When a constant character is appended, this variable is not decremented, thus when expanding macros incorrect bounds checking is performed. 3) Impact If templated filenames or templated output is used, it is possible to overflow a buffer. The number of bytes exceeding the allocated buffer depends on the exact template being used. It is believed that this overflow can be exploited, given enough constant characters are present in the template string. 4) Solution Upgrade syslog-ng to 1.5.21 (devel) or 1.4.16 (stable) or apply the following patch: diff -u -r1.52 -r1.53 --- affile.c 21 Aug 2002 14:03:50 -0000 1.52 +++ affile.c 27 Sep 2002 09:11:33 -0000 1.53 @@ -859,7 +859,7 @@ { "SOURCEIP", M_SOURCE_IP } }; char format[cfg->log_msg_size + 1], *format_ptr = format; - int left = sizeof(format); + int left = sizeof(format) - 1; int i, j; i = 0; @@ -888,6 +888,7 @@ *format_ptr = template->data[i]; format_ptr++; i++; + left--; } } *format_ptr = 0; syslog-ng-syslog-ng-4.4.0/doc/security/dos-2000-11-22.txt000066400000000000000000000042351450431004300223400ustar00rootroot00000000000000 BalaBit security advisory Advisory ID: BB-2000/01 Package: syslog-ng Versions affected: versions prior to and including 1.4.8 Problem type: remote DoS attack Date: 2000-11-22 1) Background syslog-ng is a portable syslog implementation. Its highlights include regexp based log selection, TCP transport and more. For more information: http://www.balabit.hu/products/syslog-ng/ 2) Problem description When syslog-ng parses log messages a variable named "left" is used to store the remaining length of the log message. The priority part in the message should look like this: <6> When the line ends without the closing '>' this "left" variable becomes -1 due a to a bug. The remaining part of the message parsing routine checks if there's any characters left using the condition: left != 0, since -1 is not 0, this condition evaluates to true. Syslog-ng versions after 1.4.7 filters out \r and \n characters from log messages and replaces them with spaces to avoid cluttering logfiles. Due to a problem in the parsing of log messages, this character change may access unaccessible memory region. This causes a segmentation fault. So sending a "<6", terminated with a newline to one of the input channels causes a SIGSEGV. Prior to 1.4.7, this character change was not implemented, so mounting a DoS attack is not so trivial, but is still possible. (it's left to the reader as an exercise) It is believed that no other exploitation is possible. 3) Impact Sending a carefully crafted syslog packet may cause syslog-ng to exit with a Segmentation Fault. 4) Solution Upgrade syslog-ng to 1.4.9, which is a security upgrade, and changes nothing compared to 1.4.8 or apply this patch: diff -urN syslog-ng-1.4.8/src/log.c syslog-ng-1.4.9/src/log.c --- syslog-ng-1.4.8/src/log.c Tue Oct 10 15:05:52 2000 +++ syslog-ng-1.4.9/src/log.c Wed Nov 22 16:45:11 2000 @@ -67,8 +67,10 @@ left--; } lm->pri = pri; - src++; - left--; + if (left) { + src++; + left--; + } } else { lm->pri = LOG_USER | LOG_NOTICE; syslog-ng-syslog-ng-4.4.0/doc/xsd/000077500000000000000000000000001450431004300167165ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/doc/xsd/examples/000077500000000000000000000000001450431004300205345ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/doc/xsd/examples/patterndb-1.xml000066400000000000000000000021041450431004300233740ustar00rootroot00000000000000 p-p p-desc p-url p1 p2 url2 d2 p-p2 p-p 3p1 syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-1.xsd000066400000000000000000000171511450431004300215640ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '1'. The publication date of the XML file. An optional element to attach description to an application/program. An optional element to point to the homepage of the application. The pattern representing the name of the application in the syslog program field. The patterns for the application. A rule describes one log pattern with classifications and details. The name of the application. The globaly unique ID of the application. FIXME: how it is generated? (simple md5 of the @name?) An optional element to describe the log disposition. An optional element to point to some external resource for disposition. The pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The globaly unique ID of the rule. FIXME: how it is generated? (simple md5 of the @name?) The class of the rule. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The log message is a VIOLATION where immediate action must be taken. The log message is related to a SECURITY event. The log message is related to a normal SYSTEM event. The log message is UNKNOWN and as is an anomaly. syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-2.xsd000066400000000000000000000231021450431004300215560ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '2'. The publication date of the XML file. An optional element to attach description to a ruleset. An optional element to point to a URL related to the ruleset. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. The rules in the ruleset. A rule describes one log event with classifications and details. The name of the application. An optional element to describe the log disposition. Optional elements to point to some external resource for disposition. Optional keywords that can be used for a freeform grouping of the rules. Patterns representing the rule. Log messages matching any one of the patterns are classified to this rule. A pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The class of the rule. The globaly unique ID of the rule. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The log message is a VIOLATION where immediate action must be taken. The log message is related to a SECURITY event. The log message is related to a normal SYSTEM event. The log message is UNKNOWN and as is an anomaly. syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-3.xsd000066400000000000000000000307361450431004300215720ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '3'. The publication date of the XML file. An optional element to attach description to a ruleset. An optional element to point to a URL related to the ruleset. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. The rules in the ruleset. A rule describes one log event with classifications and details. The name of the application. An optional element to describe the log disposition. Optional elements to point to some external resource for disposition. Optional values that are added after template evaluation to messages Optional examples to test rule patterns and configuration Optional keywords that can be used for a freeform grouping of the rules. Patterns representing the rule. Log messages matching any one of the patterns are classified to this rule. A pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The class of the rule. This describes a UUID syntax. Currently it is not used for the IDing to avoid enforcing the use of UUIDs, which some users complained about. Once the decision on the rule id format happens this may completely be removed. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The example message to test rule patterns syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-4.xsd000066400000000000000000000506361450431004300215740ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '4'. The publication date of the XML file. An optional element to attach description to a ruleset. An optional element to point to a URL related to the ruleset. If an application uses multiple values for its program name, then you can list them all in a patterns element containing multiple pattern elements. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. The rules in the ruleset. A rule describes one log event with classifications and details. The name of the application. An optional element to describe the log disposition. Optional elements to point to some external resource for disposition. Optional values that are added after template evaluation to messages Optional examples to test rule patterns and configuration Optional keywords that can be used for a freeform grouping of the rules. Patterns representing the rule. Log messages matching any one of the patterns are classified to this rule. A pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The class of the rule. The message to be generated when the action triggers. A filter expression guarding the triggering of this action. If the filter evaluates to TRUE the action is executed, otherwise it is skipped. The maximum rate at which this action is executed. Excess actions are ignored. Specifies when the action is to be executed. Specifies that the action is to be executed when the correlation timeout elapses without matching a further rule. Specifies that the action is to be executed immediately as the rule matches. Name-value pairs that make up the message to be generated. Optional keywords that can be used for a freeform grouping of the rules. If set to TRUE, the original message that triggered the action is cloned, including its name-value pairs and tags. For details, see Section 13.4, Triggering actions for identified messages. This describes a UUID syntax. Currently it is not used for the IDing to avoid enforcing the use of UUIDs, which some users complained about. Once the decision on the rule id format happens this may completely be removed. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The example message to test rule patterns syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-5.xsd000066400000000000000000000600601450431004300215650ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '5'. The publication date of the XML file. An optional element to attach description to a ruleset. An optional element to point to a URL related to the ruleset. Optional elements to point to some external resource for disposition. If an application uses multiple values for its program name, then you can list them all in a patterns element containing multiple pattern elements. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. The rules in the ruleset. A rule describes one log event with classifications and details. The name of the application. An optional element to describe the log disposition. Optional elements to point to some external resource for disposition. Optional values that are added after template evaluation to messages Optional examples to test rule patterns and configuration Optional keywords that can be used for a freeform grouping of the rules. Patterns representing the rule. Log messages matching any one of the patterns are classified to this rule. A pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The class of the rule. The message to be generated when the action triggers. The context to be created when the action is triggered. A filter expression guarding the triggering of this action. If the filter evaluates to TRUE the action is executed, otherwise it is skipped. The maximum rate at which this action is executed. Excess actions are ignored. Specifies when the action is to be executed. Specifies that the action is to be executed when the correlation timeout elapses without matching a further rule. Specifies that the action is to be executed immediately as the rule matches. Name-value pairs that make up the message to be generated. Optional keywords that can be used for a freeform grouping of the rules. If set to TRUE, the original message that triggered the action is cloned, including its name-value pairs and tags. For details, see Section 13.4, Triggering actions for identified messages. NOTE: This attribute is deprecated in favour of inherit-mode. This attribute is used to control which set of name-value pairs are propagated to the newly generated message. "context" means that the new message is populated with a union of all name-value pairs present in messages in the context. "last-message" means that only name-value pairs of the last message is copied. "none" means that the new message becomes empty initially. For details, see Section 13.4, Triggering actions for identified messages. The message that gets added to the new context to be created. This describes a UUID syntax. Currently it is not used for the IDing to avoid enforcing the use of UUIDs, which some users complained about. Once the decision on the rule id format happens this may completely be removed. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The example message to test rule patterns syslog-ng-syslog-ng-4.4.0/doc/xsd/patterndb-6.xsd000066400000000000000000000635301450431004300215730ustar00rootroot00000000000000 A container to group log patterns for an application/program. The schema version of the pattern database. The current version is '6'. The publication date of the XML file. An optional element to attach description to a ruleset. An optional element to point to a URL related to the ruleset. Optional elements to point to some external resource for disposition. If an application uses multiple values for its program name, then you can list them all in a patterns element containing multiple pattern elements. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. An optional element with a pattern representing the name of the application related to the ruleset in the syslog program field. The rules in the ruleset. A rule describes one log event with classifications and details. The name of the application. An optional element to describe the log disposition. Optional elements to point to some external resource for disposition. Optional values that are added after template evaluation to messages. Specifies the name of the name-value pair to be added to the message once the rule matches. The value can be a template expression, which is expanded using the matching message. Specifies the type-hint for the new name-value pair. Can be any syslog-ng supported type: string, integer, double, datetime, json Optional examples to test rule patterns and configuration Optional keywords that can be used for a freeform grouping of the rules. Patterns representing the rule. Log messages matching any one of the patterns are classified to this rule. A pattern representing the log message. The provider of the rule. To distinguish between who supplied the rule, or if it has been added to the xml by a local user. The class of the rule. The message to be generated when the action triggers. The context to be created when the action is triggered. A filter expression guarding the triggering of this action. If the filter evaluates to TRUE the action is executed, otherwise it is skipped. The maximum rate at which this action is executed. Excess actions are ignored. Specifies when the action is to be executed. Specifies that the action is to be executed when the correlation timeout elapses without matching a further rule. Specifies that the action is to be executed immediately as the rule matches. Name-value pairs that make up the message to be generated. Optional keywords that can be used for a freeform grouping of the rules. If set to TRUE, the original message that triggered the action is cloned, including its name-value pairs and tags. For details, see Section 13.4, Triggering actions for identified messages. NOTE: This attribute is deprecated in favour of inherit-mode. This attribute is used to control which set of name-value pairs are propagated to the newly generated message. "context" means that the new message is populated with a union of all name-value pairs present in messages in the context. "last-message" means that only name-value pairs of the last message is copied. "none" means that the new message becomes empty initially. For details, see Section 13.4, Triggering actions for identified messages. The message that gets added to the new context to be created. This describes a UUID syntax. Currently it is not used for the IDing to avoid enforcing the use of UUIDs, which some users complained about. Once the decision on the rule id format happens this may completely be removed. This type describes a radix/parser pattern which is used to match a program name or a whole log message. The classification class for a single rule. The example message to test rule patterns syslog-ng-syslog-ng-4.4.0/docker/000077500000000000000000000000001450431004300166225ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/docker/Dockerfile000066400000000000000000000043051450431004300206160ustar00rootroot00000000000000############################################################################# # Copyright (c) 2015-2023 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# FROM debian:testing LABEL maintainer="Andras Mitzki , László Várady " LABEL org.opencontainers.image.source="https://github.com/syslog-ng/syslog-ng" ARG PKG_TYPE=stable RUN apt-get update -qq && apt-get install -y \ wget \ ca-certificates \ gnupg2 \ && rm -rf /var/lib/apt/lists/* RUN wget -qO - https://ose-repo.syslog-ng.com/apt/syslog-ng-ose-pub.asc | gpg --dearmor > /usr/share/keyrings/ose-repo-archive-keyring.gpg && \ echo "deb [signed-by=/usr/share/keyrings/ose-repo-archive-keyring.gpg] https://ose-repo.syslog-ng.com/apt/ ${PKG_TYPE} debian-testing" | tee --append /etc/apt/sources.list.d/syslog-ng-ose.list RUN apt-get update -qq && apt-get install -y \ libdbd-mysql libdbd-pgsql libdbd-sqlite3 syslog-ng libjemalloc2 \ && rm -rf /var/lib/apt/lists/* ADD syslog-ng.conf /etc/syslog-ng/syslog-ng.conf EXPOSE 514/udp EXPOSE 601/tcp EXPOSE 6514/tcp HEALTHCHECK --interval=2m --timeout=5s --start-period=30s CMD /usr/sbin/syslog-ng-ctl healthcheck --timeout 5 ENV LD_PRELOAD /usr/lib/x86_64-linux-gnu/libjemalloc.so.2 ENTRYPOINT ["/usr/sbin/syslog-ng", "-F"] syslog-ng-syslog-ng-4.4.0/docker/README.md000066400000000000000000000067111450431004300201060ustar00rootroot00000000000000# `balabit/syslog-ng` * Syslog-ng is installed with all of its modules * Within the container syslog-ng will start in foreground. This is useful because if there is some error with syslog-ng we can easily check the output console log through the `docker logs [containerID]` command * You can use your own `syslog-ng.conf` or fall back to use the default one The following ports are exposed: * Syslog UDP: 514, * Syslog TCP: 601, * Syslog TLS: 6514 Syslog-ng will listen on these ports and forwards the logs into the file `/var/log/syslog`. You can check the default configuration in the source repository of this image. Please check the syslog-ng image tags at the official docker repository to know what image versions exist [https://registry.hub.docker.com/u/balabit] ## Using default configuration Assume that the following ports are not used on host machine, because they can conflict: `514`, `601`: ```bash sudo docker run -it -p 514:514/udp -p 601:601 --name syslog-ng balabit/syslog-ng:latest ``` By default syslog-ng will not print any debug messages to the console. If you want to see more debug messages you need to start the containers in this way: ```bash sudo docker run -it -p 514:514/udp -p 601:601 --name syslog-ng balabit/syslog-ng:latest -edv ``` ## Using custom syslog-ng configuration You can override the default configuration by mounting a configuration file under `/etc/syslog-ng/syslog-ng.conf`: ```bash sudo docker run -it -v "$PWD/syslog-ng.conf":/etc/syslog-ng/syslog-ng.conf balabit/syslog-ng:latest ``` ## Reading logs from other containers An example is used to describe how syslog-ng can read logs from other containers. Assume that you have already running an `apache2` container which exposes its logs as a mounted volume under "/var/log/apache2/". We will read the apache logs and send them to a remote host (`1.2.3.4:514`). The example syslog-ng configuration file is stored in the current directory as `syslog-ng.conf`. ``` source s_apache { file("/var/log/apache2/access.log"); }; destination d_remote { tcp("1.2.3.4" port(514)); }; log { source(s_apache); destination(d_remote); }; ``` Now we can start syslog-ng: ```bash sudo docker run -it --volumes-from [containerID for apache2] -v "$PWD/syslog-ng.conf":/etc/syslog-ng/syslog-ng.conf balabit/syslog-ng:latest ``` ## Entering into a container Assume that your running container has a name "syslog-ng". In this case we can enter into this container by executing the following command: ```bash sudo docker exec -it syslog-ng /bin/bash ``` ## More information For detailed information on how to run your central log server in Docker and other Docker-related syslog-ng use cases, see the blog post [Your central log server in Docker](https://syslog-ng.com/blog/central-log-server-docker/). ## FAQ ### capabilities If the given configuration requires, syslog-ng tries to set some POSIX capabilities at startup, but (by default) Docker do not grant capabilities to the containers. Mainly there are three methods to circumvent this: * If you do not require any capability (i.e. don't want to listen on ports under 1024 - NET_BIND_SERVICE), simply start syslog-ng with the `--no-caps` option. * If you know precisely the type of capability you need, use the `--cap-add` option of the Docker service. * (For development/testing purpose only!) To grant ALL of the capabilities to your container, start it with the `privileged` option. However, we do not recommend this method in production environments. syslog-ng-syslog-ng-4.4.0/docker/syslog-ng.conf000066400000000000000000000023311450431004300214120ustar00rootroot00000000000000############################################################################# # Default syslog-ng.conf file which collects all local logs into a # single file called /var/log/messages tailored to container usage. # # The changes from the stock, default syslog-ng.conf file is that we've # dropped the system() source that is not needed and that we enabled network # connections using default-network-drivers(). Customize as needed and # override using the -v option to docker, such as: # # docker run ... -v "$PWD/syslog-ng.conf":/etc/syslog-ng/syslog-ng.conf # @version: 4.4 @include "scl.conf" source s_local { internal(); }; source s_network { default-network-drivers( # NOTE: TLS support # # the default-network-drivers() source driver opens the TLS # enabled ports as well, however without an actual key/cert # pair they will not operate and syslog-ng would display a # warning at startup. # #tls(key-file("/path/to/ssl-private-key") cert-file("/path/to/ssl-cert")) ); }; destination d_local { file("/var/log/messages"); file("/var/log/messages-kv.log" template("$ISODATE $HOST $(format-welf --scope all-nv-pairs)\n") frac-digits(3)); }; log { source(s_local); source(s_network); destination(d_local); }; syslog-ng-syslog-ng-4.4.0/lib/000077500000000000000000000000001450431004300161215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/.gitignore000066400000000000000000000000401450431004300201030ustar00rootroot00000000000000m4 .arch-ids .arch-inventory *~ syslog-ng-syslog-ng-4.4.0/lib/CMakeLists.txt000066400000000000000000000250331450431004300206640ustar00rootroot00000000000000flex_target(CfgLexer ${PROJECT_SOURCE_DIR}/lib/cfg-lex.l ${PROJECT_BINARY_DIR}/lib/cfg-lex.c ${PROJECT_BINARY_DIR}/lib/cfg-lex.h) bison_target(CfgGrammar ${PROJECT_SOURCE_DIR}/lib/cfg-grammar.y ${PROJECT_BINARY_DIR}/lib/cfg-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) set_source_files_properties( ${PROJECT_BINARY_DIR}/lib/cfg-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) add_flex_bison_dependency(CfgLexer CfgGrammar) add_subdirectory(ack-tracker) add_subdirectory(compat) add_subdirectory(control) add_subdirectory(healthcheck) add_subdirectory(debugger) add_subdirectory(filter) add_subdirectory(logmsg) add_subdirectory(logproto) add_subdirectory(multi-line) add_subdirectory(parser) add_subdirectory(rewrite) add_subdirectory(stats) add_subdirectory(template) add_subdirectory(transport) add_subdirectory(value-pairs) add_subdirectory(scanner) add_subdirectory(str-repr) add_subdirectory(timeutils) add_subdirectory(eventlog) add_subdirectory(secret-storage) add_subdirectory(logthrsource) add_subdirectory(logthrdest) add_subdirectory(signal-slot-connector) set(LIB_SUBDIR_HEADERS ${ACK_TRACKER_HEADERS} ${COMPAT_HEADERS} ${CONTROL_HEADERS} ${HEALTHCHECK_HEADERS} ${DEBUGGER_HEADERS} ${FILTER_HEADERS} ${LOGMSG_HEADERS} ${LOGPROTO_HEADERS} ${MULTI_LINE_HEADERS} ${PARSER_HEADERS} ${REWRITE_HEADERS} ${STATS_HEADERS} ${TEMPLATE_HEADERS} ${TRANSPORT_HEADERS} ${VALUE_PAIRS_HEADERS} ${CSV_SCANNER_HEADERS} ${LIST_SCANNER_HEADERS} ${KV_SCANNER_HEADERS} ${XML_SCANNER_HEADERS} ${STR_REPR_HEADERS} ${TIMEUTILS_HEADERS} ${LOGTHRDEST_HEADERS} ${LOGTHRSOURCE_HEADERS} ${SIGNAL_SLOT_CONNECTOR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/filter/filter-expr-grammar.h ${CMAKE_CURRENT_BINARY_DIR}/rewrite/rewrite-expr-grammar.h ${CMAKE_CURRENT_BINARY_DIR}/parser/parser-expr-grammar.h ) set (LIB_HEADERS afinter.h alarms.h apphook.h atomic.h atomic-gssize.h block-ref-parser.h cache.h cfg.h cfg-lexer.h cfg-lexer-subst.h cfg-args.h cfg-block.h cfg-block-generator.h cfg-grammar-internal.h cfg-parser.h cfg-path.h cfg-tree.h cfg-walker.h cfg-persist.h cfg-monitor.h children.h crypto.h dnscache.h driver.h dynamic-window-pool.h dynamic-window.h fdhelpers.h file-perms.h find-crlf.h generic-number.h gprocess.h gsockaddr.h gsocket.h hostname.h host-resolve.h list-adt.h logmatcher.h logmpx.h logpipe.h logqueue-fifo.h logqueue.h logreader.h logsource.h logscheduler.h logscheduler-pipe.h logwriter.h mainloop.h mainloop-call.h mainloop-worker.h mainloop-io-worker.h mainloop-threaded-worker.h module-config.h memtrace.h messages.h metrics-pipe.h ml-batched-timer.h mainloop-control.h msg-format.h msg-stats.h parse-number.h pathutils.h persist-state.h persistable-state-header.h persistable-state-presenter.h plugin.h plugin-types.h poll-events.h poll-fd-events.h pragma-parser.h presented-persistable-state.h reloc.h rcptid.h run-id.h scratch-buffers.h serialize.h service-management.h seqnum.h str-format.h str-utils.h syslog-names.h syslog-ng.h string-list.h tls-support.h thread-utils.h uuid.h userdb.h utf8utils.h versioning.h ringbuffer.h host-id.h resolved-configurable-paths.h window-size-counter.h ${PROJECT_BINARY_DIR}/lib/cfg-grammar.h ${PROJECT_BINARY_DIR}/lib/block-ref-grammar.h ${PROJECT_BINARY_DIR}/lib/cfg-lex.h ${PROJECT_BINARY_DIR}/lib/pragma-grammar.h ) set(LIB_SOURCES afinter.c alarms.c apphook.c block-ref-parser.c cache.c cfg.c cfg-args.c cfg-block.c cfg-block-generator.c cfg-lexer.c cfg-lexer-subst.c cfg-grammar-internal.c cfg-parser.c cfg-path.c cfg-tree.c cfg-walker.c cfg-persist.c cfg-monitor.c children.c dnscache.c driver.c dynamic-window.c dynamic-window-pool.c fdhelpers.c file-perms.c find-crlf.c globals.c generic-number.c gprocess.c gsockaddr.c gsocket.c hostname.c host-resolve.c logmatcher.c logmpx.c logpipe.c logqueue.c logqueue-fifo.c logreader.c logscheduler.c logscheduler-pipe.c logsource.c logwriter.c mainloop.c signal-handler.c mainloop-call.c mainloop-worker.c mainloop-io-worker.c mainloop-threaded-worker.c module-config.c memtrace.c messages.c metrics-pipe.c ml-batched-timer.c mainloop-control.c msg-format.c msg-stats.c parse-number.c pathutils.c persist-state.c plugin.c poll-events.c poll-fd-events.c pragma-parser.c persistable-state-presenter.c rcptid.c reloc.c run-id.c scratch-buffers.c serialize.c service-management.c str-format.c str-utils.c syslog-names.c string-list.c ringbuffer.c crypto.c uuid.c userdb.c utf8utils.c host-id.c resolved-configurable-paths.c window-size-counter.c ${ACK_TRACKER_SOURCES} ${COMPAT_SOURCES} ${CONTROL_SOURCES} ${HEALTHCHECK_SOURCES} ${DEBUGGER_SOURCES} ${FILTER_SOURCES} ${LOGMSG_SOURCES} ${LOGPROTO_SOURCES} ${MULTI_LINE_SOURCES} ${PARSER_SOURCES} ${REWRITE_SOURCES} ${STATS_SOURCES} ${TEMPLATE_SOURCES} ${TRANSPORT_SOURCES} ${VALUE_PAIRS_SOURCES} ${SCANNER_SOURCES} ${STR_REPR_SOURCES} ${TIMEUTILS_SOURCES} ${LOGTHRDEST_SOURCES} ${LOGTHRSOURCE_SOURCES} ${SIGNAL_SLOT_CONNECTOR_SOURCES} ${PROJECT_BINARY_DIR}/lib/cfg-grammar.c ${PROJECT_BINARY_DIR}/lib/block-ref-grammar.c ${PROJECT_BINARY_DIR}/lib/cfg-lex.c ${PROJECT_BINARY_DIR}/lib/pragma-grammar.c ${CMAKE_CURRENT_BINARY_DIR}/filter/filter-expr-grammar.c ${CMAKE_CURRENT_BINARY_DIR}/rewrite/rewrite-expr-grammar.c ${CMAKE_CURRENT_BINARY_DIR}/parser/parser-expr-grammar.c ) generate_y_from_ym (lib/block-ref-grammar) bison_target(BlockRefGrammar ${PROJECT_BINARY_DIR}/lib/block-ref-grammar.y ${PROJECT_BINARY_DIR}/lib/block-ref-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) add_flex_bison_dependency(CfgLexer BlockRefGrammar) set_source_files_properties( ${PROJECT_BINARY_DIR}/lib/block-ref-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) generate_y_from_ym (lib/pragma-grammar) bison_target(PragmaGrammar ${PROJECT_BINARY_DIR}/lib/pragma-grammar.y ${PROJECT_BINARY_DIR}/lib/pragma-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) add_flex_bison_dependency(CfgLexer PragmaGrammar) set_source_files_properties( ${PROJECT_BINARY_DIR}/lib/pragma-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) generate_y_from_ym (lib/filter/filter-expr-grammar) bison_target(FilterExprGrammar ${CMAKE_CURRENT_BINARY_DIR}/filter/filter-expr-grammar.y ${CMAKE_CURRENT_BINARY_DIR}/filter/filter-expr-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) add_flex_bison_dependency(CfgLexer FilterExprGrammar) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/filter/filter-expr-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) generate_y_from_ym (lib/rewrite/rewrite-expr-grammar) bison_target(RewriteExprGrammar ${CMAKE_CURRENT_BINARY_DIR}/rewrite/rewrite-expr-grammar.y ${CMAKE_CURRENT_BINARY_DIR}/rewrite/rewrite-expr-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) add_flex_bison_dependency(CfgLexer RewriteExprGrammar) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/rewrite/rewrite-expr-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) generate_y_from_ym (lib/parser/parser-expr-grammar) bison_target(ParserExprGrammar ${CMAKE_CURRENT_BINARY_DIR}/parser/parser-expr-grammar.y ${CMAKE_CURRENT_BINARY_DIR}/parser/parser-expr-grammar.c COMPILE_FLAGS ${BISON_FLAGS}) add_flex_bison_dependency(CfgLexer ParserExprGrammar) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/parser/parser-expr-grammar.c PROPERTIES COMPILE_FLAGS ${BISON_BUILT_SOURCE_CFLAGS}) set(CORE_INCLUDE_DIRS ${Gettext_INCLUDE_DIR} ${IVYKIS_INCLUDE_DIR} ${LIBPCRE_INCLUDE_DIRS} ${Libsystemd_INCLUDE_DIRS} ) add_library(syslog-ng SHARED ${LIB_SOURCES}) target_include_directories(syslog-ng PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) target_include_directories(syslog-ng SYSTEM PUBLIC ${CORE_INCLUDE_DIRS} ) target_link_libraries( syslog-ng PUBLIC m eventlog GLib::GLib GLib::GThread GLib::GModule ${Gettext_LIBRARIES} ${IVYKIS_LIBRARY} ${LIBPCRE_LIBRARIES} ${Libsystemd_LIBRARIES} resolv libcap OpenSSL::SSL OpenSSL::Crypto Threads::Threads secret-storage ) set_target_properties(syslog-ng PROPERTIES VERSION ${SYSLOG_NG_VERSION} SOVERSION ${SYSLOG_NG_VERSION}) if (${IVYKIS_INTERNAL}) add_dependencies(syslog-ng IVYKIS) endif() install(TARGETS syslog-ng LIBRARY DESTINATION lib) install(FILES ${LIB_HEADERS} DESTINATION include/syslog-ng) install(FILES ${VALUE_PAIRS_HEADERS} DESTINATION include/syslog-ng/value-pairs) install(FILES ${COMPAT_HEADERS} DESTINATION include/syslog-ng/compat) install(FILES ${CONTROL_HEADERS} DESTINATION include/syslog-ng/control) install(FILES ${HEALTHCHECK_HEADERS} DESTINATION include/syslog-ng/healthcheck) install(FILES ${DEBUGGER_HEADERS} DESTINATION include/syslog-ng/debugger) install(FILES ${FILTER_HEADERS} DESTINATION include/syslog-ng/filter) install(FILES ${LOGMSG_HEADERS} DESTINATION include/syslog-ng/logmsg) install(FILES ${LOGPROTO_HEADERS} DESTINATION include/syslog-ng/logproto) install(FILES ${PARSER_HEADERS} DESTINATION include/syslog-ng/parser) install(FILES ${REWRITE_HEADERS} DESTINATION include/syslog-ng/rewrite) install(FILES ${STATS_HEADERS} DESTINATION include/syslog-ng/stats) install(FILES ${TEMPLATE_HEADERS} DESTINATION include/syslog-ng/template) install(FILES ${TRANSPORT_HEADERS} DESTINATION include/syslog-ng/transport) install(FILES ${CSV_SCANNER_HEADERS} DESTINATION include/syslog-ng/scanner/csv-scanner) install(FILES ${LOGTHRDEST_HEADERS} DESTINATION include/syslog-ng/logthrdest) install(FILES ${LOGTHRSOURCE_HEADERS} DESTINATION include/syslog-ng/logthrsource) install(FILES ${SIGNAL_SLOT_CONNECTOR_HEADERS} DESTINATION include/syslog-ng/signal-slot-connector) set(TOOLS merge-grammar.py cfg-grammar.y ) install(FILES ${TOOLS} DESTINATION share/syslog-ng/tools) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/Makefile.am000066400000000000000000000212521450431004300201570ustar00rootroot00000000000000DIST_SUBDIRS += @IVYKIS_SUBDIRS@ include lib/ack-tracker/Makefile.am include lib/eventlog/src/Makefile.am include lib/eventlog/tests/Makefile.am include lib/transport/Makefile.am include lib/logproto/Makefile.am include lib/rewrite/Makefile.am include lib/parser/Makefile.am include lib/filter/Makefile.am include lib/template/Makefile.am include lib/value-pairs/Makefile.am include lib/stats/Makefile.am include lib/control/Makefile.am include lib/healthcheck/Makefile.am include lib/debugger/Makefile.am include lib/compat/Makefile.am include lib/logmsg/Makefile.am include lib/scanner/csv-scanner/Makefile.am include lib/scanner/list-scanner/Makefile.am include lib/scanner/kv-scanner/Makefile.am include lib/scanner/xml-scanner/Makefile.am include lib/str-repr/Makefile.am include lib/timeutils/Makefile.am include lib/secret-storage/Makefile.am include lib/logthrsource/Makefile.am include lib/logthrdest/Makefile.am include lib/signal-slot-connector/Makefile.am include lib/multi-line/Makefile.am LSNG_RELEASE = $(shell echo @PACKAGE_VERSION@ | cut -d. -f1,2) # * Start with version information of ‘0:0:0’ for each libtool # library. # * Update the version information only immediately before a public # release of your software. More frequent updates are unnecessary, # and only guarantee that the current interface number gets larger # faster. # * If the library source code has changed at all since the last # update, then increment revision (‘c:r:a’ becomes ‘c:r+1:a’). # * If any interfaces have been added, removed, or changed since the # last update, increment current, and set revision to 0. # * If any interfaces have been added since the last public release, # then increment age. # * If any interfaces have been removed or changed since the last # public release, then set age to 0. LSNG_CURRENT = 0 LSNG_REVISION = 0 LSNG_AGE = 0 lib_LTLIBRARIES += lib/libsyslog-ng.la lib_libsyslog_ng_la_LIBADD = @CORE_DEPS_LIBS@ $(libsystemd_LIBS) $(top_builddir)/lib/secret-storage/libsecret-storage.la lib_libsyslog_ng_la_LDFLAGS = -no-undefined -release ${LSNG_RELEASE} \ -version-info ${LSNG_CURRENT}:${LSNG_REVISION}:${LSNG_AGE} lib_test_subdirs = lib_filter lib_logproto lib_parser lib_rewrite lib_template lib_stats lib_control lib_libsyslog_ng_la_DEPENDENCIES = lib/eventlog/src/libevtlog.la lib/secret-storage/libsecret-storage.la if IVYKIS_INTERNAL lib_libsyslog_ng_la_DEPENDENCIES += lib/ivykis/src/libivykis.la lib/ivykis/src/libivykis.la: ${MAKE} CFLAGS="${CFLAGS} -Wno-error" -C lib/ivykis CLEAN_SUBDIRS += @IVYKIS_SUBDIRS@ EXTRA_DIST += \ lib/ivykis/configure.gnu \ lib/CMakeLists.txt install-ivykis: ${MAKE} -C lib/ivykis/src \ install-includeHEADERS \ install-nodist_includeHEADERS \ includedir="${pkgincludedir}/ivykis" uninstall-ivykis: ${MAKE} -C lib/ivykis/src \ uninstall-includeHEADERS \ uninstall-nodist_includeHEADERS \ includedir="${pkgincludedir}/ivykis" INSTALL_EXEC_HOOKS += install-ivykis UNINSTALL_HOOKS += uninstall-ivykis endif # this is intentionally formatted so conflicts are less likely to arise. one name in every line. pkginclude_HEADERS += \ lib/afinter.h \ lib/alarms.h \ lib/apphook.h \ lib/atomic.h \ lib/atomic-gssize.h \ lib/block-ref-parser.h \ lib/cache.h \ lib/cfg.h \ lib/cfg-grammar.h \ lib/cfg-grammar-internal.h \ lib/cfg-lexer.h \ lib/cfg-lexer-subst.h \ lib/cfg-args.h \ lib/cfg-block.h \ lib/cfg-block-generator.h \ lib/cfg-parser.h \ lib/cfg-path.h \ lib/cfg-tree.h \ lib/cfg-walker.h \ lib/cfg-persist.h \ lib/cfg-monitor.h \ lib/children.h \ lib/crypto.h \ lib/dnscache.h \ lib/driver.h \ lib/dynamic-window-pool.h \ lib/dynamic-window.h \ lib/fdhelpers.h \ lib/file-perms.h \ lib/find-crlf.h \ lib/generic-number.h \ lib/gprocess.h \ lib/gsockaddr.h \ lib/gsocket.h \ lib/hostname.h \ lib/host-resolve.h \ lib/list-adt.h \ lib/logmatcher.h \ lib/logmpx.h \ lib/logscheduler.h \ lib/logscheduler-pipe.h \ lib/logpipe.h \ lib/logqueue-fifo.h \ lib/logqueue.h \ lib/logreader.h \ lib/logsource.h \ lib/logwriter.h \ lib/mainloop.h \ lib/mainloop-call.h \ lib/mainloop-worker.h \ lib/mainloop-threaded-worker.h \ lib/mainloop-io-worker.h \ lib/mainloop-control.h \ lib/module-config.h \ lib/memtrace.h \ lib/messages.h \ lib/metrics-pipe.h \ lib/ml-batched-timer.h \ lib/msg-format.h \ lib/msg-stats.h \ lib/parse-number.h \ lib/pathutils.h \ lib/persist-state.h \ lib/persistable-state-header.h \ lib/persistable-state-presenter.h \ lib/plugin.h \ lib/plugin-types.h \ lib/poll-events.h \ lib/poll-fd-events.h \ lib/pragma-parser.h \ lib/presented-persistable-state.h \ lib/reloc.h \ lib/rcptid.h \ lib/run-id.h \ lib/scratch-buffers.h \ lib/serialize.h \ lib/service-management.h \ lib/seqnum.h \ lib/signal-handler.h \ lib/str-format.h \ lib/str-utils.h \ lib/syslog-names.h \ lib/syslog-ng.h \ lib/misc.h \ lib/string-list.h \ lib/tls-support.h \ lib/thread-utils.h \ lib/uuid.h \ lib/userdb.h \ lib/utf8utils.h \ lib/versioning.h \ lib/ringbuffer.h \ lib/host-id.h \ lib/resolved-configurable-paths.h \ lib/pe-versioning.h \ lib/window-size-counter.h # this is intentionally formatted so conflicts are less likely to arise. one name in every line. lib_libsyslog_ng_la_SOURCES = \ lib/afinter.c \ lib/alarms.c \ lib/apphook.c \ lib/block-ref-parser.c \ lib/cache.c \ lib/cfg.c \ lib/cfg-args.c \ lib/cfg-block.c \ lib/cfg-block-generator.c \ lib/cfg-lexer.c \ lib/cfg-lexer-subst.c \ lib/cfg-parser.c \ lib/cfg-path.c \ lib/cfg-tree.c \ lib/cfg-walker.c \ lib/cfg-persist.c \ lib/cfg-monitor.c \ lib/children.c \ lib/dnscache.c \ lib/driver.c \ lib/dynamic-window.c \ lib/dynamic-window-pool.c \ lib/fdhelpers.c \ lib/file-perms.c \ lib/find-crlf.c \ lib/generic-number.c \ lib/globals.c \ lib/gprocess.c \ lib/gsockaddr.c \ lib/gsocket.c \ lib/hostname.c \ lib/host-resolve.c \ lib/logmatcher.c \ lib/logmpx.c \ lib/logscheduler.c \ lib/logscheduler-pipe.c \ lib/logpipe.c \ lib/logqueue.c \ lib/logqueue-fifo.c \ lib/logreader.c \ lib/logsource.c \ lib/logwriter.c \ lib/mainloop.c \ lib/signal-handler.c \ lib/mainloop-call.c \ lib/mainloop-worker.c \ lib/mainloop-threaded-worker.c \ lib/mainloop-io-worker.c \ lib/mainloop-control.c \ lib/module-config.c \ lib/memtrace.c \ lib/messages.c \ lib/metrics-pipe.c \ lib/ml-batched-timer.c \ lib/msg-format.c \ lib/msg-stats.c \ lib/parse-number.c \ lib/pathutils.c \ lib/persist-state.c \ lib/plugin.c \ lib/poll-events.c \ lib/poll-fd-events.c \ lib/pragma-parser.c \ lib/persistable-state-presenter.c \ lib/rcptid.c \ lib/reloc.c \ lib/run-id.c \ lib/scratch-buffers.c \ lib/serialize.c \ lib/service-management.c \ lib/str-format.c \ lib/str-utils.c \ lib/syslog-names.c \ lib/string-list.c \ lib/ringbuffer.c \ lib/crypto.c \ lib/uuid.c \ lib/userdb.c \ lib/utf8utils.c \ $(transport_crypto_sources) \ lib/host-id.c \ lib/resolved-configurable-paths.c \ lib/window-size-counter.c \ lib/cfg-lex.l \ lib/cfg-grammar.y \ lib/cfg-grammar-internal.c \ lib/block-ref-grammar.y \ lib/pragma-grammar.y \ $(ack_tracker_sources) \ $(csvscanner_sources) \ $(kvscanner_sources) \ $(listscanner_sources) \ $(xmlscanner_sources) \ $(transport_sources) \ $(logproto_sources) \ $(filter_sources) \ $(parser_sources) \ $(rewrite_sources) \ $(template_sources) \ $(value_pairs_sources) \ $(stats_sources) \ $(control_sources) \ $(healthcheck_sources) \ $(debugger_sources) \ $(compat_sources) \ $(logmsg_sources) \ $(str_repr_sources) \ $(timeutils_sources) \ $(multiline_sources) \ $(logthrsource_sources) \ $(logthrdest_sources) \ $(signal_slot_connector_sources) lib_libsyslog_ng_la_CFLAGS = \ $(AM_CFLAGS) \ $(libsystemd_CFLAGS) lib_libsyslog_ng_la_LIBADD += @OPENSSL_LIBS@ # each line with closely related files (e.g. the ones generated from the same source) BUILT_SOURCES += lib/cfg-lex.c lib/cfg-lex.h \ lib/cfg-grammar.c lib/cfg-grammar.h \ lib/block-ref-grammar.y lib/block-ref-grammar.c lib/block-ref-grammar.h \ lib/pragma-grammar.y lib/pragma-grammar.h lib/pragma-grammar.c EXTRA_DIST += \ lib/block-ref-grammar.ym \ lib/pragma-grammar.ym \ lib/merge-grammar.py \ lib/hostname-unix.c lib/plugin-types.h: lib/cfg-grammar.h lib/ libsyslog-ng: lib/libsyslog-ng.la if IVYKIS_INTERNAL lib/ivykis/ ivykis: lib/ivykis/src/libivykis.la endif .PHONY: lib/ libsyslog-ng ivykis lib/ivykis/ include lib/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/000077500000000000000000000000001450431004300203105ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/CMakeLists.txt000066400000000000000000000016561450431004300230600ustar00rootroot00000000000000set(ACK_TRACKER_HEADERS ack-tracker/ack_tracker.h ack-tracker/ack_tracker_factory.h ack-tracker/ack_tracker_types.h ack-tracker/batched_ack_tracker.h ack-tracker/bookmark.h ack-tracker/consecutive_ack_record_container.h ack-tracker/consecutive_ack_tracker.h ack-tracker/instant_ack_tracker.h PARENT_SCOPE) set(ACK_TRACKER_SOURCES ack-tracker/ack_tracker_factory.c ack-tracker/batched_ack_tracker.c ack-tracker/batched_ack_tracker_factory.c ack-tracker/instant_ack_tracker.c ack-tracker/instant_ack_tracker_bookmarkless.c ack-tracker/consecutive_ack_tracker.c ack-tracker/consecutive_ack_tracker_factory.c ack-tracker/consecutive_ack_record_container_static.c ack-tracker/consecutive_ack_record_container_dynamic.c ack-tracker/instant_ack_tracker_factory.c ack-tracker/instant_ack_tracker_bookmarkless_factory.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/Makefile.am000066400000000000000000000021471450431004300223500ustar00rootroot00000000000000ack_tracker_includedir = ${pkgincludedir}/ack-tracker EXTRA_DIST += lib/ack-tracker/CMakeLists.txt \ lib/ack-tracker/tests/CMakeLists.txt ack_tracker_include_HEADERS = \ lib/ack-tracker/ack_tracker.h \ lib/ack-tracker/ack_tracker_factory.h \ lib/ack-tracker/ack_tracker_types.h \ lib/ack-tracker/bookmark.h \ lib/ack-tracker/batched_ack_tracker.h \ lib/ack-tracker/consecutive_ack_record_container.h \ lib/ack-tracker/consecutive_ack_tracker.h \ lib/ack-tracker/instant_ack_tracker.h ack_tracker_sources = \ lib/ack-tracker/ack_tracker_factory.c \ lib/ack-tracker/batched_ack_tracker.c \ lib/ack-tracker/batched_ack_tracker_factory.c \ lib/ack-tracker/instant_ack_tracker.c \ lib/ack-tracker/instant_ack_tracker_bookmarkless.c \ lib/ack-tracker/consecutive_ack_tracker.c \ lib/ack-tracker/consecutive_ack_tracker_factory.c \ lib/ack-tracker/consecutive_ack_record_container_static.c \ lib/ack-tracker/consecutive_ack_record_container_dynamic.c \ lib/ack-tracker/instant_ack_tracker_factory.c \ lib/ack-tracker/instant_ack_tracker_bookmarkless_factory.c include lib/ack-tracker/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/ack_tracker.h000066400000000000000000000047651450431004300227460ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ACK_TRACKER_H_INCLUDED #define ACK_TRACKER_H_INCLUDED #include "syslog-ng.h" #include "logsource.h" #include "ack_tracker_types.h" #include "bookmark.h" struct _AckTracker { LogSource *source; Bookmark *(*request_bookmark)(AckTracker *self); void (*track_msg)(AckTracker *self, LogMessage *msg); void (*manage_msg_ack)(AckTracker *self, LogMessage *msg, AckType ack_type); void (*free_fn)(AckTracker *self); void (*disable_bookmark_saving)(AckTracker *self); gboolean (*init)(AckTracker *self); void (*deinit)(AckTracker *self); }; struct _AckRecord { AckTracker *tracker; Bookmark bookmark; }; static inline void ack_tracker_free(AckTracker *self) { if (self && self->free_fn) { self->free_fn(self); } } static inline Bookmark * ack_tracker_request_bookmark(AckTracker *self) { return self->request_bookmark(self); } static inline void ack_tracker_track_msg(AckTracker *self, LogMessage *msg) { self->track_msg(self, msg); } static inline void ack_tracker_manage_msg_ack(AckTracker *self, LogMessage *msg, AckType ack_type) { self->manage_msg_ack(self, msg, ack_type); } static inline void ack_tracker_disable_bookmark_saving(AckTracker *self) { if (self->disable_bookmark_saving) { self->disable_bookmark_saving(self); } } static inline gboolean ack_tracker_init(AckTracker *self) { if (self && self->init) return self->init(self); return TRUE; } static inline void ack_tracker_deinit(AckTracker *self) { if (self && self->deinit) self->deinit(self); } #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/ack_tracker_factory.c000066400000000000000000000033651450431004300244630ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ack_tracker_factory.h" #include "instant_ack_tracker.h" #include "consecutive_ack_tracker.h" #include "ack_tracker.h" void ack_tracker_factory_init_instance(AckTrackerFactory *self) { g_atomic_counter_set(&self->ref_cnt, 1); } AckTrackerFactory * ack_tracker_factory_ref(AckTrackerFactory *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } static inline void _free(AckTrackerFactory *self) { if (self && self->free_fn) self->free_fn(self); } void ack_tracker_factory_unref(AckTrackerFactory *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) { _free(self); } } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/ack_tracker_factory.h000066400000000000000000000044341450431004300244660ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ACK_TRACKER_FACTORY_H_INCLUDED #define ACK_TRACKER_FACTORY_H_INCLUDED #include "syslog-ng.h" #include "logsource.h" #include "ack_tracker_types.h" #include "atomic.h" #include "batched_ack_tracker.h" struct _AckTrackerFactory { GAtomicCounter ref_cnt; AckTrackerType type; AckTracker *(*create)(AckTrackerFactory *self, LogSource *source); void (*free_fn)(AckTrackerFactory *self); }; static inline AckTracker * ack_tracker_factory_create(AckTrackerFactory *self, LogSource *source) { g_assert(self && self->create); return self->create(self, source); } static inline AckTrackerType ack_tracker_factory_get_type(AckTrackerFactory *self) { g_assert(self); return self->type; } void ack_tracker_factory_init_instance(AckTrackerFactory *self); AckTrackerFactory *ack_tracker_factory_ref(AckTrackerFactory *self); void ack_tracker_factory_unref(AckTrackerFactory *self); AckTrackerFactory *instant_ack_tracker_factory_new(void); AckTrackerFactory *instant_ack_tracker_bookmarkless_factory_new(void); AckTrackerFactory *consecutive_ack_tracker_factory_new(void); AckTrackerFactory *batched_ack_tracker_factory_new(guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked cb, gpointer user_data); #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/ack_tracker_types.h000066400000000000000000000024461450431004300241640ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ACK_TRACKER_TYPES_H_INCLUDED #define ACK_TRACKER_TYPES_H_INCLUDED typedef enum { ACK_CONSECUTIVE, ACK_INSTANT_BOOKMARKLESS, ACK_INSTANT, ACK_BATCHED } AckTrackerType; static inline gboolean ack_tracker_type_is_position_tracked(AckTrackerType type) { return (type != ACK_INSTANT_BOOKMARKLESS); } #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/batched_ack_tracker.c000066400000000000000000000233231450431004300244020ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "batched_ack_tracker.h" #include "bookmark.h" #include "syslog-ng.h" #include "logsource.h" #include "timeutils/misc.h" #include #include typedef struct _BatchedAckRecord { AckRecord super; } BatchedAckRecord; typedef struct _OnBatchAckedFunctor { BatchedAckTrackerOnBatchAcked func; gpointer user_data; } OnBatchAckedFunctor; typedef struct _BatchedAckTracker { AckTracker super; guint timeout; guint batch_size; OnBatchAckedFunctor on_batch_acked; BatchedAckRecord *pending_ack_record; GMutex acked_records_lock; gulong acked_records_num; GList *acked_records; struct iv_timer batch_timer; struct iv_event request_destroy; struct iv_event request_restart_timer; gboolean has_pending_request_restart_timer; GMutex pending_request_restart_timer_lock; gboolean watches_running; } BatchedAckTracker; static void _ack_record_free(AckRecord *s) { BatchedAckRecord *self = (BatchedAckRecord *) s; bookmark_destroy(&self->super.bookmark); g_free(self); } static void _ack_batch(BatchedAckTracker *self, GList *ack_records) { self->on_batch_acked.func(ack_records, self->on_batch_acked.user_data); g_list_free_full(ack_records, (GDestroyNotify) _ack_record_free); } static Bookmark * _request_bookmark(AckTracker *s) { BatchedAckTracker *self = (BatchedAckTracker *) s; if (!self->pending_ack_record) self->pending_ack_record = g_new0(BatchedAckRecord, 1); return &(self->pending_ack_record->super.bookmark); } static void _assign_pending_ack_record_to_msg(BatchedAckTracker *self, LogMessage *msg) { LogSource *source = self->super.source; log_pipe_ref((LogPipe *) source); self->pending_ack_record->super.bookmark.persist_state = source->super.cfg->state; self->pending_ack_record->super.tracker = &self->super; msg->ack_record = (AckRecord *) self->pending_ack_record; } static void _track_msg(AckTracker *s, LogMessage *msg) { BatchedAckTracker *self = (BatchedAckTracker *)s; _assign_pending_ack_record_to_msg(self, msg); self->pending_ack_record = NULL; } static GList * _append_ack_record_to_batch(BatchedAckTracker *self, AckRecord *ack_record) { GList *full_batch = NULL; g_mutex_lock(&self->acked_records_lock); { self->acked_records = g_list_prepend(self->acked_records, ack_record); ++self->acked_records_num; if (self->acked_records_num == self->batch_size) { full_batch = self->acked_records; self->acked_records = NULL; self->acked_records_num = 0; } } g_mutex_unlock(&self->acked_records_lock); return full_batch; } static void _stop_batch_timer(BatchedAckTracker *self) { if (iv_timer_registered(&self->batch_timer)) iv_timer_unregister(&self->batch_timer); } static void _start_batch_timer(BatchedAckTracker *self) { if (self->timeout <= 0) return; iv_validate_now(); self->batch_timer.expires = iv_now; timespec_add_msec(&self->batch_timer.expires, self->timeout); iv_timer_register(&self->batch_timer); } static void _restart_batch_timer(BatchedAckTracker *self) { _stop_batch_timer(self); _start_batch_timer(self); } static void _batch_timeout(gpointer data) { msg_trace("BatchedAckTracker::batch_timeout"); BatchedAckTracker *self = (BatchedAckTracker *) data; GList *batch = NULL; g_mutex_lock(&self->acked_records_lock); { batch = self->acked_records; self->acked_records = NULL; self->acked_records_num = 0; } g_mutex_unlock(&self->acked_records_lock); if (batch) { _ack_batch(self, batch); } _start_batch_timer(self); } static void _restart_timer_requested(gpointer data) { BatchedAckTracker *self = (BatchedAckTracker *) data; g_mutex_lock(&self->pending_request_restart_timer_lock); { g_assert(self->has_pending_request_restart_timer); self->has_pending_request_restart_timer = FALSE; if (!log_pipe_unref(&self->super.source->super)) _restart_batch_timer(self); } g_mutex_unlock(&self->pending_request_restart_timer_lock); } static void _start_watches(BatchedAckTracker *self) { if (!self->watches_running) { _start_batch_timer(self); self->watches_running = TRUE; } } static void _stop_watches(BatchedAckTracker *self) { if (self->watches_running) { _stop_batch_timer(self); self->watches_running = FALSE; } } static void __free(AckTracker *s) { msg_trace("BatchedAckTracker::free"); BatchedAckTracker *self = (BatchedAckTracker *) s; g_mutex_clear(&self->acked_records_lock); self->has_pending_request_restart_timer = TRUE; _stop_watches(self); g_mutex_clear(&self->pending_request_restart_timer_lock); if (self->acked_records) _ack_batch(self, self->acked_records); if (self->pending_ack_record) _ack_record_free(&self->pending_ack_record->super); iv_event_unregister(&self->request_restart_timer); iv_event_unregister(&self->request_destroy); g_free(self); } static void _destroy(gpointer data) { BatchedAckTracker *self = (BatchedAckTracker *) data; __free(&self->super); } static void _init_watches(BatchedAckTracker *self) { IV_TIMER_INIT(&self->batch_timer); self->batch_timer.cookie = self; self->batch_timer.handler = _batch_timeout; IV_EVENT_INIT(&self->request_restart_timer); self->request_restart_timer.cookie = self; self->request_restart_timer.handler = _restart_timer_requested; IV_EVENT_INIT(&self->request_destroy); self->request_destroy.cookie = self; self->request_destroy.handler = _destroy; } static void _request_batch_timer_restart(BatchedAckTracker *self) { g_mutex_lock(&self->pending_request_restart_timer_lock); { if (!self->has_pending_request_restart_timer) { self->has_pending_request_restart_timer = TRUE; log_pipe_ref(&self->super.source->super); iv_event_post(&self->request_restart_timer); } } g_mutex_unlock(&self->pending_request_restart_timer_lock); } static void _manage_msg_ack(AckTracker *s, LogMessage *msg, AckType ack_type) { BatchedAckTracker *self = (BatchedAckTracker *) s; gboolean need_to_restart_batch_timer = FALSE; log_source_flow_control_adjust(self->super.source, 1); if (ack_type == AT_SUSPENDED) log_source_flow_control_suspend(self->super.source); if (ack_type != AT_ABORTED) { GList *full_batch = _append_ack_record_to_batch(self, msg->ack_record); if (full_batch) { _ack_batch(self, full_batch); need_to_restart_batch_timer = TRUE; } } else { _ack_record_free(msg->ack_record); } log_msg_unref(msg); if (!log_pipe_unref((LogPipe *)self->super.source) && need_to_restart_batch_timer) { _request_batch_timer_restart(self); } } static void _free(AckTracker *s) { msg_trace("BatchedAckTracker::request destroy"); BatchedAckTracker *self = (BatchedAckTracker *) s; iv_event_post(&self->request_destroy); } static void _ack_partial_batch(BatchedAckTracker *self) { GList *partial_batch = NULL; g_mutex_lock(&self->acked_records_lock); { partial_batch = self->acked_records; self->acked_records = NULL; self->acked_records_num = 0; } g_mutex_unlock(&self->acked_records_lock); _ack_batch(self, partial_batch); } static gboolean _init(AckTracker *s) { BatchedAckTracker *self = (BatchedAckTracker *)s; _start_watches(self); return TRUE; } static void _deinit(AckTracker *s) { BatchedAckTracker *self = (BatchedAckTracker *) s; _stop_watches(self); _ack_partial_batch(self); } static void _setup_callbacks(AckTracker *s) { s->request_bookmark = _request_bookmark; s->track_msg = _track_msg; s->manage_msg_ack = _manage_msg_ack; s->free_fn = _free; s->init = _init; s->deinit = _deinit; } static void _init_instance(AckTracker *s, LogSource *source, guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked cb, gpointer user_data) { BatchedAckTracker *self = (BatchedAckTracker *) s; _setup_callbacks(s); s->source = source; source->ack_tracker = s; self->timeout = timeout; self->batch_size = batch_size; self->pending_ack_record = NULL; self->on_batch_acked.func = cb; self->on_batch_acked.user_data = user_data; g_mutex_init(&self->acked_records_lock); g_mutex_init(&self->pending_request_restart_timer_lock); _init_watches(self); iv_event_register(&self->request_restart_timer); iv_event_register(&self->request_destroy); } AckTracker * batched_ack_tracker_new(LogSource *source, guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked on_batch_acked, gpointer user_data) { BatchedAckTracker *self = g_new0(BatchedAckTracker, 1); _init_instance(&self->super, source, timeout, batch_size, on_batch_acked, user_data); g_assert(batch_size > 0); /* * It is mandatory to process the batched ACKs * */ g_assert(self->on_batch_acked.func != NULL); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/batched_ack_tracker.h000066400000000000000000000026171450431004300244120ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef BATCHED_ACK_TRACKER_H_INCLUDED #define BATCHED_ACK_TRACKER_H_INCLUDED #include "ack_tracker.h" typedef void (*BatchedAckTrackerOnBatchAcked)(GList *ack_records, gpointer user_data); AckTracker *batched_ack_tracker_new(LogSource *source, guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked on_batch_acked, gpointer user_data); #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/batched_ack_tracker_factory.c000066400000000000000000000051731450431004300261340ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ack_tracker_factory.h" #include "batched_ack_tracker.h" typedef struct _BatchedAckTrackerFactory { AckTrackerFactory super; struct { guint timeout; guint batch_size; } options; struct { BatchedAckTrackerOnBatchAcked func; gpointer user_data; } on_batch_acked; } BatchedAckTrackerFactory; static AckTracker * _factory_create(AckTrackerFactory *s, LogSource *source) { BatchedAckTrackerFactory *self = (BatchedAckTrackerFactory *) s; return batched_ack_tracker_new(source, self->options.timeout, self->options.batch_size, self->on_batch_acked.func, self->on_batch_acked.user_data); } static void _factory_free(AckTrackerFactory *s) { BatchedAckTrackerFactory *self = (BatchedAckTrackerFactory *)s; g_free(self); } static void _init_instance(AckTrackerFactory *s, guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked cb, gpointer user_data) { BatchedAckTrackerFactory *self = (BatchedAckTrackerFactory *) s; ack_tracker_factory_init_instance(s); self->options.timeout = timeout; self->options.batch_size = batch_size; self->on_batch_acked.func = cb; self->on_batch_acked.user_data = user_data; s->create = _factory_create; s->free_fn = _factory_free; s->type = ACK_BATCHED; } AckTrackerFactory * batched_ack_tracker_factory_new(guint timeout, guint batch_size, BatchedAckTrackerOnBatchAcked cb, gpointer user_data) { BatchedAckTrackerFactory *factory = g_new0(BatchedAckTrackerFactory, 1); _init_instance(&factory->super, timeout, batch_size, cb, user_data); return &factory->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/bookmark.h000066400000000000000000000032621450431004300222710ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef BOOKMARK_H_INCLUDED #define BOOKMARK_H_INCLUDED #include "syslog-ng.h" #include "persist-state.h" #define MAX_BOOKMARK_DATA_LENGTH (128) typedef struct _BookmarkContainer { /* Bookmark structure should be aligned (ie. HPUX-11v2 ia64) */ gint64 other_state[MAX_BOOKMARK_DATA_LENGTH/sizeof(gint64)]; } BookmarkContainer; struct _Bookmark { PersistState *persist_state; void (*save)(Bookmark *self); void (*destroy)(Bookmark *self); BookmarkContainer container; }; static inline void bookmark_save(Bookmark *self) { if (self->save) { self->save(self); } } static inline void bookmark_destroy(Bookmark *self) { if (self->destroy) { self->destroy(self); } } #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_record_container.h000066400000000000000000000064461450431004300272400ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONSECUTIVE_ACK_RECORD_CONTAINER_H_INCLUDED #define CONSECUTIVE_ACK_RECORD_CONTAINER_H_INCLUDED #include "ack_tracker.h" typedef struct _ConsecutiveAckRecord { AckRecord super; gboolean acked; } ConsecutiveAckRecord; typedef struct _ConsecutiveAckRecordContainer ConsecutiveAckRecordContainer; struct _ConsecutiveAckRecordContainer { gboolean (*is_empty)(const ConsecutiveAckRecordContainer *s); ConsecutiveAckRecord *(*request_pending)(ConsecutiveAckRecordContainer *s); void (*store_pending)(ConsecutiveAckRecordContainer *s); void (*drop)(ConsecutiveAckRecordContainer *s, gsize n); ConsecutiveAckRecord *(*at)(const ConsecutiveAckRecordContainer *s, gsize idx); void (*free_fn)(ConsecutiveAckRecordContainer *s); gsize (*size)(const ConsecutiveAckRecordContainer *s); gsize (*get_continual_range_length)(const ConsecutiveAckRecordContainer *s); }; static inline void consecutive_ack_record_destroy(ConsecutiveAckRecord *self) { bookmark_destroy(&self->super.bookmark); } ConsecutiveAckRecordContainer *consecutive_ack_record_container_static_new(gsize size); ConsecutiveAckRecordContainer *consecutive_ack_record_container_dynamic_new(void); static inline gboolean consecutive_ack_record_container_is_empty(ConsecutiveAckRecordContainer *s) { return s->is_empty(s); } static inline ConsecutiveAckRecord * consecutive_ack_record_container_request_pending(ConsecutiveAckRecordContainer *s) { return s->request_pending(s); } static inline void consecutive_ack_record_container_store_pending(ConsecutiveAckRecordContainer *s) { s->store_pending(s); } static inline gsize consecutive_ack_record_container_size(const ConsecutiveAckRecordContainer *s) { return s->size(s); } static inline void consecutive_ack_record_container_drop(ConsecutiveAckRecordContainer *s, gsize n) { g_assert(n <= consecutive_ack_record_container_size(s)); s->drop(s, n); } static inline ConsecutiveAckRecord * consecutive_ack_record_container_at(const ConsecutiveAckRecordContainer *s, gsize idx) { return s->at(s, idx); } static inline void consecutive_ack_record_container_free(ConsecutiveAckRecordContainer *s) { s->free_fn(s); } static inline gsize consecutive_ack_record_container_get_continual_range_length(const ConsecutiveAckRecordContainer *s) { return s->get_continual_range_length(s); } #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_record_container_dynamic.c000066400000000000000000000114371450431004300307330ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "consecutive_ack_record_container.h" typedef struct _DynamicConsecutiveAckRecordContainer { ConsecutiveAckRecordContainer super; GList *head; GList *tail; gsize size; ConsecutiveAckRecord *pending; } DynamicConsecutiveAckRecordContainer; static gboolean _is_empty(const ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *) s; return (!self->head || self->size == 0); } static ConsecutiveAckRecord * _request_pending(ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *)s; if (self->pending) return self->pending; self->pending = g_new0(ConsecutiveAckRecord, 1); return self->pending; } static void _store_pending(ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *) s; if (self->head == NULL) { self->head = g_list_append(self->head, self->pending); self->tail = self->head; } else { g_assert(g_list_append(self->tail, self->pending) == self->tail); self->tail = self->tail->next; } self->size++; self->pending = NULL; } static void _free_and_destroy_ack_record(gpointer data) { ConsecutiveAckRecord *rec = (ConsecutiveAckRecord *)data; consecutive_ack_record_destroy(rec); g_free(rec); } static void _drop(ConsecutiveAckRecordContainer *s, gsize n) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *) s; if (n == self->size) { g_list_free_full(self->head, _free_and_destroy_ack_record); self->head = self->tail = NULL; self->size = 0; return; } GList *delete_head = self->head; GList *last = g_list_nth(self->head, n-1); self->head = last->next; self->head->prev = NULL; self->size -= n; last->next = NULL; g_list_free_full(delete_head, _free_and_destroy_ack_record); } static ConsecutiveAckRecord * _at(const ConsecutiveAckRecordContainer *s, gsize idx) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *) s; return (ConsecutiveAckRecord *) g_list_nth(self->head, idx)->data; } static void _free(ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *)s; if (self->pending) { consecutive_ack_record_destroy(self->pending); g_free(self->pending); self->pending = NULL; } g_list_free_full(self->head, _free_and_destroy_ack_record); self->head = NULL; self->tail = NULL; g_free(self); } static gsize _size(const ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *)s; return self->size; } static inline gboolean _ack_range_is_continuous(void *data) { ConsecutiveAckRecord *ack_rec = (ConsecutiveAckRecord *)data; return ack_rec->acked; } static gsize _get_continual_range_length(const ConsecutiveAckRecordContainer *s) { DynamicConsecutiveAckRecordContainer *self = (DynamicConsecutiveAckRecordContainer *)s; guint32 ack_range_length = 0; for (GList *it = self->head; it != NULL && _ack_range_is_continuous(it->data); it = it->next) { ++ack_range_length; } return ack_range_length; } ConsecutiveAckRecordContainer * consecutive_ack_record_container_dynamic_new(void) { DynamicConsecutiveAckRecordContainer *self = g_new0(DynamicConsecutiveAckRecordContainer, 1); self->super.is_empty = _is_empty; self->super.request_pending = _request_pending; self->super.store_pending = _store_pending; self->super.drop = _drop; self->super.at = _at; self->super.free_fn = _free; self->super.size = _size; self->super.get_continual_range_length = _get_continual_range_length; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_record_container_static.c000066400000000000000000000103451450431004300305730ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "consecutive_ack_record_container.h" #include "ringbuffer.h" typedef struct _StaticConsecutiveAckRecordContainer { ConsecutiveAckRecordContainer super; RingBuffer ack_records; ConsecutiveAckRecord *pending; } StaticConsecutiveAckRecordContainer; static gboolean _is_empty(const ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; return ring_buffer_is_empty(&self->ack_records); } static ConsecutiveAckRecord * _request_pending(ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; if (self->pending) return self->pending; self->pending = ring_buffer_tail(&self->ack_records); return self->pending; } static void _store_pending(ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; g_assert(ring_buffer_push(&self->ack_records) == self->pending); self->pending = NULL; } static void _drop(ConsecutiveAckRecordContainer *s, gsize n) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; int i; ConsecutiveAckRecord *ack_rec; for (i = 0; i < n; i++) { ack_rec = (ConsecutiveAckRecord *)ring_buffer_element_at(&self->ack_records, i); ack_rec->acked = FALSE; consecutive_ack_record_destroy(ack_rec); ack_rec->super.bookmark.save = NULL; ack_rec->super.bookmark.destroy = NULL; } ring_buffer_drop(&self->ack_records, n); } static ConsecutiveAckRecord * _at(const ConsecutiveAckRecordContainer *s, gsize idx) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; return ring_buffer_element_at(&self->ack_records, idx); } static void _free(ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; guint32 count = ring_buffer_count(&self->ack_records); _drop(s, count); ring_buffer_free(&self->ack_records); g_free(self); } static gsize _size(const ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; return ring_buffer_count(&self->ack_records); } static inline gboolean _ack_range_is_continuous(void *data) { ConsecutiveAckRecord *ack_rec = (ConsecutiveAckRecord *)data; return ack_rec->acked; } static gsize _get_continual_range_length(const ConsecutiveAckRecordContainer *s) { StaticConsecutiveAckRecordContainer *self = (StaticConsecutiveAckRecordContainer *)s; return ring_buffer_get_continual_range_length(&self->ack_records, _ack_range_is_continuous); } ConsecutiveAckRecordContainer * consecutive_ack_record_container_static_new(gsize size) { StaticConsecutiveAckRecordContainer *self = g_new0(StaticConsecutiveAckRecordContainer, 1); self->super.is_empty = _is_empty; self->super.request_pending = _request_pending; self->super.store_pending = _store_pending; self->super.drop = _drop; self->super.at = _at; self->super.free_fn = _free; self->super.size = _size; self->super.get_continual_range_length = _get_continual_range_length; ring_buffer_alloc(&self->ack_records, sizeof(ConsecutiveAckRecord), size); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_tracker.c000066400000000000000000000172741450431004300253470ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "consecutive_ack_tracker.h" #include "consecutive_ack_record_container.h" #include "bookmark.h" #include "syslog-ng.h" typedef struct _ConsecutiveAckTracker { AckTracker super; ConsecutiveAckRecord *pending_ack_record; ConsecutiveAckRecordContainer *ack_records; GMutex mutex; AckTrackerOnAllAcked on_all_acked; gboolean bookmark_saving_disabled; } ConsecutiveAckTracker; void consecutive_ack_tracker_lock(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; g_mutex_lock(&self->mutex); } void consecutive_ack_tracker_unlock(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; g_mutex_unlock(&self->mutex); } void consecutive_ack_tracker_set_on_all_acked(AckTracker *s, AckTrackerOnAllAckedFunc func, gpointer user_data, GDestroyNotify user_data_free_fn) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; if (self->on_all_acked.user_data && self->on_all_acked.user_data_free_fn) { self->on_all_acked.user_data_free_fn(self->on_all_acked.user_data); } self->on_all_acked = (AckTrackerOnAllAcked) { .func = func, .user_data = user_data, .user_data_free_fn = user_data_free_fn }; } static inline void consecutive_ack_tracker_on_all_acked_call(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; AckTrackerOnAllAcked *handler = &self->on_all_acked; if (handler->func) { handler->func(handler->user_data); } } static void _ack_records_track_msg(ConsecutiveAckTracker *self, LogMessage *msg) { consecutive_ack_record_container_store_pending(self->ack_records); msg->ack_record = (AckRecord *) self->pending_ack_record; self->pending_ack_record = NULL; } static void consecutive_ack_tracker_track_msg(AckTracker *s, LogMessage *msg) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; LogSource *source = self->super.source; g_assert(self->pending_ack_record != NULL); log_pipe_ref((LogPipe *)source); consecutive_ack_tracker_lock(s); { _ack_records_track_msg(self, msg); } consecutive_ack_tracker_unlock(s); } static gboolean _is_bookmark_saving_enabled(ConsecutiveAckTracker *self) { return self->bookmark_saving_disabled == FALSE; } static void _ack_record_save_bookmark(ConsecutiveAckRecord *ack_record) { Bookmark *bookmark = &(ack_record->super.bookmark); bookmark_save(bookmark); } static guint32 _ack_records_untrack_msg(ConsecutiveAckTracker *self, LogMessage *msg, AckType ack_type) { guint32 ack_range_length = consecutive_ack_record_container_get_continual_range_length(self->ack_records); if (ack_range_length > 0) { if (ack_type != AT_ABORTED && _is_bookmark_saving_enabled(self)) { _ack_record_save_bookmark(consecutive_ack_record_container_at(self->ack_records, ack_range_length - 1)); } consecutive_ack_record_container_drop(self->ack_records, ack_range_length); } return ack_range_length; } static void consecutive_ack_tracker_manage_msg_ack(AckTracker *s, LogMessage *msg, AckType ack_type) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; ConsecutiveAckRecord *ack_rec = (ConsecutiveAckRecord *)msg->ack_record; ack_rec->acked = TRUE; if (ack_type == AT_SUSPENDED) log_source_flow_control_suspend(self->super.source); consecutive_ack_tracker_lock(s); { guint32 ack_range_length = _ack_records_untrack_msg(self, msg, ack_type); if (ack_range_length > 0) { if (ack_type == AT_SUSPENDED) log_source_flow_control_adjust_when_suspended(self->super.source, ack_range_length); else log_source_flow_control_adjust(self->super.source, ack_range_length); if (consecutive_ack_tracker_is_empty(s)) consecutive_ack_tracker_on_all_acked_call(s); } } consecutive_ack_tracker_unlock(s); log_msg_unref(msg); log_pipe_unref((LogPipe *)self->super.source); } gboolean consecutive_ack_tracker_is_empty(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; return consecutive_ack_record_container_is_empty(self->ack_records); } static Bookmark * consecutive_ack_tracker_request_bookmark(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; if (!self->pending_ack_record) { consecutive_ack_tracker_lock(s); self->pending_ack_record = consecutive_ack_record_container_request_pending(self->ack_records); consecutive_ack_tracker_unlock(s); } if (self->pending_ack_record) { self->pending_ack_record->super.bookmark.persist_state = s->source->super.cfg->state; self->pending_ack_record->super.tracker = (AckTracker *)self; return &(self->pending_ack_record->super.bookmark); } return NULL; } static void consecutive_ack_tracker_free(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; AckTrackerOnAllAcked *handler = &self->on_all_acked; if (handler->user_data_free_fn && handler->user_data) { handler->user_data_free_fn(handler->user_data); } g_mutex_clear(&self->mutex); consecutive_ack_record_container_free(self->ack_records); g_free(self); } static void consecutive_ack_tracker_disable_bookmark_saving(AckTracker *s) { ConsecutiveAckTracker *self = (ConsecutiveAckTracker *)s; consecutive_ack_tracker_lock(s); { self->bookmark_saving_disabled = TRUE; } consecutive_ack_tracker_unlock(s); } static void _setup_callbacks(ConsecutiveAckTracker *self) { self->super.request_bookmark = consecutive_ack_tracker_request_bookmark; self->super.track_msg = consecutive_ack_tracker_track_msg; self->super.manage_msg_ack = consecutive_ack_tracker_manage_msg_ack; self->super.disable_bookmark_saving = consecutive_ack_tracker_disable_bookmark_saving; self->super.free_fn = consecutive_ack_tracker_free; } static void consecutive_ack_tracker_init_instance(ConsecutiveAckTracker *self, LogSource *source, ConsecutiveAckRecordContainer *ack_records) { self->super.source = source; source->ack_tracker = (AckTracker *)self; self->ack_records = ack_records; g_mutex_init(&self->mutex); _setup_callbacks(self); } static ConsecutiveAckRecordContainer * _create_ack_record_container(LogSource *source) { if (log_source_is_dynamic_window_enabled(source)) return consecutive_ack_record_container_dynamic_new(); return consecutive_ack_record_container_static_new(log_source_get_init_window_size(source)); } AckTracker * consecutive_ack_tracker_new(LogSource *source) { ConsecutiveAckTracker *self = g_new0(ConsecutiveAckTracker, 1); ConsecutiveAckRecordContainer *ack_records = _create_ack_record_container(source); consecutive_ack_tracker_init_instance(self, source, ack_records); return (AckTracker *)self; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_tracker.h000066400000000000000000000034161450431004300253450ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONSECUTIVE_ACK_TRACKER_H_INCLUDED #define CONSECUTIVE_ACK_TRACKER_H_INCLUDED #include "ack_tracker.h" typedef struct _AckTrackerOnAllAcked AckTrackerOnAllAcked; typedef void (*AckTrackerOnAllAckedFunc)(gpointer); struct _AckTrackerOnAllAcked { AckTrackerOnAllAckedFunc func; gpointer user_data; GDestroyNotify user_data_free_fn; }; gboolean consecutive_ack_tracker_is_empty(AckTracker *self); void consecutive_ack_tracker_lock(AckTracker *self); void consecutive_ack_tracker_unlock(AckTracker *self); void consecutive_ack_tracker_set_on_all_acked(AckTracker *s, AckTrackerOnAllAckedFunc func, gpointer user_data, GDestroyNotify user_data_free_fn); AckTracker *consecutive_ack_tracker_new(LogSource *source); #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/consecutive_ack_tracker_factory.c000066400000000000000000000034611450431004300270670ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ack_tracker_factory.h" #include "consecutive_ack_tracker.h" typedef struct _ConsecutiveAckTrackerFactory { AckTrackerFactory super; } ConsecutiveAckTrackerFactory; static AckTracker * _factory_create(AckTrackerFactory *s, LogSource *source) { return consecutive_ack_tracker_new(source); } static void _factory_free(AckTrackerFactory *s) { ConsecutiveAckTrackerFactory *self = (ConsecutiveAckTrackerFactory *)s; g_free(self); } static void _init_instance(AckTrackerFactory *s) { ack_tracker_factory_init_instance(s); s->create = _factory_create; s->free_fn = _factory_free; s->type = ACK_CONSECUTIVE; } AckTrackerFactory * consecutive_ack_tracker_factory_new(void) { ConsecutiveAckTrackerFactory *factory = g_new0(ConsecutiveAckTrackerFactory, 1); _init_instance(&factory->super); return &factory->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/instant_ack_tracker.c000066400000000000000000000065161450431004300244750ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "instant_ack_tracker.h" #include "ack_tracker.h" #include "bookmark.h" #include "syslog-ng.h" typedef struct _InstantAckRecord { AckRecord super; void *padding; } InstantAckRecord; typedef struct _InstantAckTracker { AckTracker super; InstantAckRecord *pending_ack_record; } InstantAckTracker; static Bookmark * _request_bookmark(AckTracker *s) { InstantAckTracker *self = (InstantAckTracker *)s; if (!self->pending_ack_record) self->pending_ack_record = g_new0(InstantAckRecord, 1); return &(self->pending_ack_record->super.bookmark); } static void _track_msg(AckTracker *s, LogMessage *msg) { InstantAckTracker *self = (InstantAckTracker *)s; log_pipe_ref((LogPipe *)self->super.source); self->pending_ack_record->super.bookmark.persist_state = s->source->super.cfg->state; self->pending_ack_record->super.tracker = s; msg->ack_record = (AckRecord *) self->pending_ack_record; self->pending_ack_record = NULL; } static void _save_bookmark(LogMessage *msg) { bookmark_save(&msg->ack_record->bookmark); } static void _ack_record_free(AckRecord *s) { bookmark_destroy(&s->bookmark); g_free(s); } static void _manage_msg_ack(AckTracker *s, LogMessage *msg, AckType ack_type) { InstantAckTracker *self = (InstantAckTracker *)s; _save_bookmark(msg); _ack_record_free(msg->ack_record); log_source_flow_control_adjust(self->super.source, 1); if (ack_type == AT_SUSPENDED) log_source_flow_control_suspend(self->super.source); log_msg_unref(msg); log_pipe_unref((LogPipe *)self->super.source); } static void _free(AckTracker *s) { InstantAckTracker *self = (InstantAckTracker *)s; if (self->pending_ack_record) g_free(self->pending_ack_record); g_free(self); } static void _setup_callbacks(InstantAckTracker *self) { self->super.request_bookmark = _request_bookmark; self->super.track_msg = _track_msg; self->super.manage_msg_ack = _manage_msg_ack; self->super.free_fn = _free; } static void _init_instance(InstantAckTracker *self, LogSource *source) { self->super.source = source; source->ack_tracker = (AckTracker *)self; self->pending_ack_record = NULL; _setup_callbacks(self); } AckTracker * instant_ack_tracker_new(LogSource *source) { InstantAckTracker *self = (InstantAckTracker *)g_new0(InstantAckTracker, 1); _init_instance(self, source); return (AckTracker *)self; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/instant_ack_tracker.h000066400000000000000000000023541450431004300244760ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef INSTANT_ACK_TRACKER_H_INCLUDED #define INSTANT_ACK_TRACKER_H_INCLUDED #include "ack_tracker.h" AckTracker *instant_ack_tracker_new(LogSource *source); AckTracker *instant_ack_tracker_bookmarkless_new(LogSource *source); #endif syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/instant_ack_tracker_bookmarkless.c000066400000000000000000000057641450431004300272550ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "instant_ack_tracker.h" #include "bookmark.h" #include "syslog-ng.h" typedef struct _InstantAckRecord { AckRecord super; void *padding; /* bookmark contains a binary container which has to be aligned */ } InstantAckRecord; typedef struct _InstantAckTrackerBookmarkless { AckTracker super; InstantAckRecord ack_record_storage; } InstantAckTrackerBookmarkless; static Bookmark * _request_bookmark(AckTracker *s) { InstantAckTrackerBookmarkless *self = (InstantAckTrackerBookmarkless *)s; return &(self->ack_record_storage.super.bookmark); } static void _track_msg(AckTracker *s, LogMessage *msg) { InstantAckTrackerBookmarkless *self = (InstantAckTrackerBookmarkless *)s; log_pipe_ref((LogPipe *)self->super.source); msg->ack_record = (AckRecord *)(&self->ack_record_storage); } static void _manage_msg_ack(AckTracker *s, LogMessage *msg, AckType ack_type) { InstantAckTrackerBookmarkless *self = (InstantAckTrackerBookmarkless *)s; log_source_flow_control_adjust(self->super.source, 1); if (ack_type == AT_SUSPENDED) log_source_flow_control_suspend(self->super.source); log_msg_unref(msg); log_pipe_unref((LogPipe *)self->super.source); } static void _free(AckTracker *s) { InstantAckTrackerBookmarkless *self = (InstantAckTrackerBookmarkless *)s; g_free(self); } static void _setup_callbacks(InstantAckTrackerBookmarkless *self) { self->super.request_bookmark = _request_bookmark; self->super.track_msg = _track_msg; self->super.manage_msg_ack = _manage_msg_ack; self->super.free_fn = _free; } static void _init_instance(InstantAckTrackerBookmarkless *self, LogSource *source) { self->super.source = source; source->ack_tracker = (AckTracker *)self; self->ack_record_storage.super.tracker = (AckTracker *)self; _setup_callbacks(self); } AckTracker * instant_ack_tracker_bookmarkless_new(LogSource *source) { InstantAckTrackerBookmarkless *self = (InstantAckTrackerBookmarkless *)g_new0(InstantAckTrackerBookmarkless, 1); _init_instance(self, source); return (AckTracker *)self; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/instant_ack_tracker_bookmarkless_factory.c000066400000000000000000000035671450431004300310030ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ack_tracker_factory.h" #include "instant_ack_tracker.h" typedef struct _InstantAckTrackerBookmarklessFactory { AckTrackerFactory super; } InstantAckTrackerBookmarklessFactory; static AckTracker * _factory_create(AckTrackerFactory *s, LogSource *source) { return instant_ack_tracker_bookmarkless_new(source); } static void _factory_free(AckTrackerFactory *s) { InstantAckTrackerBookmarklessFactory *self = (InstantAckTrackerBookmarklessFactory *)s; g_free(self); } static void _init_instance(AckTrackerFactory *s) { ack_tracker_factory_init_instance(s); s->create = _factory_create; s->free_fn = _factory_free; s->type = ACK_INSTANT_BOOKMARKLESS; } AckTrackerFactory * instant_ack_tracker_bookmarkless_factory_new(void) { InstantAckTrackerBookmarklessFactory *factory = g_new0(InstantAckTrackerBookmarklessFactory, 1); _init_instance(&factory->super); return &factory->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/instant_ack_tracker_factory.c000066400000000000000000000034501450431004300262160ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ack_tracker_factory.h" #include "instant_ack_tracker.h" typedef struct _InstantAckTrackerFactory { AckTrackerFactory super; } InstantAckTrackerFactory; static AckTracker * _instant_factory_create(AckTrackerFactory *s, LogSource *source) { return instant_ack_tracker_new(source); } static void _instant_factory_free(AckTrackerFactory *s) { InstantAckTrackerFactory *self = (InstantAckTrackerFactory *)s; g_free(self); } static void _init_instance(AckTrackerFactory *s) { ack_tracker_factory_init_instance(s); s->create = _instant_factory_create; s->free_fn = _instant_factory_free; s->type = ACK_INSTANT; } AckTrackerFactory * instant_ack_tracker_factory_new(void) { InstantAckTrackerFactory *factory = g_new0(InstantAckTrackerFactory, 1); _init_instance(&factory->super); return &factory->super; } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/000077500000000000000000000000001450431004300214525ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/CMakeLists.txt000066400000000000000000000003611450431004300242120ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_consecutive_ack_record_container) add_unit_test(CRITERION TARGET test_instant_ack_tracker) add_unit_test(CRITERION TARGET test_ack_tracker_factory) add_unit_test(CRITERION TARGET test_batched_ack_tracker) syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/Makefile.am000066400000000000000000000015741450431004300235150ustar00rootroot00000000000000lib_ack_tracker_tests_TESTS = \ lib/ack-tracker/tests/test_consecutive_ack_record_container \ lib/ack-tracker/tests/test_instant_ack_tracker \ lib/ack-tracker/tests/test_ack_tracker_factory \ lib/ack-tracker/tests/test_batched_ack_tracker check_PROGRAMS += \ ${lib_ack_tracker_tests_TESTS} lib_ack_tracker_tests_test_consecutive_ack_record_container_LDADD = $(TEST_LDADD) lib_ack_tracker_tests_test_consecutive_ack_record_container_CFLAGS = $(TEST_CFLAGS) lib_ack_tracker_tests_test_instant_ack_tracker_LDADD = $(TEST_LDADD) lib_ack_tracker_tests_test_instant_ack_tracker_CFLAGS = $(TEST_CFLAGS) lib_ack_tracker_tests_test_ack_tracker_factory_LDADD = $(TEST_LDADD) lib_ack_tracker_tests_test_ack_tracker_factory_CFLAGS = $(TEST_CFLAGS) lib_ack_tracker_tests_test_batched_ack_tracker_LDADD = $(TEST_LDADD) lib_ack_tracker_tests_test_batched_ack_tracker_CFLAGS = $(TEST_CFLAGS) syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/test_ack_tracker_factory.c000066400000000000000000000037071450431004300266640ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "ack-tracker/ack_tracker_factory.h" static void _dummy_on_batch_acked(GList *ack_records, gpointer user_data) { } Test(AckTrackerFactory, position_tracking) { AckTrackerFactory *instant = instant_ack_tracker_factory_new(); AckTrackerFactory *bookmarkless = instant_ack_tracker_bookmarkless_factory_new(); AckTrackerFactory *consecutive = consecutive_ack_tracker_factory_new(); AckTrackerFactory *batched = batched_ack_tracker_factory_new(0, 1, _dummy_on_batch_acked, NULL); cr_expect(ack_tracker_type_is_position_tracked(instant->type)); cr_expect_not(ack_tracker_type_is_position_tracked(bookmarkless->type)); cr_expect(ack_tracker_type_is_position_tracked(consecutive->type)); cr_expect(ack_tracker_type_is_position_tracked(batched->type)); ack_tracker_factory_unref(instant); ack_tracker_factory_unref(bookmarkless); ack_tracker_factory_unref(consecutive); ack_tracker_factory_unref(batched); } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/test_batched_ack_tracker.c000066400000000000000000000232071450431004300266040ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "ack-tracker/batched_ack_tracker.h" #include "ack-tracker/ack_tracker_factory.h" #include "logsource.h" #include "apphook.h" #include "timeutils/misc.h" #include GlobalConfig *cfg; static LogSource * _init_log_source(AckTrackerFactory *factory) { LogSource *src = g_new0(LogSource, 1); LogSourceOptions *options = g_new0(LogSourceOptions, 1); log_source_options_defaults(options); options->init_window_size = 10; log_source_init_instance(src, cfg); log_source_options_init(options, cfg, "testgroup"); log_source_set_options(src, options, "test_stats_id", NULL, TRUE, NULL); log_source_set_ack_tracker_factory(src, factory); cr_assert(log_pipe_init(&src->super)); return src; } static void _deinit_log_source(LogSource *src) { log_pipe_deinit(&src->super); g_free(src->options); log_pipe_unref(&src->super); } typedef struct _TestBookmarkData { guint *saved_ctr; guint *destroy_ctr; } TestBookmarkData; static void _save_bookmark(Bookmark *bookmark) { TestBookmarkData *bookmark_data = (TestBookmarkData *) &bookmark->container; (*bookmark_data->saved_ctr)++; } static void _destroy_bookmark(Bookmark *bookmark) { TestBookmarkData *bookmark_data = (TestBookmarkData *) &bookmark->container; (*bookmark_data->destroy_ctr)++; } static void _fill_bookmark(Bookmark *bookmark, guint *saved_ctr, guint *destroy_ctr) { TestBookmarkData *bookmark_data = (TestBookmarkData *) &bookmark->container; bookmark_data->saved_ctr = saved_ctr; bookmark_data->destroy_ctr = destroy_ctr; bookmark->save = _save_bookmark; bookmark->destroy = _destroy_bookmark; } typedef struct _TestLogPipeDst { LogPipe super; } TestLogPipeDst; static gboolean _test_logpipe_dst_init(LogPipe *s) { return TRUE; } static void _test_logpipe_dst_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { } static TestLogPipeDst * _init_test_logpipe_dst(void) { TestLogPipeDst *dst = g_new0(TestLogPipeDst, 1); log_pipe_init_instance(&dst->super, cfg); dst->super.init = _test_logpipe_dst_init; dst->super.queue = _test_logpipe_dst_queue; cr_assert(log_pipe_init(&dst->super)); return dst; } static void _deinit_test_logpipe_dst(TestLogPipeDst *dst) { log_pipe_deinit(&dst->super); log_pipe_unref(&dst->super); } static void _setup(void) { cfg = cfg_new_snippet(); app_startup(); } static void _teardown(void) { app_shutdown(); cfg_free(cfg); } TestSuite(batched_ack_tracker, .init = _setup, .fini = _teardown); static void _dummy_on_batch_acked(GList *ack_records, gpointer user_data) { gboolean *acked = (gboolean *) user_data; *acked = TRUE; } Test(batched_ack_tracker, request_bookmark_returns_the_same_until_not_track_msg) { gboolean acked = FALSE; LogSource *src = _init_log_source(batched_ack_tracker_factory_new(0, 1, _dummy_on_batch_acked, &acked)); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm1 = ack_tracker_request_bookmark(ack_tracker); Bookmark *bm2 = ack_tracker_request_bookmark(ack_tracker); cr_expect_eq(bm1, bm2); LogMessage *msg = log_msg_new_empty(); ack_tracker_track_msg(ack_tracker, msg); cr_expect_not(acked); Bookmark *bm3 = ack_tracker_request_bookmark(ack_tracker); cr_expect_neq(bm3, bm1); ack_tracker_manage_msg_ack(ack_tracker, msg, AT_PROCESSED); cr_expect(acked); _deinit_log_source(src); } static void _ack(AckRecord *rec) { bookmark_save(&rec->bookmark); } static void _ack_all(GList *ack_records, gpointer user_data) { if (user_data) { gboolean *cb_called = (gboolean *) user_data; *cb_called = TRUE; } g_list_foreach(ack_records, (GFunc) _ack, user_data); } Test(batched_ack_tracker, bookmark_saving) { LogSource *src = _init_log_source(batched_ack_tracker_factory_new(0, 2, _ack_all, NULL)); TestLogPipeDst *dst = _init_test_logpipe_dst(); log_pipe_append(&src->super, &dst->super); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm = ack_tracker_request_bookmark(ack_tracker); guint saved_ctr = 0; guint destroy_ctr = 0; _fill_bookmark(bm, &saved_ctr, &destroy_ctr); LogMessage *msg1 = log_msg_new_empty(); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_source_post(src, msg1); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); cr_assert_eq(msg1->ack_record->tracker, ack_tracker); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_ack(msg1, &path_options, AT_PROCESSED); cr_expect_eq(saved_ctr, 0); cr_expect_eq(destroy_ctr, 0); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); LogMessage *msg2 = log_msg_new_empty(); bm = ack_tracker_request_bookmark(ack_tracker); _fill_bookmark(bm, &saved_ctr, &destroy_ctr); log_source_post(src, msg2); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); log_msg_ack(msg2, &path_options, AT_PROCESSED); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); cr_expect_eq(saved_ctr, 2); cr_expect_eq(destroy_ctr, 2); log_msg_unref(msg1); log_msg_unref(msg2); _deinit_log_source(src); _deinit_test_logpipe_dst(dst); } static void _iv_quit(void *user_data) { iv_quit(); } static void _run_iv_main_for_n_seconds(gint seconds) { struct iv_timer wait_timer; IV_TIMER_INIT(&wait_timer); wait_timer.cookie = NULL; wait_timer.handler = _iv_quit; iv_validate_now(); wait_timer.expires = iv_now; timespec_add_msec(&wait_timer.expires, seconds * 1000); iv_timer_register(&wait_timer); iv_main(); } Test(batched_ack_tracker, batch_timeout) { LogSource *src = _init_log_source(batched_ack_tracker_factory_new(500, 3, _ack_all, NULL)); TestLogPipeDst *dst = _init_test_logpipe_dst(); log_pipe_append(&src->super, &dst->super); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm = ack_tracker_request_bookmark(ack_tracker); guint saved_ctr = 0; guint destroy_ctr = 0; _fill_bookmark(bm, &saved_ctr, &destroy_ctr); LogMessage *msg1 = log_msg_new_empty(); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_source_post(src, msg1); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); cr_assert_eq(msg1->ack_record->tracker, ack_tracker); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_ack(msg1, &path_options, AT_PROCESSED); cr_expect_eq(saved_ctr, 0); cr_expect_eq(destroy_ctr, 0); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); LogMessage *msg2 = log_msg_new_empty(); bm = ack_tracker_request_bookmark(ack_tracker); _fill_bookmark(bm, &saved_ctr, &destroy_ctr); log_source_post(src, msg2); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); log_msg_ack(msg2, &path_options, AT_PROCESSED); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); _run_iv_main_for_n_seconds(1); cr_expect_eq(saved_ctr, 2); cr_expect_eq(destroy_ctr, 2); log_msg_unref(msg1); log_msg_unref(msg2); _deinit_log_source(src); _deinit_test_logpipe_dst(dst); } Test(batched_ack_tracker, deinit_acks_partial_batch) { gboolean ack_cb_called = FALSE; LogSource *src = _init_log_source(batched_ack_tracker_factory_new(2000, 3, _ack_all, &ack_cb_called)); TestLogPipeDst *dst = _init_test_logpipe_dst(); log_pipe_append(&src->super, &dst->super); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm = ack_tracker_request_bookmark(ack_tracker); guint saved_ctr = 0; guint destroy_ctr = 0; _fill_bookmark(bm, &saved_ctr, &destroy_ctr); LogMessage *msg1 = log_msg_new_empty(); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_source_post(src, msg1); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); cr_assert_eq(msg1->ack_record->tracker, ack_tracker); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_ack(msg1, &path_options, AT_PROCESSED); cr_expect_eq(saved_ctr, 0); cr_expect_eq(destroy_ctr, 0); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); LogMessage *msg2 = log_msg_new_empty(); bm = ack_tracker_request_bookmark(ack_tracker); _fill_bookmark(bm, &saved_ctr, &destroy_ctr); log_source_post(src, msg2); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); log_msg_ack(msg2, &path_options, AT_PROCESSED); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); ack_tracker_deinit(ack_tracker); cr_expect(ack_cb_called); _run_iv_main_for_n_seconds(1); cr_expect_eq(saved_ctr, 2); cr_expect_eq(destroy_ctr, 2); log_msg_unref(msg1); log_msg_unref(msg2); _deinit_log_source(src); _deinit_test_logpipe_dst(dst); } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/test_consecutive_ack_record_container.c000066400000000000000000000272701450431004300314320ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "ack-tracker/consecutive_ack_record_container.h" typedef struct _TestBookmark { gsize idx; } TestBookmark; static TestBookmark * _ack_record_extract_bookmark(ConsecutiveAckRecord *self) { return (TestBookmark *)&(self->super.bookmark.container); } static void _ack_record_write_idx_to_bookmark(ConsecutiveAckRecord *self, gsize idx) { TestBookmark *bookmark = _ack_record_extract_bookmark(self); bookmark->idx = idx; } static void _fill_container(ConsecutiveAckRecordContainer *container, gsize n, gsize idx_shift) { for (gsize i = 0; i < n; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_request_pending(container); rec->acked = FALSE; _ack_record_write_idx_to_bookmark(rec, i + idx_shift); consecutive_ack_record_container_store_pending(container); } } static void _set_ack_range(ConsecutiveAckRecordContainer *ack_records, gsize start, gsize n) { for (gsize i = start; i < start + n; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_at(ack_records, i); rec->acked = TRUE; } } static void _assert_ack_range(ConsecutiveAckRecordContainer *ack_records, gsize start, gsize n, gboolean expected_acked) { for (gsize i = start; i < start + n; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_at(ack_records, i); cr_assert_eq(rec->acked, expected_acked); } } static void _assert_indexes(ConsecutiveAckRecordContainer *ack_records, gsize n, gsize idx_shift) { for (gsize i = 0; i < n; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_at(ack_records, i); TestBookmark *bookmark = _ack_record_extract_bookmark(rec); cr_assert_eq(bookmark->idx, i + idx_shift); } } Test(consecutive_ack_record_container_static, is_empty) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { cr_expect_eq(consecutive_ack_record_container_size(ack_records), 0); cr_expect(consecutive_ack_record_container_is_empty(ack_records)); _fill_container(ack_records, capacity, 0); cr_expect_not(consecutive_ack_record_container_is_empty(ack_records)); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 32); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, request_store_pending) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { for (gsize i = 0; i < capacity; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_request_pending(ack_records); _ack_record_write_idx_to_bookmark(rec, i); consecutive_ack_record_container_store_pending(ack_records); rec = consecutive_ack_record_container_at(ack_records, i); TestBookmark *bookmark = _ack_record_extract_bookmark(rec); cr_expect_eq(bookmark->idx, i); } } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, drop_more_than_current_size, .signal = SIGABRT) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); consecutive_ack_record_container_drop(ack_records, 16); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 16); // when trying to drop more than current size, should assert (->SIGABRT) consecutive_ack_record_container_drop(ack_records, 20); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, drop_from_the_beginning) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); consecutive_ack_record_container_drop(ack_records, 16); _assert_indexes(ack_records, 16, 16); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 16); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, request_pending_should_return_null_when_capacity_reached) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); ConsecutiveAckRecord *rec = consecutive_ack_record_container_request_pending(ack_records); cr_expect_eq(rec, NULL); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, store_pending_should_not_modify_container_when_capacity_reached) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); consecutive_ack_record_container_store_pending(ack_records); _assert_indexes(ack_records, 32, 0); ConsecutiveAckRecord *rec = consecutive_ack_record_container_request_pending(ack_records); cr_expect_eq(rec, NULL); consecutive_ack_record_container_store_pending(ack_records); _assert_indexes(ack_records, 32, 0); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, after_drop_from_a_full_container_can_store_new_element) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); consecutive_ack_record_container_drop(ack_records, 1); ConsecutiveAckRecord *rec = consecutive_ack_record_container_at(ack_records, 0); TestBookmark *bookmark = _ack_record_extract_bookmark(rec); cr_expect_eq(bookmark->idx, 1); _fill_container(ack_records, 1, 32); //append new element, idx = 32 cr_expect_eq(consecutive_ack_record_container_size(ack_records), capacity); // all values shifted by 1 _assert_indexes(ack_records, capacity, 1); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_static, get_continual_range_length) { static const gsize capacity = 32; ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_static_new(capacity); { _fill_container(ack_records, capacity, 0); _set_ack_range(ack_records, 1, 15); _assert_ack_range(ack_records, 0, 1, FALSE); _assert_ack_range(ack_records, 1, 15, TRUE); _assert_ack_range(ack_records, 16, 16, FALSE); cr_expect_eq(consecutive_ack_record_container_get_continual_range_length(ack_records), 0); consecutive_ack_record_container_drop(ack_records, 1); // drop unacked... cr_expect_eq(consecutive_ack_record_container_get_continual_range_length(ack_records), 15); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, is_empty) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { cr_expect_eq(consecutive_ack_record_container_size(ack_records), 0); cr_expect(consecutive_ack_record_container_is_empty(ack_records)); _fill_container(ack_records, 32, 0); cr_expect_not(consecutive_ack_record_container_is_empty(ack_records)); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 32); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, request_store_pending) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { for (gsize i = 0; i < 32; i++) { ConsecutiveAckRecord *rec = consecutive_ack_record_container_request_pending(ack_records); _ack_record_write_idx_to_bookmark(rec, i); consecutive_ack_record_container_store_pending(ack_records); rec = consecutive_ack_record_container_at(ack_records, i); TestBookmark *bookmark = _ack_record_extract_bookmark(rec); cr_expect_eq(bookmark->idx, i); } } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, drop_more_than_current_size, .signal = SIGABRT) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { _fill_container(ack_records, 32, 0); consecutive_ack_record_container_drop(ack_records, 16); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 16); // when trying to drop more than current size, remove all the elements consecutive_ack_record_container_drop(ack_records, 20); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, drop_from_the_beginning) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { _fill_container(ack_records, 32, 0); consecutive_ack_record_container_drop(ack_records, 16); _assert_indexes(ack_records, 16, 16); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 16); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, get_continual_range_length) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { _fill_container(ack_records, 32, 0); _set_ack_range(ack_records, 1, 15); _assert_ack_range(ack_records, 0, 1, FALSE); _assert_ack_range(ack_records, 1, 15, TRUE); _assert_ack_range(ack_records, 16, 16, FALSE); cr_expect_eq(consecutive_ack_record_container_get_continual_range_length(ack_records), 0); consecutive_ack_record_container_drop(ack_records, 1); // drop unacked... cr_expect_eq(consecutive_ack_record_container_get_continual_range_length(ack_records), 15); } consecutive_ack_record_container_free(ack_records); } Test(consecutive_ack_record_container_dynamic, store_pending_after_drop_all) { ConsecutiveAckRecordContainer *ack_records = consecutive_ack_record_container_dynamic_new(); { _fill_container(ack_records, 32, 0); ConsecutiveAckRecord *pending = consecutive_ack_record_container_request_pending(ack_records); cr_assert_not_null(pending); TestBookmark *bookmark = _ack_record_extract_bookmark(pending); bookmark->idx = 111; consecutive_ack_record_container_drop(ack_records, 32); cr_expect(consecutive_ack_record_container_is_empty(ack_records)); consecutive_ack_record_container_store_pending(ack_records); cr_expect_eq(consecutive_ack_record_container_size(ack_records), 1); ConsecutiveAckRecord *rec = consecutive_ack_record_container_at(ack_records, 0); bookmark = _ack_record_extract_bookmark(rec); cr_expect_eq(bookmark->idx, 111); } consecutive_ack_record_container_free(ack_records); } syslog-ng-syslog-ng-4.4.0/lib/ack-tracker/tests/test_instant_ack_tracker.c000066400000000000000000000163061450431004300266740ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2020 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "ack-tracker/instant_ack_tracker.h" #include "ack-tracker/ack_tracker_factory.h" #include "logsource.h" #include "apphook.h" GlobalConfig *cfg; typedef struct _TestBookmarkData { guint *saved_ctr; } TestBookmarkData; static void _save_bookmark(Bookmark *bookmark) { TestBookmarkData *bookmark_data = (TestBookmarkData *) &bookmark->container; (*bookmark_data->saved_ctr)++; } static void _fill_bookmark(Bookmark *bookmark, guint *ctr) { TestBookmarkData *bookmark_data = (TestBookmarkData *) &bookmark->container; bookmark_data->saved_ctr = ctr; bookmark->save = _save_bookmark; } typedef struct _TestLogPipeDst { LogPipe super; } TestLogPipeDst; static gboolean _test_logpipe_dst_init(LogPipe *s) { return TRUE; } static void _test_logpipe_dst_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { } static TestLogPipeDst * _init_test_logpipe_dst(void) { TestLogPipeDst *dst = g_new0(TestLogPipeDst, 1); log_pipe_init_instance(&dst->super, cfg); dst->super.init = _test_logpipe_dst_init; dst->super.queue = _test_logpipe_dst_queue; cr_assert(log_pipe_init(&dst->super)); return dst; } static void _deinit_test_logpipe_dst(TestLogPipeDst *dst) { log_pipe_deinit(&dst->super); log_pipe_unref(&dst->super); } static LogSource * _init_log_source(AckTrackerFactory *factory) { LogSource *src = g_new0(LogSource, 1); LogSourceOptions *options = g_new0(LogSourceOptions, 1); log_source_options_defaults(options); options->init_window_size = 10; log_source_init_instance(src, cfg); log_source_options_init(options, cfg, "testgroup"); log_source_set_options(src, options, "test_stats_id", NULL, TRUE, NULL); log_source_set_ack_tracker_factory(src, factory); cr_assert(log_pipe_init(&src->super)); return src; } static void _deinit_log_source(LogSource *src) { log_pipe_deinit(&src->super); g_free(src->options); log_pipe_unref(&src->super); } static void _setup(void) { cfg = cfg_new_snippet(); app_startup(); } static void _teardown(void) { app_shutdown(); cfg_free(cfg); } TestSuite(instant_ack_tracker_bookmarkless, .init = _setup, .fini = _teardown); Test(instant_ack_tracker_bookmarkless, request_bookmark_returns_the_same_bookmark) { LogSource *src = _init_log_source(instant_ack_tracker_bookmarkless_factory_new()); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm1 = ack_tracker_request_bookmark(ack_tracker); Bookmark *bm2 = ack_tracker_request_bookmark(ack_tracker); cr_expect_eq(bm1, bm2); _deinit_log_source(src); } Test(instant_ack_tracker_bookmarkless, bookmark_save_not_called_when_acked) { LogSource *src = _init_log_source(instant_ack_tracker_bookmarkless_factory_new()); TestLogPipeDst *dst = _init_test_logpipe_dst(); log_pipe_append(&src->super, &dst->super); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm = ack_tracker_request_bookmark(ack_tracker); guint saved_ctr = 0; _fill_bookmark(bm, &saved_ctr); LogMessage *msg = log_msg_new_empty(); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_source_post(src, msg); // this is why we need a dummy 'destination' : keep back ACK cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); cr_assert_eq(msg->ack_record->tracker, ack_tracker); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_ack(msg, &path_options, AT_PROCESSED); // okay, ACK is done, but save counter is 0 -> so Bookmark::save not called cr_expect_eq(saved_ctr, 0); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_msg_unref(msg); _deinit_log_source(src); _deinit_test_logpipe_dst(dst); } Test(instant_ack_tracker_bookmarkless, same_bookmark_for_all_messages) { LogSource *src = _init_log_source(instant_ack_tracker_bookmarkless_factory_new()); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm1 = ack_tracker_request_bookmark(ack_tracker); LogMessage *msg1 = log_msg_new_empty(); ack_tracker_track_msg(ack_tracker, msg1); Bookmark *bm2 = ack_tracker_request_bookmark(ack_tracker); LogMessage *msg2 = log_msg_new_empty(); ack_tracker_track_msg(ack_tracker, msg2); ack_tracker_manage_msg_ack(ack_tracker, msg1, AT_PROCESSED); ack_tracker_manage_msg_ack(ack_tracker, msg2, AT_PROCESSED); cr_expect_eq(bm1, bm2); _deinit_log_source(src); } TestSuite(instant_ack_tracker, .init = _setup, .fini = _teardown); Test(instant_ack_tracker, request_bookmark_returns_same_bookmarks_until_pending_not_assigned) { LogSource *src = _init_log_source(instant_ack_tracker_factory_new()); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm1 = ack_tracker_request_bookmark(ack_tracker); Bookmark *bm2 = ack_tracker_request_bookmark(ack_tracker); cr_expect_eq(bm1, bm2); LogMessage *msg = log_msg_new_empty(); ack_tracker_track_msg(ack_tracker, msg); log_msg_ref(msg); bm2 = ack_tracker_request_bookmark(ack_tracker); cr_expect_neq(bm1, bm2); ack_tracker_manage_msg_ack(ack_tracker, msg, AT_PROCESSED); log_msg_unref(msg); _deinit_log_source(src); } Test(instant_ack_tracker, bookmark_saving) { LogSource *src = _init_log_source(instant_ack_tracker_factory_new()); TestLogPipeDst *dst = _init_test_logpipe_dst(); log_pipe_append(&src->super, &dst->super); cr_assert_not_null(src->ack_tracker); AckTracker *ack_tracker = src->ack_tracker; Bookmark *bm = ack_tracker_request_bookmark(ack_tracker); guint saved_ctr = 0; _fill_bookmark(bm, &saved_ctr); LogMessage *msg = log_msg_new_empty(); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_source_post(src, msg); // this is why we need a dummy 'destination' : keep back ACK cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 9); cr_assert_eq(msg->ack_record->tracker, ack_tracker); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_ack(msg, &path_options, AT_PROCESSED); // okay, ACK is done, save counter is 1 cr_expect_eq(saved_ctr, 1); cr_expect_eq(window_size_counter_get(&src->window_size, NULL), 10); log_msg_unref(msg); _deinit_log_source(src); _deinit_test_logpipe_dst(dst); } syslog-ng-syslog-ng-4.4.0/lib/afinter.c000066400000000000000000000454511450431004300177260ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinter.h" #include "logreader.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-logpipe.h" #include "stats/stats-cluster-single.h" #include "messages.h" #include "apphook.h" #include "mainloop-threaded-worker.h" #include typedef struct _AFInterSource AFInterSource; static GMutex internal_msg_lock; static GQueue *internal_msg_queue; static AFInterSource *current_internal_source; static AFInterMetrics metrics; /* the expiration timer of the next MARK message */ static struct timespec next_mark_target = { -1, 0 }; /* as different sources from different threads can call afinter_postpone_mark, and we use the value in the init thread, we need to synchronize the value references */ static GMutex internal_mark_target_lock; /* * This class is parallel to LogReader, e.g. it hangs on the * AFInterSourceDriver on the left (e.g. feeds messages to * AFInterSourceDriver). * * Threading: * ========== * * syslog-ng can generate internal() messages in any of its threads, thus * some care must be taken to make the internal() source multithreaded. * This is how it works: * * Whenever a thread decides to send a message using the msg_() API, it puts * an entry into the internal_msg_queue under the protection of * "internal_msg_lock". * * The receiving side of this queue is in the main thread, where the * internal() source is operating. This object will publish a pointer to * itself into current_internal_source. This pointer will be set under the * protection of the internal_msg_lock. The internal source will define an * ivykis event, a post is submitted to this event whenever a new message is * added to the queue. * * Once the event arrives to the main loop, it wakes up and feeds all * internal messages into the log path. * * If the window is depleted (e.g. flow control is enabled and the * destination is unable to process any more messages), * free_to_send will be set to FALSE, which means that messages * will be added to the queue, but the wakeup will not be done. * * When the window becomes free, log_source_wakeup() is called, which * restores the free_to_send flag (e.g. further messages will * wake up the source) and also starts emptying the messages accumulated in the queue. * * Possible races: * =============== * * The biggest offenders are when a client thread submits a message and * we're in the process of getting asleep (no window), or waking up. There * are notes in the code how we handle these cases (search for "Possible race"). * */ struct _AFInterSource { LogSource super; MainLoopThreadedWorker thread; gint mark_freq; const AFInterSourceOptions *options; struct iv_event post; struct iv_event schedule_wakeup; struct iv_event exit; struct iv_timer mark_timer; struct iv_task restart_task; guint watches_running:1, free_to_send:1; }; static void afinter_source_update_watches(AFInterSource *self); void afinter_message_posted(LogMessage *msg); static void afinter_source_post(gpointer s) { AFInterSource *self = (AFInterSource *) s; LogMessage *msg; while (log_source_free_to_send(&self->super)) { g_mutex_lock(&internal_msg_lock); msg = g_queue_pop_head(internal_msg_queue); g_mutex_unlock(&internal_msg_lock); if (!msg) break; stats_counter_dec(metrics.queued); stats_counter_inc(metrics.processed); log_source_post(&self->super, msg); main_loop_worker_invoke_batch_callbacks(); } afinter_source_update_watches(self); } static void afinter_source_start_watches(AFInterSource *self); static void afinter_source_stop_watches(AFInterSource *self); static gboolean afinter_source_thread_init(MainLoopThreadedWorker *s) { AFInterSource *self = (AFInterSource *) s->data; /* post event is used by other threads and can only be unregistered if * current_afinter_source is set to NULL in a thread safe manner */ iv_event_register(&self->post); iv_event_register(&self->schedule_wakeup); iv_event_register(&self->exit); return TRUE; } static void afinter_source_thread_deinit(MainLoopThreadedWorker *s) { AFInterSource *self = (AFInterSource *) s->data; iv_event_unregister(&self->exit); iv_event_unregister(&self->post); iv_event_unregister(&self->schedule_wakeup); } static void afinter_source_run(MainLoopThreadedWorker *s) { AFInterSource *self = (AFInterSource *) s->data; g_mutex_lock(&internal_msg_lock); self->free_to_send = TRUE; g_mutex_unlock(&internal_msg_lock); afinter_source_start_watches(self); afinter_source_update_watches(self); iv_main(); g_mutex_lock(&internal_msg_lock); current_internal_source = NULL; g_mutex_unlock(&internal_msg_lock); afinter_source_stop_watches(self); } static void afinter_source_thread_request_exit(MainLoopThreadedWorker *s) { AFInterSource *self = (AFInterSource *) s->data; iv_event_post(&self->exit); } static gboolean afinter_source_start_thread(LogSource *s) { AFInterSource *self = (AFInterSource *) s; main_loop_threaded_worker_start(&self->thread); return TRUE; } static void afinter_source_mark(gpointer s) { AFInterSource *self = (AFInterSource *) s; struct timespec nmt; g_mutex_lock(&internal_mark_target_lock); nmt = next_mark_target; g_mutex_unlock(&internal_mark_target_lock); if (nmt.tv_sec <= self->mark_timer.expires.tv_sec) { /* the internal_mark_target has not been overwritten by an incoming message in afinter_postpone_mark (there was no msg in the meantime) -> the mark msg can be sent */ afinter_message_posted(log_msg_new_mark()); /* the next_mark_target will be increased in afinter_postpone_mark */ } } static void afinter_source_wakeup(LogSource *s) { AFInterSource *self = (AFInterSource *) s; /* * We might get called even after this AFInterSource has been * deinitialized, in which case we must not do anything (since the * iv_event triggered here is not registered). * * This happens when log_writer_deinit() flushes its output queue * after the internal source which produced the message has already been * deinited. Since init/deinit calls are made in the main thread, no * locking is needed. * */ if (self->super.super.flags & PIF_INITIALIZED) iv_event_post(&self->schedule_wakeup); } static void afinter_source_init_watches(AFInterSource *self) { IV_EVENT_INIT(&self->post); self->post.cookie = self; self->post.handler = afinter_source_post; IV_TIMER_INIT(&self->mark_timer); self->mark_timer.cookie = self; self->mark_timer.handler = afinter_source_mark; IV_EVENT_INIT(&self->schedule_wakeup); self->schedule_wakeup.cookie = self; self->schedule_wakeup.handler = (void (*)(void *)) afinter_source_update_watches; IV_EVENT_INIT(&self->exit); self->exit.cookie = NULL; self->exit.handler = (void (*)(void *)) iv_quit; IV_TASK_INIT(&self->restart_task); self->restart_task.cookie = self; self->restart_task.handler = afinter_source_post; } static void afinter_source_start_watches(AFInterSource *self) { if (!self->watches_running) { if (self->mark_timer.expires.tv_sec >= 0) iv_timer_register(&self->mark_timer); self->watches_running = TRUE; } } static void afinter_source_stop_watches(AFInterSource *self) { if (self->watches_running) { if (iv_task_registered(&self->restart_task)) iv_task_unregister(&self->restart_task); if (iv_timer_registered(&self->mark_timer)) iv_timer_unregister(&self->mark_timer); self->watches_running = FALSE; } } static void afinter_source_update_watches(AFInterSource *self) { if (!log_source_free_to_send(&self->super)) { /* ok, we go to sleep now. let's disable the post event. * Messages get accumulated into internal_msg_queue. */ g_mutex_lock(&internal_msg_lock); self->free_to_send = FALSE; g_mutex_unlock(&internal_msg_lock); /* Possible race: * * After the check log_source_free_to_send() above, the destination * may actually write out a message, thus by the time we get here, the * window may have space again. This is taken care of by the fact * that the wakeup is running in the main thread, which we do too. So * the wakeup is either completely performed before we entered this * function, or after we return. * * In case it happened earlier, the check above will find that we have * window space, in case it's going to be happening afterwards, we * will be woken up by the schedule_wakeup event (which calls * update_watches again). */ /* MARK events also get disabled */ afinter_source_stop_watches(self); } else { /* ok we can send our stuff. make sure we wake up */ afinter_source_stop_watches(self); self->mark_timer.expires = next_mark_target; afinter_source_start_watches(self); /* Possible race: * * The free_to_send flag is set to FALSE here (in case * we're just waking up). In case the sender submits a message, it'll * not trigger the self->post (since free_to_send is FALSE). This is * taken care of by the queue-length check in the locked region below. * If the queue has elements, we need to wake up, because we may have * lost a wakeup call. If it happens after the locked region, that * doesn't matter, in that case we already set * free_to_send = TRUE to ourselves, thus the post event will also * be triggered. */ g_mutex_lock(&internal_msg_lock); if (internal_msg_queue && g_queue_get_length(internal_msg_queue) > 0) iv_task_register(&self->restart_task); self->free_to_send = TRUE; g_mutex_unlock(&internal_msg_lock); } } static gboolean afinter_source_init(LogPipe *s) { AFInterSource *self = (AFInterSource *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_source_init(s)) return FALSE; self->mark_freq = cfg->mark_freq; afinter_postpone_mark(self->mark_freq); self->mark_timer.expires = next_mark_target; g_mutex_lock(&internal_msg_lock); current_internal_source = self; stats_counter_set(metrics.queue_capacity, self->options->queue_capacity); g_mutex_unlock(&internal_msg_lock); return TRUE; } static gboolean afinter_source_deinit(LogPipe *s) { AFInterSource *self = (AFInterSource *) s; g_mutex_lock(&internal_msg_lock); current_internal_source = NULL; g_mutex_unlock(&internal_msg_lock); return log_source_deinit(&self->super.super); } static void afinter_source_free(LogPipe *s) { AFInterSource *self = (AFInterSource *) s; main_loop_threaded_worker_clear(&self->thread); log_source_free(s); } static LogSource * afinter_source_new(AFInterSourceDriver *owner, AFInterSourceOptions *options) { AFInterSource *self = g_new0(AFInterSource, 1); log_source_init_instance(&self->super, owner->super.super.super.cfg); log_source_set_options(&self->super, &options->super, owner->super.super.id, NULL, FALSE, owner->super.super.super.expr_node); main_loop_threaded_worker_init(&self->thread, MLW_THREADED_INPUT_WORKER, self); self->thread.thread_init = afinter_source_thread_init; self->thread.thread_deinit = afinter_source_thread_deinit; self->thread.run = afinter_source_run; self->thread.request_exit = afinter_source_thread_request_exit; afinter_source_init_watches(self); self->super.super.init = afinter_source_init; self->super.super.deinit = afinter_source_deinit; self->super.wakeup = afinter_source_wakeup; self->super.super.free_fn = afinter_source_free; self->options = options; return &self->super; } void afinter_source_options_defaults(AFInterSourceOptions *options) { log_source_options_defaults(&options->super); options->queue_capacity = 10000; } static gboolean afinter_sd_pre_config_init(LogPipe *s) { main_loop_worker_allocate_thread_space(1); return TRUE; } static gboolean afinter_sd_init(LogPipe *s) { AFInterSourceDriver *self = (AFInterSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_29)) { msg_warning_once("WARNING: The internal_queue_length stat counter has been renamed to internal_source.queued", cfg_format_config_version_tag(cfg)); } if (!log_src_driver_init_method(s)) return FALSE; if (current_internal_source != NULL) { msg_error("Multiple internal() sources were detected, this is not possible"); return FALSE; } log_source_options_init(&self->source_options.super, cfg, self->super.super.group); self->source_options.super.stats_level = STATS_LEVEL0; self->source_options.super.stats_source = stats_register_type("internal"); self->source = afinter_source_new(self, &self->source_options); log_pipe_append(&self->source->super, s); if (!log_pipe_init(&self->source->super)) { log_pipe_unref(&self->source->super); self->source = NULL; return FALSE; } return TRUE; } static gboolean afinter_sd_post_config_init(LogPipe *s) { AFInterSourceDriver *self = (AFInterSourceDriver *) s; return afinter_source_start_thread(self->source); } static gboolean afinter_sd_deinit(LogPipe *s) { AFInterSourceDriver *self = (AFInterSourceDriver *) s; if (self->source) { log_pipe_deinit(&self->source->super); /* break circular reference created during _init */ log_pipe_unref(&self->source->super); self->source = NULL; } if (!log_src_driver_deinit_method(s)) return FALSE; return TRUE; } static void afinter_sd_free(LogPipe *s) { AFInterSourceDriver *self = (AFInterSourceDriver *) s; g_assert(!self->source); log_src_driver_free(s); } LogDriver * afinter_sd_new(GlobalConfig *cfg) { AFInterSourceDriver *self = g_new0(AFInterSourceDriver, 1); log_src_driver_init_instance((LogSrcDriver *)&self->super, cfg); self->super.super.super.pre_config_init = afinter_sd_pre_config_init; self->super.super.super.init = afinter_sd_init; self->super.super.super.deinit = afinter_sd_deinit; self->super.super.super.free_fn = afinter_sd_free; self->super.super.super.post_config_init = afinter_sd_post_config_init; afinter_source_options_defaults(&self->source_options); return (LogDriver *)&self->super.super; } /**************************************************************************** * Global entry points, without an AFInterSourceDriver instance. ****************************************************************************/ void afinter_postpone_mark(gint mark_freq) { if (mark_freq > 0) { iv_validate_now(); g_mutex_lock(&internal_mark_target_lock); next_mark_target = iv_now; next_mark_target.tv_sec += mark_freq; g_mutex_unlock(&internal_mark_target_lock); } else { g_mutex_lock(&internal_mark_target_lock); next_mark_target.tv_sec = -1; g_mutex_unlock(&internal_mark_target_lock); } } static void _release_internal_msg_queue(void) { LogMessage *internal_message = g_queue_pop_head(internal_msg_queue); while (internal_message) { stats_counter_dec(metrics.queued); log_msg_unref(internal_message); internal_message = g_queue_pop_head(internal_msg_queue); } g_queue_free(internal_msg_queue); internal_msg_queue = NULL; } void afinter_message_posted(LogMessage *msg) { g_mutex_lock(&internal_msg_lock); if (!current_internal_source) { if (internal_msg_queue) { _release_internal_msg_queue(); } log_msg_unref(msg); goto exit; } if (!internal_msg_queue) { internal_msg_queue = g_queue_new(); stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_set(&sc_key, "internal_events_total", NULL, 0); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_GLOBAL, "internal_source", NULL ); stats_register_counter(0, &sc_key, SC_TYPE_QUEUED, &metrics.queued); stats_register_counter(0, &sc_key, SC_TYPE_DROPPED, &metrics.dropped); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &metrics.processed); stats_cluster_single_key_set(&sc_key, "internal_events_queue_capacity", NULL, 0); stats_register_counter(0, &sc_key, SC_TYPE_SINGLE_VALUE, &metrics.queue_capacity); stats_unlock(); stats_counter_set(metrics.queue_capacity, current_internal_source->options->queue_capacity); } if (g_queue_get_length(internal_msg_queue) >= current_internal_source->options->queue_capacity) { stats_counter_inc(metrics.dropped); log_msg_unref(msg); goto exit; } g_queue_push_tail(internal_msg_queue, msg); stats_counter_inc(metrics.queued); if (current_internal_source->free_to_send) iv_event_post(¤t_internal_source->post); exit: g_mutex_unlock(&internal_msg_lock); } static void afinter_register_posted_hook(gint hook_type, gpointer user_data) { msg_set_post_func(afinter_message_posted); } void afinter_global_init(void) { register_application_hook(AH_CONFIG_CHANGED, afinter_register_posted_hook, NULL, AHM_RUN_ONCE); } void afinter_global_deinit(void) { if (internal_msg_queue) { stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_set(&sc_key, "internal_events_total", NULL, 0); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_GLOBAL, "internal_source", NULL ); stats_unregister_counter(&sc_key, SC_TYPE_QUEUED, &metrics.queued); stats_unregister_counter(&sc_key, SC_TYPE_DROPPED, &metrics.dropped); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &metrics.processed); stats_cluster_single_key_set(&sc_key, "internal_events_queue_capacity", NULL, 0); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &metrics.queue_capacity); stats_unlock(); g_queue_free_full(internal_msg_queue, (GDestroyNotify)log_msg_unref); internal_msg_queue = NULL; } current_internal_source = NULL; } AFInterMetrics afinter_get_metrics(void) { return metrics; } syslog-ng-syslog-ng-4.4.0/lib/afinter.h000066400000000000000000000035351450431004300177300ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SDINTER_H_INCLUDED #define SDINTER_H_INCLUDED #include "driver.h" #include "logsource.h" #include "mainloop-worker.h" #include "stats/stats-counter.h" typedef struct AFInterSourceOptions { LogSourceOptions super; gint queue_capacity; } AFInterSourceOptions; /* * This is the actual source driver, linked into the configuration tree. */ typedef struct _AFInterSourceDriver { LogSrcDriver super; LogSource *source; AFInterSourceOptions source_options; } AFInterSourceDriver; typedef struct _AFInterMetrics { StatsCounterItem *processed; StatsCounterItem *dropped; StatsCounterItem *queued; StatsCounterItem *queue_capacity; } AFInterMetrics; void afinter_postpone_mark(gint mark_freq); LogDriver *afinter_sd_new(GlobalConfig *cfg); void afinter_global_init(void); void afinter_global_deinit(void); AFInterMetrics afinter_get_metrics(void); #endif syslog-ng-syslog-ng-4.4.0/lib/alarms.c000066400000000000000000000034351450431004300175510ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "alarms.h" #include "messages.h" #include #include #include static gboolean sig_alarm_received = FALSE; static gboolean alarm_pending = FALSE; static void sig_alarm_handler(int signo) { sig_alarm_received = TRUE; } void alarm_set(int timeout) { if (G_UNLIKELY(alarm_pending)) { msg_error("Internal error, alarm_set() called while an alarm is still active"); return; } alarm(timeout); alarm_pending = TRUE; } void alarm_cancel(void) { alarm(0); sig_alarm_received = FALSE; alarm_pending = FALSE; } gboolean alarm_has_fired(void) { gboolean res = sig_alarm_received; return res; } void alarm_init(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_alarm_handler; sigaction(SIGALRM, &sa, NULL); } syslog-ng-syslog-ng-4.4.0/lib/alarms.h000066400000000000000000000022621450431004300175530ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ALARMS_H_INCLUDED #define ALARMS_H_INCLUDED #include "syslog-ng.h" void alarm_set(int timeout); void alarm_cancel(void); gboolean alarm_has_fired(void); void alarm_init(void); #endif syslog-ng-syslog-ng-4.4.0/lib/apphook.c000066400000000000000000000207511450431004300177330ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "apphook.h" #include "messages.h" #include "children.h" #include "dnscache.h" #include "alarms.h" #include "stats/stats-registry.h" #include "healthcheck/healthcheck-stats.h" #include "logmsg/logmsg.h" #include "logsource.h" #include "logwriter.h" #include "afinter.h" #include "template/templates.h" #include "hostname.h" #include "mainloop-call.h" #include "service-management.h" #include "crypto.h" #include "value-pairs/value-pairs.h" #include "scratch-buffers.h" #include "mainloop.h" #include "secret-storage/nondumpable-allocator.h" #include "secret-storage/secret-storage.h" #include "transport/transport-factory-id.h" #include "timeutils/timeutils.h" #include "msg-stats.h" #include "timeutils/cache.h" #include "multi-line/multi-line-factory.h" #include #include typedef struct _ApplicationHookEntry { gint type; ApplicationHookRunMode run_mode; ApplicationHookFunc func; gpointer user_data; } ApplicationHookEntry; typedef struct _ApplicationThreadHookEntry { ApplicationThreadHookFunc func; gpointer user_data; } ApplicationThreadHookEntry; static GList *application_hooks = NULL; static GList *application_thread_init_hooks = NULL; static GList *application_thread_deinit_hooks = NULL; static gint current_state = AH_STARTUP; gboolean app_is_starting_up(void) { return current_state < AH_RUNNING; } gboolean app_is_shutting_down(void) { return current_state >= AH_PRE_SHUTDOWN; } void register_application_hook(gint type, ApplicationHookFunc func, gpointer user_data, ApplicationHookRunMode run_mode) { if (type > __AH_STATE_MAX || current_state < type) { ApplicationHookEntry *entry = g_new0(ApplicationHookEntry, 1); entry->type = type; entry->func = func; entry->user_data = user_data; entry->run_mode = run_mode; application_hooks = g_list_prepend(application_hooks, entry); } else { /* the requested hook has already passed, call the requested function immediately */ msg_debug("Application hook registered after the given point passed", evt_tag_int("current", current_state), evt_tag_int("hook", type)); func(type, user_data); } } void register_application_thread_init_hook(ApplicationThreadHookFunc func, gpointer user_data) { ApplicationThreadHookEntry *entry = g_new0(ApplicationThreadHookEntry, 1); entry->func = func; entry->user_data = user_data; application_thread_init_hooks = g_list_prepend(application_thread_init_hooks, entry); } void register_application_thread_deinit_hook(ApplicationThreadHookFunc func, gpointer user_data) { ApplicationThreadHookEntry *entry = g_new0(ApplicationThreadHookEntry, 1); entry->func = func; entry->user_data = user_data; application_thread_deinit_hooks = g_list_prepend(application_thread_deinit_hooks, entry); } static void run_application_thread_init_hooks(void) { for (GList *elem = application_thread_init_hooks; elem; elem = elem->next) { ApplicationThreadHookEntry *hook = (ApplicationThreadHookEntry *) elem->data; hook->func(hook->user_data); } } static void run_application_thread_deinit_hooks(void) { for (GList *elem = application_thread_deinit_hooks; elem; elem = elem->next) { ApplicationThreadHookEntry *hook = (ApplicationThreadHookEntry *) elem->data; hook->func(hook->user_data); } } static void _update_current_state(gint type) { if (type > __AH_STATE_MAX) return; g_assert(current_state <= type); current_state = type; } static void run_application_hook(gint type) { GList *l, *l_next; _update_current_state(type); msg_debug("Running application hooks", evt_tag_int("hook", type)); for (l = application_hooks; l; l = l_next) { ApplicationHookEntry *e = l->data; if (e->type == type) { l_next = l->next; e->func(type, e->user_data); if (e->run_mode == AHM_RUN_ONCE) { application_hooks = g_list_remove_link(application_hooks, l); g_free(e); g_list_free_1(l); } else { g_assert(e->run_mode == AHM_RUN_REPEAT); } } else { l_next = l->next; } } } static void app_fatal(const char *msg) { fprintf(stderr, "%s\n", msg); } #define construct_nondumpable_logger(logger) \ void \ nondumpable_allocator_ ## logger (gchar *summary, gchar *reason) \ { \ logger(summary, evt_tag_str("reason", reason)); \ } construct_nondumpable_logger(msg_debug); construct_nondumpable_logger(msg_fatal); void app_startup(void) { msg_init(FALSE); iv_set_fatal_msg_handler(app_fatal); iv_init(); crypto_init(); hostname_global_init(); dns_caching_global_init(); dns_caching_thread_init(); afinter_global_init(); child_manager_init(); alarm_init(); main_loop_thread_resource_init(); stats_init(); healthcheck_stats_global_init(); tzset(); log_msg_global_init(); log_tags_global_init(); log_source_global_init(); log_template_global_init(); value_pairs_global_init(); service_management_init(); scratch_buffers_allocator_init(); nondumpable_setlogger(nondumpable_allocator_msg_debug, nondumpable_allocator_msg_fatal); secret_storage_init(); transport_factory_id_global_init(); scratch_buffers_global_init(); msg_stats_init(); timeutils_global_init(); multi_line_global_init(); } void app_post_daemonized(void) { run_application_hook(AH_POST_DAEMONIZED); } void app_running(void) { run_application_hook(AH_RUNNING); } void app_pre_shutdown(void) { run_application_hook(AH_PRE_SHUTDOWN); } void app_shutdown(void) { msg_stats_deinit(); run_application_hook(AH_SHUTDOWN); multi_line_global_deinit(); main_loop_thread_resource_deinit(); secret_storage_deinit(); scratch_buffers_allocator_deinit(); scratch_buffers_global_deinit(); value_pairs_global_deinit(); log_template_global_deinit(); log_tags_global_deinit(); log_msg_global_deinit(); afinter_global_deinit(); stats_destroy(); child_manager_deinit(); g_list_foreach(application_hooks, (GFunc) g_free, NULL); g_list_free(application_hooks); g_list_free_full(application_thread_init_hooks, g_free); g_list_free_full(application_thread_deinit_hooks, g_free); dns_caching_thread_deinit(); dns_caching_global_deinit(); hostname_global_deinit(); crypto_deinit(); msg_deinit(); transport_factory_id_global_deinit(); /* NOTE: the iv_deinit() call should come here, but there's some exit * synchronization issue in libivykis that causes use-after-free with the * thread-local-state for the main thread and iv_work_pool worker threads. * I've dropped a mail to Lennert about the issue, but I'm commenting this * out for now to avoid it biting someone. Bazsi, 2013/12/23. * * iv_deinit(); */ } void app_config_pre_pre_init(void) { run_application_hook(AH_CONFIG_PRE_PRE_INIT); } void app_config_pre_init(void) { run_application_hook(AH_CONFIG_PRE_INIT); } void app_config_stopped(void) { run_application_hook(AH_CONFIG_STOPPED); } void app_config_changed(void) { run_application_hook(AH_CONFIG_CHANGED); } void app_reopen_files(void) { run_application_hook(AH_REOPEN_FILES); } void app_thread_start(void) { scratch_buffers_allocator_init(); dns_caching_thread_init(); main_loop_call_thread_init(); run_application_thread_init_hooks(); } void app_thread_stop(void) { run_application_thread_deinit_hooks(); main_loop_call_thread_deinit(); dns_caching_thread_deinit(); scratch_buffers_allocator_deinit(); timeutils_cache_deinit(); } syslog-ng-syslog-ng-4.4.0/lib/apphook.h000066400000000000000000000055601450431004300177410ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPHOOK_H_INCLUDED #define APPHOOK_H_INCLUDED #include "syslog-ng.h" enum { /* these states happen as a sequence and only happen once */ AH_STARTUP, AH_POST_DAEMONIZED, AH_RUNNING, AH_PRE_SHUTDOWN, AH_SHUTDOWN, /* this item separates state-like hooks from events happening regularly in * the RUNNING state */ __AH_STATE_MAX, /* these happen from time to time and don't update the current state of * the process */ AH_CONFIG_PRE_PRE_INIT, /* configuration pre_init() is to be called */ AH_CONFIG_PRE_INIT, /* configuration init() is to be called */ AH_CONFIG_STOPPED, /* configuration is deinitialized, threads have stopped */ AH_CONFIG_CHANGED, /* configuration changed, threads are running again */ AH_REOPEN_FILES, /* reopen files signal from syslog-ng-ctl */ }; typedef enum { AHM_RUN_ONCE, AHM_RUN_REPEAT, } ApplicationHookRunMode; /* state-like hook entry points */ void app_startup(void); void app_post_daemonized(void); void app_running(void); void app_pre_shutdown(void); void app_shutdown(void); /* stateless entry points */ void app_config_pre_pre_init(void); void app_config_pre_init(void); void app_config_stopped(void); void app_config_changed(void); void app_reopen_files(void); typedef void (*ApplicationHookFunc)(gint type, gpointer user_data); typedef void (*ApplicationThreadHookFunc)(gpointer user_data); gboolean app_is_starting_up(void); gboolean app_is_shutting_down(void); void register_application_hook(gint type, ApplicationHookFunc func, gpointer user_data, ApplicationHookRunMode run_mode); void register_application_thread_init_hook(ApplicationThreadHookFunc func, gpointer user_data); void register_application_thread_deinit_hook(ApplicationThreadHookFunc func, gpointer user_data); void app_thread_start(void); void app_thread_stop(void); #endif syslog-ng-syslog-ng-4.4.0/lib/atomic-gssize.h000066400000000000000000000062221450431004300210520ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ATOMIC_GSSIZE_H_INCLUDED #define ATOMIC_GSSIZE_H_INCLUDED #include "syslog-ng.h" G_STATIC_ASSERT(sizeof(gssize) == sizeof(gpointer)); typedef struct { gssize value; } atomic_gssize; static inline gssize atomic_gssize_add(atomic_gssize *a, gssize add) { return g_atomic_pointer_add(&a->value, add); } static inline gssize atomic_gssize_sub(atomic_gssize *a, gssize sub) { return g_atomic_pointer_add(&a->value, -1 * sub); } static inline gssize atomic_gssize_inc(atomic_gssize *a) { return g_atomic_pointer_add(&a->value, 1); } static inline gssize atomic_gssize_dec(atomic_gssize *a) { return g_atomic_pointer_add(&a->value, -1); } static inline gssize atomic_gssize_get(atomic_gssize *a) { return (gssize)g_atomic_pointer_get(&a->value); } static inline void atomic_gssize_set(atomic_gssize *a, gssize value) { g_atomic_pointer_set(&a->value, value); } static inline gsize atomic_gssize_get_unsigned(atomic_gssize *a) { return (gsize)g_atomic_pointer_get(&a->value); } static inline gssize atomic_gssize_racy_get(atomic_gssize *a) { return a->value; } static inline gsize atomic_gssize_racy_get_unsigned(atomic_gssize *a) { return (gsize)a->value; } static inline void atomic_gssize_racy_set(atomic_gssize *a, gssize value) { a->value = value; } static inline gsize atomic_gssize_or(atomic_gssize *a, gsize value) { return g_atomic_pointer_or(&a->value, value); } static inline gsize atomic_gssize_xor(atomic_gssize *a, gsize value) { return g_atomic_pointer_xor(&a->value, value); } static inline gsize atomic_gssize_and(atomic_gssize *a, gsize value) { return g_atomic_pointer_and(&a->value, value); } static inline gboolean atomic_gssize_compare_and_exchange(atomic_gssize *a, gssize oldval, gssize newval) { return g_atomic_pointer_compare_and_exchange(&a->value, oldval, newval); } static inline gssize atomic_gssize_set_and_get(atomic_gssize *a, gssize value) { gssize oldval = atomic_gssize_get(a); while (!atomic_gssize_compare_and_exchange(a, oldval, value)) { oldval = atomic_gssize_get(a); } return oldval; } #endif syslog-ng-syslog-ng-4.4.0/lib/atomic.h000066400000000000000000000034201450431004300175450ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ATOMIC_H_INCLUDED #define ATOMIC_H_INCLUDED #include "compat/glib.h" typedef struct { gint counter; } GAtomicCounter; static inline void g_atomic_counter_inc(GAtomicCounter *c) { g_atomic_int_inc(&c->counter); } static inline gboolean g_atomic_counter_dec_and_test(GAtomicCounter *c) { return g_atomic_int_dec_and_test(&c->counter); } static inline gint g_atomic_counter_get(GAtomicCounter *c) { return g_atomic_int_get(&c->counter); } static inline gint g_atomic_counter_exchange_and_add(GAtomicCounter *c, gint val) { return g_atomic_int_add(&c->counter, val); } static inline gint g_atomic_counter_racy_get(GAtomicCounter *c) { return c->counter; } static inline void g_atomic_counter_set(GAtomicCounter *c, gint value) { g_atomic_int_set(&c->counter, value); } #endif syslog-ng-syslog-ng-4.4.0/lib/block-ref-grammar.ym000066400000000000000000000032451450431004300217640ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #pragma GCC diagnostic ignored "-Wswitch-default" #include "block-ref-parser.h" #include } %define api.prefix {block_ref_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {CfgArgs **result} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %% start : { *result = cfg_args_new(); } '(' block_args ')' { YYACCEPT; } ; block_args : block_arg block_args | ; block_arg : LL_IDENTIFIER _block_arg_context_push LL_BLOCK _block_arg_context_pop { cfg_args_set(*result, $1, $3); free($1); free($3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/block-ref-parser.c000066400000000000000000000032401450431004300214220ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "block-ref-parser.h" #include "block-ref-grammar.h" extern int block_ref_debug; int block_ref_parse(CfgLexer *lexer, CfgArgs **node, gpointer arg); static CfgLexerKeyword block_ref_keywords[] = { { CFG_KEYWORD_STOP }, }; CfgLexerKeyword *block_def_keywords = block_ref_keywords; CfgParser block_ref_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &block_ref_debug, #endif .name = "block reference", .context = LL_CONTEXT_BLOCK_REF, .keywords = block_ref_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer arg)) block_ref_parse, .cleanup = (void (*)(gpointer))cfg_args_unref }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(block_ref_, BLOCK_REF_, CfgArgs **) syslog-ng-syslog-ng-4.4.0/lib/block-ref-parser.h000066400000000000000000000023541450431004300214340ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef BLOCK_REF_PARSER_H_INCLUDED #define BLOCK_REF_PARSER_H_INCLUDED #include "cfg-parser.h" extern CfgParser block_ref_parser; extern CfgLexerKeyword *block_def_keywords; CFG_PARSER_DECLARE_LEXER_BINDING(block_ref_, BLOCK_REF_, CfgArgs **) #endif syslog-ng-syslog-ng-4.4.0/lib/cache.c000066400000000000000000000043221450431004300173310ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cache.h" struct _Cache { GHashTable *hash_table; CacheResolver *resolver; }; void * cache_resolve(Cache *self, const gchar *key) { return cache_resolver_resolve_elem(self->resolver, key); } void * cache_lookup(Cache *self, const gchar *key) { gpointer result = g_hash_table_lookup(self->hash_table, key); if (!result) { result = cache_resolve(self, key); if (result) { g_hash_table_insert(self->hash_table, g_strdup(key), result); } } return result; } void cache_populate(Cache *self, const gchar *key, const gchar *value) { gpointer result = g_hash_table_lookup(self->hash_table, key); g_assert(result == NULL); g_hash_table_insert(self->hash_table, g_strdup(key), g_strdup(value)); } void cache_clear(Cache *self) { g_hash_table_unref(self->hash_table); self->hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, self->resolver->free_elem); } Cache * cache_new(CacheResolver *resolver) { Cache *self = g_new0(Cache, 1); self->resolver = resolver; self->hash_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, resolver->free_elem); return self; } void cache_free(Cache *self) { cache_resolver_free(self->resolver); g_hash_table_unref(self->hash_table); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/cache.h000066400000000000000000000041131450431004300173340ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CACHE_H_INCLUDED #define CACHE_H_INCLUDED #include "syslog-ng.h" typedef struct _CacheResolver CacheResolver; typedef struct _Cache Cache; struct _CacheResolver { gpointer (*resolve_elem)(CacheResolver *self, const gchar *key); /* NOTE: free_elem lacks a self argument as we are using it as a * GDestroyNotify callback for hashtables. Lacking a better solution * (e.g. curried functions) this means that we can't pass self here. */ void (*free_elem)(gpointer value); void (*free_fn)(CacheResolver *self); }; static inline gpointer cache_resolver_resolve_elem(CacheResolver *self, const gchar *key) { if (self->resolve_elem) { return self->resolve_elem(self, key); } return NULL; } static inline void cache_resolver_free(CacheResolver *self) { if (self->free_fn) { self->free_fn(self); } g_free(self); } void cache_populate(Cache *self, const gchar *key, const gchar *value); void *cache_resolve(Cache *self, const gchar *key); gpointer cache_lookup(Cache *self, const gchar *key); void cache_clear(Cache *self); Cache *cache_new(CacheResolver *resolver); void cache_free(Cache *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-args.c000066400000000000000000000076301450431004300177640ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-args.h" #include "messages.h" #include "str-utils.h" #include "str-repr/encode.h" #include struct _CfgArgs { gint ref_cnt; GHashTable *args; gboolean accept_varargs; }; gboolean cfg_args_is_accepting_varargs(CfgArgs *self) { return self->accept_varargs; } void cfg_args_accept_varargs(CfgArgs *self) { self->accept_varargs = TRUE; } void cfg_args_foreach(CfgArgs *self, GHFunc func, gpointer user_data) { g_hash_table_foreach(self->args, func, user_data); } static void _resolve_unknown_blockargs_as_varargs(gpointer key, gpointer value, gpointer user_data) { CfgArgs *defaults = ((gpointer *) user_data)[0]; GString *varargs = ((gpointer *) user_data)[1]; if (!defaults || !cfg_args_contains(defaults, key)) { g_string_append_printf(varargs, "%s(%s) ", (gchar *)key, (gchar *)value); } } gchar * cfg_args_format_varargs(CfgArgs *self, CfgArgs *defaults) { GString *varargs = g_string_new(""); gpointer user_data[] = { defaults, varargs }; cfg_args_foreach(self, _resolve_unknown_blockargs_as_varargs, user_data); return g_string_free(varargs, FALSE); } void cfg_args_set(CfgArgs *self, const gchar *name, const gchar *value) { g_hash_table_insert(self->args, __normalize_key(name), g_strdup(value)); } const gchar * cfg_args_get(CfgArgs *self, const gchar *name) { const gchar *value = g_hash_table_lookup(self->args, name); if (!value) { gchar *normalized_name = __normalize_key(name); value = g_hash_table_lookup(self->args, normalized_name); g_free(normalized_name); } return value; } gboolean cfg_args_get_as_boolean(CfgArgs *self, const gchar *name) { const gchar *value = cfg_args_get(self, name); if (strcmp(value, "yes") == 0) return TRUE; else if (strcmp(value, "no") == 0) return FALSE; gint n = atoi(value); return n != 0; } gboolean cfg_args_contains(CfgArgs *self, const gchar *name) { gchar *normalized_name = __normalize_key(name); gboolean contains = g_hash_table_lookup_extended(self->args, normalized_name, NULL, NULL); g_free(normalized_name); return contains; } void cfg_args_remove_normalized(CfgArgs *self, const gchar *normalized_name) { gpointer orig_key; if (g_hash_table_lookup_extended(self->args, normalized_name, &orig_key, NULL)) { g_hash_table_remove(self->args, orig_key); } } void cfg_args_remove(CfgArgs *self, const gchar *name) { gchar *normalized_name = __normalize_key(name); cfg_args_remove_normalized(self, normalized_name); g_free(normalized_name); } CfgArgs * cfg_args_new(void) { CfgArgs *self = g_new0(CfgArgs, 1); self->args = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); self->ref_cnt = 1; return self; } CfgArgs * cfg_args_ref(CfgArgs *self) { if (self) self->ref_cnt++; return self; } void cfg_args_unref(CfgArgs *self) { if (self && --self->ref_cnt == 0) { g_hash_table_destroy(self->args); g_free(self); } } syslog-ng-syslog-ng-4.4.0/lib/cfg-args.h000066400000000000000000000035671450431004300177760ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_ARGS_H_INCLUDED #define CFG_ARGS_H_INCLUDED 1 #include "syslog-ng.h" typedef struct _CfgArgs CfgArgs; /* argument list for a block generator */ gchar *cfg_args_format_varargs(CfgArgs *self, CfgArgs *defaults); void cfg_args_set(CfgArgs *self, const gchar *name, const gchar *value); const gchar *cfg_args_get(CfgArgs *self, const gchar *name); gboolean cfg_args_get_as_boolean(CfgArgs *self, const gchar *name); gboolean cfg_args_contains(CfgArgs *self, const gchar *name); void cfg_args_remove_normalized(CfgArgs *self, const gchar *normalized_name); void cfg_args_remove(CfgArgs *self, const gchar *name); void cfg_args_foreach(CfgArgs *self, GHFunc func, gpointer user_data); void cfg_args_accept_varargs(CfgArgs *self); gboolean cfg_args_is_accepting_varargs(CfgArgs *self); CfgArgs *cfg_args_new(void); CfgArgs *cfg_args_ref(CfgArgs *self); void cfg_args_unref(CfgArgs *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-block-generator.c000066400000000000000000000047221450431004300221050ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-block-generator.h" #include "cfg-lexer.h" const gchar * cfg_block_generator_format_name_method(CfgBlockGenerator *self, gchar *buf, gsize buf_len) { g_snprintf(buf, buf_len, "%s generator %s", cfg_lexer_lookup_context_name_by_type(self->context), self->name); return buf; } gboolean cfg_block_generator_generate(CfgBlockGenerator *self, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference) { gchar block_name[1024]; cfg_block_generator_format_name(self, block_name, sizeof(block_name)/sizeof(block_name[0])); g_string_append_printf(result, "\n#Start Block %s\n", block_name); const gboolean res = self->generate(self, cfg, args, result, reference); g_string_append_printf(result, "\n#End Block %s\n", block_name); return res; } void cfg_block_generator_init_instance(CfgBlockGenerator *self, gint context, const gchar *name) { self->ref_cnt = 1; self->context = context; self->name = g_strdup(name); self->format_name = cfg_block_generator_format_name_method; self->free_fn = cfg_block_generator_free_instance; } void cfg_block_generator_free_instance(CfgBlockGenerator *self) { g_free(self->name); } CfgBlockGenerator * cfg_block_generator_ref(CfgBlockGenerator *self) { self->ref_cnt++; return self; } void cfg_block_generator_unref(CfgBlockGenerator *self) { if (--self->ref_cnt == 0) { if (self->free_fn) self->free_fn(self); g_free(self); } } syslog-ng-syslog-ng-4.4.0/lib/cfg-block-generator.h000066400000000000000000000050221450431004300221040ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_BLOCK_GENERATOR_H_INCLUDED #define CFG_BLOCK_GENERATOR_H_INCLUDED 1 #include "syslog-ng.h" /** * CfgBlockGenerator: * * This class describes a block generator, e.g. a function callback * that returns a configuration snippet in a given context. Each * user-defined "block" results in a generator to be registered, but * theoretically this mechanism can be used to write plugins that * generate syslog-ng configuration on the fly, based on system * settings for example. **/ typedef struct _CfgBlockGenerator CfgBlockGenerator; struct _CfgBlockGenerator { gint ref_cnt; gint context; gchar *name; gboolean suppress_backticks; const gchar *(*format_name)(CfgBlockGenerator *self, gchar *buf, gsize buf_len); gboolean (*generate)(CfgBlockGenerator *self, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference); void (*free_fn)(CfgBlockGenerator *self); }; static inline const gchar * cfg_block_generator_format_name(CfgBlockGenerator *self, gchar *buf, gsize buf_len) { return self->format_name(self, buf, buf_len); } gboolean cfg_block_generator_generate(CfgBlockGenerator *self, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference); void cfg_block_generator_init_instance(CfgBlockGenerator *self, gint context, const gchar *name); void cfg_block_generator_free_instance(CfgBlockGenerator *self); CfgBlockGenerator *cfg_block_generator_ref(CfgBlockGenerator *self); void cfg_block_generator_unref(CfgBlockGenerator *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-block.c000066400000000000000000000153761450431004300201300ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-block.h" #include "cfg-lexer-subst.h" #include "cfg.h" #include "str-utils.h" /* * This class encapsulates a configuration block that the user defined * via the configuration file. It behaves like a macro, e.g. when * referenced the content of the block is expanded. * * Each block is identified by its name and the context (source, * destination, etc.) where it is meant to be used. * * A block has a set of name-value pairs to allow expansion to be * parameterized. The set of allowed NV pairs is defined at block * definition time */ typedef struct _CfgBlock CfgBlock; struct _CfgBlock { CfgBlockGenerator super; gchar *filename; gint line, column; gchar *content; CfgArgs *arg_defs; }; static const gchar * cfg_block_format_name(CfgBlockGenerator *s, gchar *buf, gsize buf_len) { CfgBlock *self = (CfgBlock *) s; g_snprintf(buf, buf_len, "block %s %s() at %s:%d", cfg_lexer_lookup_context_name_by_type(self->super.context), self->super.name, self->filename ? : "#buffer", self->line); return buf; } /* token block args */ static void _validate_args_callback(gpointer k, gpointer v, gpointer user_data) { CfgArgs *defs = ((gpointer *) user_data)[0]; const gchar *reference = ((gpointer *) user_data)[1]; gboolean *problem_found = ((gpointer *) user_data)[2]; if ((!defs || !cfg_args_contains(defs, k))) { if (cfg_args_is_accepting_varargs(defs)) { msg_verbose("Unknown argument, adding it to __VARARGS__", evt_tag_str("argument", k), evt_tag_str("value", v), evt_tag_str("reference", reference)); } else { msg_error("Unknown argument specified to block reference", evt_tag_str("argument", k), evt_tag_str("value", v), evt_tag_str("reference", reference)); *problem_found = TRUE; } } } static void _validate_mandatory_options_callback(gpointer parameter, gpointer default_value, gpointer user_data) { CfgArgs *user_args = ((gpointer *) user_data)[0]; const gchar *reference = ((gpointer *) user_data)[1]; gboolean *missing_parameter_found = ((gpointer *) user_data)[2]; const gchar *value = cfg_args_get(user_args, parameter); if (default_value == NULL && value == NULL) { *missing_parameter_found = TRUE; msg_error("Mandatory parameter not overridden", evt_tag_str("parameter", parameter), evt_tag_str("reference", reference)); } } static gboolean _validate_mandatory_options(CfgArgs *arg_defs, CfgArgs *args, const gchar *reference) { gboolean missing_parameter_found = FALSE; gpointer validate_params[] = { args, (gchar *)reference, &missing_parameter_found }; cfg_args_foreach(arg_defs, _validate_mandatory_options_callback, validate_params); if (missing_parameter_found) return FALSE; return TRUE; }; gboolean _validate_spurious_args(CfgArgs *self, CfgArgs *defs, const gchar *reference) { gboolean problem_found = FALSE; gpointer validate_params[] = { defs, (gchar *) reference, &problem_found }; cfg_args_foreach(self, _validate_args_callback, validate_params); if (problem_found) return FALSE; return TRUE; } static gboolean _validate_args(CfgArgs *self, CfgArgs *defs, const gchar *reference) { return _validate_mandatory_options(defs, self, reference) && _validate_spurious_args(self, defs, reference); } /* * cfg_block_generate: * * This is a CfgBlockGeneratorFunc, which takes a CfgBlock defined by * the user, substitutes backtick values and generates input tokens * for the lexer. */ gboolean cfg_block_generate(CfgBlockGenerator *s, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference) { CfgBlock *self = (CfgBlock *) s; gchar *value; gsize length; GError *error = NULL; gchar buf[256]; CfgArgs *cfgargs = (CfgArgs *)args; if (!_validate_args(cfgargs, self->arg_defs, reference)) return FALSE; if (cfg_args_is_accepting_varargs(self->arg_defs)) { gchar *formatted_varargs = cfg_args_format_varargs(cfgargs, self->arg_defs); cfg_args_set(cfgargs, "__VARARGS__", formatted_varargs); g_free(formatted_varargs); } value = cfg_lexer_subst_args_in_input(cfg->globals, self->arg_defs, cfgargs, self->content, -1, &length, &error); if (!value) { msg_warning("Syntax error while resolving backtick references in block", evt_tag_str("block_definition", cfg_block_generator_format_name(s, buf, sizeof(buf))), evt_tag_str("error", error->message)); g_clear_error(&error); return FALSE; } if (cfg->lexer && !cfg->lexer->ignore_pragma) g_string_append_printf(result, "@line \"%s\" %d %d\n", self->filename, self->line, self->column); g_string_append_len(result, value, length); g_free(value); return TRUE; } /* * Free a user defined block. */ void cfg_block_free_instance(CfgBlockGenerator *s) { CfgBlock *self = (CfgBlock *) s; g_free(self->filename); g_free(self->content); cfg_args_unref(self->arg_defs); cfg_block_generator_free_instance(s); } /* * Construct a user defined block. */ CfgBlockGenerator * cfg_block_new(gint context, const gchar *name, const gchar *content, CfgArgs *arg_defs, CFG_LTYPE *lloc) { CfgBlock *self = g_new0(CfgBlock, 1); cfg_block_generator_init_instance(&self->super, context, name); self->super.free_fn = cfg_block_free_instance; self->super.generate = cfg_block_generate; self->super.format_name = cfg_block_format_name; self->super.suppress_backticks = TRUE; self->content = g_strdup(content); self->filename = g_strdup(lloc->name); self->line = lloc->first_line; self->column = lloc->first_column; self->arg_defs = arg_defs; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/cfg-block.h000066400000000000000000000024631450431004300201260ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_BLOCK_H_INCLUDED #define CFG_BLOCK_H_INCLUDED 1 #include "cfg-block-generator.h" #include "cfg-lexer.h" /* user defined configuration block */ CfgBlockGenerator *cfg_block_new(gint context, const gchar *name, const gchar *content, CfgArgs *arg_defs, CFG_LTYPE *yylloc); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-grammar-internal.c000066400000000000000000000037771450431004300223000ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2020 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-grammar-internal.h" LogDriver *last_driver; LogSchedulerOptions *last_scheduler_options; LogParser *last_parser; FilterExprNode *last_filter_expr; LogSourceOptions *last_source_options; LogProtoServerOptions *last_proto_server_options; LogProtoClientOptions *last_proto_client_options; LogReaderOptions *last_reader_options; LogWriterOptions *last_writer_options; MsgFormatOptions *last_msg_format_options; FilePermOptions *last_file_perm_options; LogTemplateOptions *last_template_options; LogTemplate *last_template; CfgArgs *last_block_args; ValuePairs *last_value_pairs; ValuePairsTransformSet *last_vp_transset; LogMatcherOptions *last_matcher_options; HostResolveOptions *last_host_resolve_options; StatsOptions *last_stats_options; HealthCheckStatsOptions *last_healthcheck_options; DNSCacheOptions *last_dns_cache_options; LogRewrite *last_rewrite; CfgArgs *last_block_args; DNSCacheOptions *last_dns_cache_options; MultiLineOptions *last_multi_line_options; syslog-ng-syslog-ng-4.4.0/lib/cfg-grammar-internal.h000066400000000000000000000064111450431004300222710ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2020 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_GRAMMAR_INTERNAL_H_INCLUDED #define CFG_GRAMMAR_INTERNAL_H_INCLUDED 1 #include "syslog-ng.h" #include "driver.h" #include "logreader.h" #include "logwriter.h" #include "logmatcher.h" #include "parser/parser-expr.h" #include "filter/filter-expr.h" #include "value-pairs/value-pairs.h" #include "rewrite/rewrite-expr.h" #include "logproto/logproto.h" #include "afinter.h" #include "str-utils.h" #include "logscheduler-pipe.h" #include "filter/filter-expr-parser.h" #include "filter/filter-pipe.h" #include "parser/parser-expr-parser.h" #include "rewrite/rewrite-expr-parser.h" #include "block-ref-parser.h" #include "template/user-function.h" #include "cfg-block.h" #include "cfg-path.h" #include "multi-line/multi-line-factory.h" #include "logthrsource/logthrfetcherdrv.h" #include "logthrdest/logthrdestdrv.h" #include "stats/stats.h" #include "healthcheck/healthcheck-stats.h" #include #include #include /* uses struct declarations instead of the typedefs to avoid having to * include logreader/logwriter/driver.h, which defines the typedefs. This * is to avoid including unnecessary dependencies into grammars that are not * themselves reader/writer based */ extern LogSourceOptions *last_source_options; extern LogReaderOptions *last_reader_options; extern LogProtoServerOptions *last_proto_server_options; extern LogProtoClientOptions *last_proto_client_options; extern LogWriterOptions *last_writer_options; extern FilePermOptions *last_file_perm_options; extern MsgFormatOptions *last_msg_format_options; extern LogDriver *last_driver; extern LogSchedulerOptions *last_scheduler_options; extern LogParser *last_parser; extern FilterExprNode *last_filter_expr; extern LogTemplateOptions *last_template_options; extern LogTemplate *last_template; extern ValuePairs *last_value_pairs; extern ValuePairsTransformSet *last_vp_transset; extern LogMatcherOptions *last_matcher_options; extern HostResolveOptions *last_host_resolve_options; extern StatsOptions *last_stats_options; extern HealthCheckStatsOptions *last_healthcheck_options; extern LogRewrite *last_rewrite; extern CfgArgs *last_block_args; extern DNSCacheOptions *last_dns_cache_options; extern MultiLineOptions *last_multi_line_options; #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-grammar.y000066400000000000000000001663531450431004300205140ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { /* this block is inserted into cfg-grammar.h, so it is included practically all of the syslog-ng code. Please add headers here with care. If you need additional headers, please look for a massive list of includes further below. */ #pragma GCC diagnostic ignored "-Wswitch-default" #if (defined(__GNUC__) && __GNUC__ >= 6) || (defined(__clang__) && __clang_major__ >= 10) # pragma GCC diagnostic ignored "-Wmisleading-indentation" #endif /* YYSTYPE and YYLTYPE is defined by the lexer */ #include "cfg-lexer.h" #include "cfg-grammar-internal.h" #include "syslog-names.h" /* uses struct declarations instead of the typedefs to avoid having to * include logreader/logwriter/driver.h, which defines the typedefs. This * is to avoid including unnecessary dependencies into grammars that are not * themselves reader/writer based */ } %define api.prefix {main_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {gpointer *dummy} %parse-param {gpointer arg} /* START_DECLS */ %require "3.7.6" %locations %define api.pure %define api.value.type {CFG_STYPE} %define api.location.type {CFG_LTYPE} %define parse.error verbose %code { # define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) \ { \ (Current).name = YYRHSLOC(Rhs, 1).name; \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).name = YYRHSLOC(Rhs, 0).name; \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ } while (0) #define CHECK_ERROR_WITHOUT_MESSAGE(val, token) do { \ if (!(val)) \ { \ YYERROR; \ } \ } while (0) #define CHECK_ERROR(val, token, errorfmt, ...) do { \ if (!(val)) \ { \ if (errorfmt) \ { \ gchar __buf[256]; \ g_snprintf(__buf, sizeof(__buf), errorfmt, ## __VA_ARGS__); \ yyerror(& (token), lexer, NULL, NULL, __buf); \ } \ YYERROR; \ } \ } while (0) #define CHECK_ERROR_GERROR(val, token, error, errorfmt, ...) do { \ if (!(val)) \ { \ if (errorfmt) \ { \ gchar __buf[256]; \ g_snprintf(__buf, sizeof(__buf), errorfmt ", error=%s", ## __VA_ARGS__, error->message); \ yyerror(& (token), lexer, NULL, NULL, __buf); \ } \ g_clear_error(&error); \ YYERROR; \ } \ } while (0) #define YYMAXDEPTH 20000 } /* plugin types, must be equal to the numerical values of the plugin type in plugin.h */ %token LL_CONTEXT_ROOT 1 %token LL_CONTEXT_DESTINATION 2 %token LL_CONTEXT_SOURCE 3 %token LL_CONTEXT_PARSER 4 %token LL_CONTEXT_REWRITE 5 %token LL_CONTEXT_FILTER 6 %token LL_CONTEXT_LOG 7 %token LL_CONTEXT_BLOCK_DEF 8 %token LL_CONTEXT_BLOCK_REF 9 %token LL_CONTEXT_BLOCK_CONTENT 10 %token LL_CONTEXT_BLOCK_ARG 11 %token LL_CONTEXT_PRAGMA 12 %token LL_CONTEXT_FORMAT 13 %token LL_CONTEXT_TEMPLATE_FUNC 14 %token LL_CONTEXT_INNER_DEST 15 %token LL_CONTEXT_INNER_SRC 16 %token LL_CONTEXT_CLIENT_PROTO 17 %token LL_CONTEXT_SERVER_PROTO 18 %token LL_CONTEXT_OPTIONS 19 %token LL_CONTEXT_CONFIG 20 /* this is a placeholder for unit tests, must be the latest & largest */ %token LL_CONTEXT_MAX 21 /* statements */ %token KW_SOURCE 10000 %token KW_FILTER 10001 %token KW_PARSER 10002 %token KW_DESTINATION 10003 %token KW_LOG 10004 %token KW_OPTIONS 10005 %token KW_INCLUDE 10006 %token KW_BLOCK 10007 %token KW_JUNCTION 10008 %token KW_CHANNEL 10009 %token KW_IF 10010 %token KW_ELSE 10011 %token KW_ELIF 10012 /* source & destination items */ %token KW_INTERNAL 10020 %token KW_SYSLOG 10060 /* option items */ %token KW_MARK_FREQ 10071 %token KW_STATS_FREQ 10072 %token KW_STATS_LEVEL 10073 %token KW_STATS_LIFETIME 10074 %token KW_FLUSH_LINES 10075 %token KW_SUPPRESS 10076 %token KW_FLUSH_TIMEOUT 10077 %token KW_LOG_MSG_SIZE 10078 %token KW_FILE_TEMPLATE 10079 %token KW_PROTO_TEMPLATE 10080 %token KW_MARK_MODE 10081 %token KW_ENCODING 10082 %token KW_TYPE 10083 %token KW_STATS_MAX_DYNAMIC 10084 %token KW_MIN_IW_SIZE_PER_READER 10085 %token KW_WORKERS 10086 %token KW_BATCH_LINES 10087 %token KW_BATCH_TIMEOUT 10088 %token KW_TRIM_LARGE_MESSAGES 10089 %token KW_STATS 10400 %token KW_FREQ 10401 %token KW_LEVEL 10402 %token KW_LIFETIME 10403 %token KW_MAX_DYNAMIC 10404 %token KW_SYSLOG_STATS 10405 %token KW_HEALTHCHECK_FREQ 10406 %token KW_WORKER_PARTITION_KEY 10407 %token KW_CHAIN_HOSTNAMES 10090 %token KW_NORMALIZE_HOSTNAMES 10091 %token KW_KEEP_HOSTNAME 10092 %token KW_CHECK_HOSTNAME 10093 %token KW_BAD_HOSTNAME 10094 %token KW_LOG_LEVEL 10095 %token KW_KEEP_TIMESTAMP 10100 %token KW_USE_DNS 10110 %token KW_USE_FQDN 10111 %token KW_CUSTOM_DOMAIN 10112 %token KW_DNS_CACHE 10120 %token KW_DNS_CACHE_SIZE 10121 %token KW_DNS_CACHE_EXPIRE 10130 %token KW_DNS_CACHE_EXPIRE_FAILED 10131 %token KW_DNS_CACHE_HOSTS 10132 %token KW_PERSIST_ONLY 10140 %token KW_USE_RCPTID 10141 %token KW_USE_UNIQID 10142 %token KW_TZ_CONVERT 10150 %token KW_TS_FORMAT 10151 %token KW_FRAC_DIGITS 10152 %token KW_LOG_FIFO_SIZE 10160 %token KW_LOG_FETCH_LIMIT 10162 %token KW_LOG_IW_SIZE 10163 %token KW_LOG_PREFIX 10164 %token KW_PROGRAM_OVERRIDE 10165 %token KW_HOST_OVERRIDE 10166 %token KW_THROTTLE 10170 %token KW_THREADED 10171 %token KW_PASS_UNIX_CREDENTIALS 10180 %token KW_PERSIST_NAME 10181 %token KW_READ_OLD_RECORDS 10182 %token KW_USE_SYSLOGNG_PID 10183 /* log statement options */ %token KW_FLAGS 10190 /* reader options */ %token KW_PAD_SIZE 10200 %token KW_TIME_ZONE 10201 %token KW_RECV_TIME_ZONE 10202 %token KW_SEND_TIME_ZONE 10203 %token KW_LOCAL_TIME_ZONE 10204 %token KW_FORMAT 10205 /* multi-line options */ %token KW_MULTI_LINE_MODE 10206 %token KW_MULTI_LINE_PREFIX 10207 %token KW_MULTI_LINE_GARBAGE 10208 /* destination writer options */ %token KW_TRUNCATE_SIZE 10209 /* timers */ %token KW_TIME_REOPEN 10210 %token KW_TIME_REAP 10211 %token KW_TIME_SLEEP 10212 %token KW_PARTITIONS 10213 %token KW_PARTITION_KEY 10214 %token KW_PARALLELIZE 10215 /* destination options */ %token KW_TMPL_ESCAPE 10220 /* driver specific options */ %token KW_OPTIONAL 10230 /* file related options */ %token KW_CREATE_DIRS 10240 %token KW_OWNER 10250 %token KW_GROUP 10251 %token KW_PERM 10252 %token KW_DIR_OWNER 10260 %token KW_DIR_GROUP 10261 %token KW_DIR_PERM 10262 %token KW_TEMPLATE 10270 %token KW_TEMPLATE_ESCAPE 10271 %token KW_TEMPLATE_FUNCTION 10272 %token KW_DEFAULT_FACILITY 10300 %token KW_DEFAULT_SEVERITY 10301 %token KW_SDATA_PREFIX 10302 %token KW_PORT 10323 /* misc options */ %token KW_USE_TIME_RECVD 10340 /* filter items*/ %token KW_FACILITY 10350 %token KW_SEVERITY 10351 %token KW_HOST 10352 %token KW_MATCH 10353 %token KW_MESSAGE 10354 %token KW_NETMASK 10355 %token KW_TAGS 10356 %token KW_NETMASK6 10357 /* parser items */ /* rewrite items */ %token KW_REWRITE 10370 %token KW_CONDITION 10371 %token KW_VALUE 10372 /* yes/no switches */ %token KW_YES 10380 %token KW_NO 10381 %token KW_AUTO 10382 %token KW_IFDEF 10410 %token KW_ENDIF 10411 %token LL_DOTDOT 10420 %token LL_DOTDOTDOT 10421 %token LL_PRAGMA 10422 %token LL_EOL 10423 %token LL_ERROR 10424 %token LL_ARROW 10425 %token LL_IDENTIFIER 10430 %token LL_NUMBER 10431 %token LL_FLOAT 10432 %token LL_STRING 10433 %token LL_TOKEN 10434 %token LL_BLOCK 10435 %token LL_PLUGIN 10436 %destructor { free($$); } /* value pairs */ %token KW_VALUE_PAIRS 10500 %token KW_EXCLUDE 10502 %token KW_PAIR 10503 %token KW_KEY 10504 %token KW_SCOPE 10505 %token KW_SHIFT 10506 %token KW_SHIFT_LEVELS 10507 %token KW_REKEY 10508 %token KW_ADD_PREFIX 10509 %token KW_REPLACE_PREFIX 10510 %token KW_CAST 10511 %token KW_UPPER 10512 %token KW_LOWER 10513 %token KW_INCLUDE_BYTES 10514 %token KW_ON_ERROR 10520 %token KW_RETRIES 10521 %token KW_FETCH_NO_DATA_DELAY 10522 /* END_DECLS */ %type expr_stmt %type source_stmt %type dest_stmt %type filter_stmt %type parser_stmt %type rewrite_stmt %type log_stmt %type plugin_stmt /* START_DECLS */ %type source_content %type source_items %type source_item %type source_afinter %type source_plugin %type source_afinter_params %type dest_content %type dest_items %type dest_item %type dest_plugin %type template_content %type template_content_list %type filter_content %type parser_content %type rewrite_content %type log_items %type log_item %type log_last_junction %type log_scheduler %type log_junction %type log_content %type log_conditional %type log_if %type log_forks %type log_fork %type log_flags %type log_flags_items %type value_pair_option %type yesno_strict %type yesno %type yesnoauto %type dnsmode %type dest_writer_options_flags %type string %type string_or_number %type optional_string %type normalized_flag %type string_list %type string_list_build %type facility_string %type severity_string %type positive_integer %type positive_integer64 %type nonnegative_integer %type nonnegative_integer64 %type positive_float %type nonnegative_float %type path_no_check %type path_secret %type path_check %type path /* END_DECLS */ %type template_def %type template_block %type template_simple %type template_fn %% start : stmts ; stmts : stmt semicolons stmts | ; stmt : expr_stmt { CHECK_ERROR(cfg_tree_add_object(&configuration->tree, $1) || cfg_allow_config_dups(configuration), @1, "duplicate %s definition", log_expr_node_get_content_name(((LogExprNode *) $1)->content)); } | template_stmt | options_stmt | block_stmt | plugin_stmt ; expr_stmt : source_stmt | dest_stmt | filter_stmt | parser_stmt | rewrite_stmt | log_stmt ; source_stmt : KW_SOURCE string '{' source_content '}' { $$ = log_expr_node_new_source($2, $4, &@1); free($2); } ; dest_stmt : KW_DESTINATION string '{' dest_content '}' { $$ = log_expr_node_new_destination($2, $4, &@1); free($2); } ; filter_stmt : KW_FILTER string '{' filter_content '}' { /* NOTE: the filter() subexpression (e.g. the one that invokes * one filter expression from another) depends on the layout * parsed into the cfg-tree when looking up the referenced * filter expression. So when changing how a filter statement * is transformed into the cfg-tree, make sure you check * filter-call.c, especially filter_call_init() function as * well. */ $$ = log_expr_node_new_filter($2, $4, &@1); free($2); } ; parser_stmt : KW_PARSER string '{' parser_content '}' { $$ = log_expr_node_new_parser($2, $4, &@1); free($2); } ; rewrite_stmt : KW_REWRITE string '{' rewrite_content '}' { $$ = log_expr_node_new_rewrite($2, $4, &@1); free($2); } log_stmt : KW_LOG optional_string _log_context_push '{' log_content '}' _log_context_pop { if ($2) { log_expr_node_set_name($5, $2); free($2); } $$ = $5; } ; plugin_stmt : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_ROOT; gpointer result; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); result = cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!result) YYERROR; $$ = NULL; } /* START_RULES */ source_content : _source_context_push source_items _source_context_pop { $$ = log_expr_node_new_source_junction($2, &@$); } ; source_items : source_item semicolons source_items { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_fork semicolons source_items { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; source_item : source_afinter { $$ = $1; } | source_plugin { $$ = $1; } ; source_plugin : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_SOURCE; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_driver) { YYERROR; } $$ = last_driver; } ; source_afinter : KW_INTERNAL '(' source_afinter_params ')' { $$ = $3; } ; source_afinter_params : { last_driver = afinter_sd_new(configuration); last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super; } source_afinter_options { $$ = last_driver; } ; source_afinter_options : source_afinter_option source_afinter_options | ; source_afinter_option : KW_LOG_FIFO_SIZE '(' positive_integer ')' { ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; } | source_option ; filter_content : { FilterExprNode *filter_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @$); $$ = log_expr_node_new_pipe(log_filter_pipe_new(filter_expr, configuration), &@$); } ; parser_content : { LogExprNode *last_parser_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$); $$ = last_parser_expr; } ; rewrite_content : { LogExprNode *last_rewrite_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$); $$ = last_rewrite_expr; } ; dest_content : _destination_context_push dest_items _destination_context_pop { $$ = log_expr_node_new_destination_junction($2, &@$); } ; dest_items /* all destination drivers are added as an independent branch in a junction*/ : dest_item semicolons dest_items { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_fork semicolons dest_items { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; dest_item : dest_plugin { $$ = $1; } ; dest_plugin : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_DESTINATION; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_driver) { YYERROR; } $$ = last_driver; } ; log_items : log_item semicolons log_items { log_expr_node_append_tail($1, $3); $$ = $1; } | { $$ = NULL; } ; log_item : KW_SOURCE '(' string ')' { $$ = log_expr_node_new_source_reference($3, &@$); free($3); } | KW_SOURCE '{' source_content '}' { $$ = log_expr_node_new_source(NULL, $3, &@$); } | KW_FILTER '(' string ')' { $$ = log_expr_node_new_filter_reference($3, &@$); free($3); } | KW_FILTER '{' filter_content '}' { $$ = log_expr_node_new_filter(NULL, $3, &@$); } | KW_PARSER '(' string ')' { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); } | KW_PARSER '{' parser_content '}' { $$ = log_expr_node_new_parser(NULL, $3, &@$); } | KW_REWRITE '(' string ')' { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); } | KW_REWRITE '{' rewrite_content '}' { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); } | KW_DESTINATION '(' string ')' { $$ = log_expr_node_new_destination_reference($3, &@$); free($3); } | KW_DESTINATION '{' dest_content '}' { $$ = log_expr_node_new_destination(NULL, $3, &@$); } | log_scheduler { $$ = $1; } | log_conditional { $$ = $1; } | log_junction { $$ = $1; } ; log_scheduler : KW_PARALLELIZE '(' { LogPipe *scheduler_pipe = log_scheduler_pipe_new(configuration); last_scheduler_options = log_scheduler_pipe_get_scheduler_options(scheduler_pipe); $$ = scheduler_pipe; } log_scheduler_options ')' { $$ = log_expr_node_new_pipe($3, &@$); } ; log_scheduler_options : log_scheduler_option log_scheduler_options | ; log_scheduler_option : KW_PARTITIONS '(' nonnegative_integer ')' { last_scheduler_options->num_partitions = $3; } | KW_PARTITION_KEY '(' template_content ')' { log_scheduler_options_set_partition_key_ref(last_scheduler_options, $3); } ; log_junction : KW_JUNCTION '{' log_forks '}' { $$ = log_expr_node_new_junction($3, &@$); } ; log_last_junction /* this rule matches the last set of embedded log {} * statements at the end of the log {} block. * It is the final junction and was the only form of creating * a processing tree before syslog-ng 3.4. * * We emulate if the user was writing junction {} explicitly. */ : log_forks { $$ = $1 ? log_expr_node_new_junction($1, &@1) : NULL; } ; log_forks : log_fork semicolons log_forks { log_expr_node_append_tail($1, $3); $$ = $1; } | { $$ = NULL; } ; log_fork : KW_LOG optional_string '{' log_content '}' { if ($2) { log_expr_node_set_name($4, $2); free($2); } $$ = $4; } | KW_CHANNEL optional_string '{' log_content '}' { if ($2) { log_expr_node_set_name($4, $2); free($2); } $$ = $4; } ; log_conditional : log_if { $$ = $1; } | log_if KW_ELSE '{' log_content '}' { log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4); $$ = $1; } ; log_if : KW_IF '(' filter_content ')' '{' log_content '}' { $$ = log_expr_node_new_simple_conditional($3, $6, &@$); } | KW_IF '{' log_content '}' { $$ = log_expr_node_new_compound_conditional($3, &@$); } | log_if KW_ELIF '(' filter_content ')' '{' log_content '}' { LogExprNode *false_branch; false_branch = log_expr_node_new_simple_conditional($4, $7, &@$); log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch); $$ = $1; } | log_if KW_ELIF '{' log_content '}' { LogExprNode *false_branch; false_branch = log_expr_node_new_compound_conditional($4, &@$); log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch); $$ = $1; } ; log_content : log_items log_last_junction log_flags { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); } ; log_flags : KW_FLAGS '(' log_flags_items ')' semicolons { $$ = $3; } | { $$ = 0; } ; log_flags_items : normalized_flag log_flags_items { $$ = log_expr_node_lookup_flag($1) | $2; free($1); } | { $$ = 0; } ; /* END_RULES */ options_stmt : KW_OPTIONS _options_context_push '{' options_items '}' _options_context_pop ; template_stmt : template_def { CHECK_ERROR(cfg_tree_add_template(&configuration->tree, $1) || cfg_allow_config_dups(configuration), @1, "duplicate template"); } | template_fn { user_template_function_register(configuration, last_template->name, last_template); log_template_unref(last_template); last_template = NULL; } ; template_def : template_block | template_simple ; template_block : KW_TEMPLATE string { $$ = last_template = log_template_new(configuration, $2); } '{' template_items '}' { $$ = $3; free($2); } ; template_simple : KW_TEMPLATE string { $$ = last_template = log_template_new(configuration, $2); } template_content_inner { $$ = $3; free($2); } ; template_fn : KW_TEMPLATE_FUNCTION string { $$ = last_template = log_template_new(configuration, $2); } template_content_inner { $$ = $3; free($2); } ; template_items : template_item semicolons template_items | ; /* START_RULES */ template_content_inner : string { GError *error = NULL; CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template"); free($1); } | LL_IDENTIFIER '(' string_or_number ')' { GError *error = NULL; CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template"); free($3); CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1); free($1); } | LL_NUMBER { gchar decimal[32]; g_snprintf(decimal, sizeof(decimal), "%" G_GINT64_FORMAT, $1); log_template_compile_literal_string(last_template, decimal); log_template_set_type_hint(last_template, "int64", NULL); } | LL_FLOAT { log_template_compile_literal_string(last_template, lexer->token_text->str); log_template_set_type_hint(last_template, "float", NULL); } ; template_content : { $$ = last_template = log_template_new(configuration, NULL); } template_content_inner { $$ = $1; } ; template_content_list : template_content template_content_list { $$ = g_list_prepend($2, $1); } | { $$ = NULL; } ; /* END_RULES */ template_item : KW_TEMPLATE '(' template_content_inner ')' | KW_TEMPLATE_ESCAPE '(' yesno ')' { log_template_set_escape(last_template, $3); } ; block_stmt : KW_BLOCK _block_def_context_push LL_IDENTIFIER LL_IDENTIFIER '(' { last_block_args = cfg_args_new(); } block_definition ')' _block_content_context_push LL_BLOCK _block_content_context_pop _block_def_context_pop { CfgBlockGenerator *block; gint context_type = cfg_lexer_lookup_context_type_by_name($3); CHECK_ERROR(context_type, @3, "unknown context \"%s\"", $3); block = cfg_block_new(context_type, $4, $10, last_block_args, &@1); cfg_lexer_register_generator_plugin(&configuration->plugin_context, block); free($3); free($4); free($10); last_block_args = NULL; } ; block_definition : block_args | block_args LL_DOTDOTDOT { cfg_args_accept_varargs(last_block_args); } ; block_args : block_arg block_args | ; block_arg : LL_IDENTIFIER _block_arg_context_push LL_BLOCK _block_arg_context_pop { cfg_args_set(last_block_args, $1, $3); free($1); free($3); } ; options_items : options_item semicolons options_items | ; options_item : KW_MARK_FREQ '(' nonnegative_integer ')' { configuration->mark_freq = $3; } | KW_FLUSH_LINES '(' nonnegative_integer ')' { configuration->flush_lines = $3; } | KW_MARK_MODE '(' KW_INTERNAL ')' { cfg_set_mark_mode(configuration, "internal"); } | KW_MARK_MODE '(' string ')' { CHECK_ERROR(cfg_lookup_mark_mode($3) > 0 && cfg_lookup_mark_mode($3) != MM_GLOBAL, @3, "illegal global mark-mode \"%s\"", $3); cfg_set_mark_mode(configuration, $3); free($3); } | KW_FLUSH_TIMEOUT '(' positive_integer ')' { } | KW_CHAIN_HOSTNAMES '(' yesno ')' { configuration->chain_hostnames = $3; } | KW_KEEP_HOSTNAME '(' yesno ')' { configuration->keep_hostname = $3; } | KW_CHECK_HOSTNAME '(' yesno ')' { configuration->check_hostname = $3; } | KW_BAD_HOSTNAME '(' string ')' { cfg_bad_hostname_set(configuration, $3); free($3); } | KW_TIME_REOPEN '(' positive_integer ')' { configuration->time_reopen = $3; } | KW_TIME_REAP '(' nonnegative_integer ')' { configuration->time_reap = $3; } | KW_TIME_SLEEP '(' nonnegative_integer ')' {} | KW_SUPPRESS '(' nonnegative_integer ')' { configuration->suppress = $3; } | KW_THREADED '(' yesno ')' { configuration->threaded = $3; } | KW_PASS_UNIX_CREDENTIALS '(' yesno ')' { configuration->pass_unix_credentials = $3; } | KW_USE_RCPTID '(' yesno ')' { cfg_set_use_uniqid($3); } | KW_USE_UNIQID '(' yesno ')' { cfg_set_use_uniqid($3); } | KW_LOG_FIFO_SIZE '(' positive_integer ')' { configuration->log_fifo_size = $3; } | KW_LOG_IW_SIZE '(' positive_integer ')' { msg_warning("WARNING: Support for the global log-iw-size() option was removed, please use a per-source log-iw-size()", cfg_lexer_format_location_tag(lexer, &@1)); } | KW_LOG_FETCH_LIMIT '(' positive_integer ')' { msg_warning("WARNING: Support for the global log-fetch-limit() option was removed, please use a per-source log-fetch-limit()", cfg_lexer_format_location_tag(lexer, &@1)); } | KW_LOG_MSG_SIZE '(' positive_integer ')' { configuration->log_msg_size = $3; } | KW_TRIM_LARGE_MESSAGES '(' yesno ')' { configuration->trim_large_messages = $3; } | KW_KEEP_TIMESTAMP '(' yesno ')' { configuration->keep_timestamp = $3; } | KW_CREATE_DIRS '(' yesno ')' { configuration->create_dirs = $3; } | KW_CUSTOM_DOMAIN '(' string ')' { configuration->custom_domain = g_strdup($3); free($3); } | KW_FILE_TEMPLATE '(' string ')' { configuration->file_template_name = g_strdup($3); free($3); } | KW_PROTO_TEMPLATE '(' string ')' { configuration->proto_template_name = g_strdup($3); free($3); } | KW_RECV_TIME_ZONE '(' string ')' { configuration->recv_time_zone = g_strdup($3); free($3); } | KW_MIN_IW_SIZE_PER_READER '(' positive_integer ')' { configuration->min_iw_size_per_reader = $3; } | KW_LOG_LEVEL '(' string ')' { CHECK_ERROR(cfg_set_log_level(configuration, $3), @3, "Unknown log-level() option"); free($3); } | { last_template_options = &configuration->template_options; } template_option | { last_host_resolve_options = &configuration->host_resolve_options; } host_resolve_option | { last_stats_options = &configuration->stats_options; last_healthcheck_options = &configuration->healthcheck_options; } stat_option | { last_dns_cache_options = &configuration->dns_cache_options; } dns_cache_option | { last_file_perm_options = &configuration->file_perm_options; } file_perm_option | LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_OPTIONS; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); cfg_parse_plugin(configuration, p, &@1, NULL); free($1); } ; stat_option : KW_STATS_FREQ '(' nonnegative_integer ')' { last_stats_options->log_freq = $3; } | KW_STATS_LEVEL '(' nonnegative_integer ')' { last_stats_options->level = $3; } | KW_STATS_LIFETIME '(' positive_integer ')' { last_stats_options->lifetime = $3; } | KW_STATS_MAX_DYNAMIC '(' nonnegative_integer ')' { last_stats_options->max_dynamic = $3; } | KW_STATS '(' stats_group_options ')' ; stats_group_options : stats_group_option stats_group_options | ; stats_group_option : KW_FREQ '(' nonnegative_integer ')' { last_stats_options->log_freq = $3; } | KW_LEVEL '(' nonnegative_integer ')' { last_stats_options->level = $3; } | KW_LIFETIME '(' positive_integer ')' { last_stats_options->lifetime = $3; } | KW_MAX_DYNAMIC '(' nonnegative_integer ')' { last_stats_options->max_dynamic = $3; } | KW_SYSLOG_STATS '(' yesnoauto ')' { last_stats_options->syslog_stats = $3; } | KW_HEALTHCHECK_FREQ '(' nonnegative_integer ')' { last_healthcheck_options->freq = $3; } ; dns_cache_option : KW_DNS_CACHE_SIZE '(' positive_integer ')' { last_dns_cache_options->cache_size = $3; } | KW_DNS_CACHE_EXPIRE '(' positive_integer ')' { last_dns_cache_options->expire = $3; } | KW_DNS_CACHE_EXPIRE_FAILED '(' positive_integer ')' { last_dns_cache_options->expire_failed = $3; } | KW_DNS_CACHE_HOSTS '(' string ')' { last_dns_cache_options->hosts = g_strdup($3); free($3); } ; /* START_RULES */ string : LL_IDENTIFIER | LL_STRING ; yesno_strict : KW_YES { $$ = 1; } | KW_NO { $$ = 0; } ; yesno : yesno_strict | LL_NUMBER { $$ = $1; } ; yesnoauto : KW_YES { $$ = CYNA_YES; } | KW_NO { $$ = CYNA_NO; } | KW_AUTO { $$ = CYNA_AUTO; } ; dnsmode : yesno { $$ = $1; } | KW_PERSIST_ONLY { $$ = 2; } ; nonnegative_integer64 : LL_NUMBER { CHECK_ERROR(($1 >= 0), @1, "It cannot be negative"); } ; nonnegative_integer : nonnegative_integer64 { CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31"); } ; positive_integer64 : LL_NUMBER { CHECK_ERROR(($1 > 0), @1, "Must be positive"); } ; positive_integer : positive_integer64 { CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31"); } ; nonnegative_float : LL_FLOAT { CHECK_ERROR(($1 >= 0), @1, "It cannot be negative"); } | nonnegative_integer { $$ = (double) $1; } ; positive_float : LL_FLOAT { CHECK_ERROR(($1 > 0), @1, "Must be positive"); } | positive_integer { $$ = (double) $1; } ; string_or_number : string { $$ = $1; } | LL_NUMBER { $$ = strdup(lexer->token_text->str); } | LL_FLOAT { $$ = strdup(lexer->token_text->str); } ; optional_string : string { $$ = $1; } | { $$ = NULL; } ; path : string { struct stat buffer; int ret = stat($1, &buffer); CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno)); $$ = $1; } ; path_check : path { cfg_path_track_file(configuration, $1, "path_check"); } ; path_secret : path { cfg_path_track_file(configuration, $1, "path_secret"); } ; path_no_check : string { cfg_path_track_file(configuration, $1, "path_no_check"); } ; normalized_flag : string { $$ = normalize_flag($1); free($1); } ; string_list : string_list_build { $$ = $1; } ; string_list_build : string string_list_build { $$ = g_list_prepend($2, g_strdup($1)); free($1); } | { $$ = NULL; } ; semicolons : ';' | ';' semicolons ; severity_string : string { /* return the numeric value of the "level" */ int n = syslog_name_lookup_severity_by_name($1); CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1); free($1); $$ = n; } ; facility_string : string { /* return the numeric value of facility */ int n = syslog_name_lookup_facility_by_name($1); CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1); free($1); $$ = n; } | KW_SYSLOG { $$ = LOG_SYSLOG; } ; parser_opt : KW_TEMPLATE '(' string ')' { LogTemplate *template; GError *error = NULL; template = cfg_tree_check_inline_template(&configuration->tree, $3, &error); CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template"); log_parser_set_template(last_parser, template); free($3); } | KW_INTERNAL '(' yesno ')' { log_pipe_set_internal(&last_parser->super, $3); } ; driver_option : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); } | KW_INTERNAL '(' yesno ')' { log_pipe_set_internal(&last_driver->super, $3); } ; inner_source : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_INNER_SRC; gpointer value; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); value = cfg_parse_plugin(configuration, p, &@1, last_driver); free($1); if (!value) { YYERROR; } if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value)) { log_driver_plugin_free(value); CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1); } } ; /* All source drivers should incorporate this rule, implies driver_option */ source_driver_option : inner_source | driver_option ; inner_dest : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_INNER_DEST; gpointer value; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); value = cfg_parse_plugin(configuration, p, &@1, last_driver); free($1); if (!value) { YYERROR; } if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value)) { log_driver_plugin_free(value); CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1); } } ; /* implies driver_option */ dest_driver_option /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */ : KW_LOG_FIFO_SIZE '(' positive_integer ')' { ((LogDestDriver *) last_driver)->log_fifo_size = $3; } | KW_THROTTLE '(' nonnegative_integer ')' { ((LogDestDriver *) last_driver)->throttle = $3; } | inner_dest | driver_option ; threaded_dest_driver_batch_option : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); } | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); } ; threaded_dest_driver_workers_option : KW_WORKERS '(' positive_integer ')' { log_threaded_dest_driver_set_num_workers(last_driver, $3); } | KW_WORKER_PARTITION_KEY '(' template_content ')' { log_threaded_dest_driver_set_worker_partition_key_ref(last_driver, $3); } ; /* implies dest_driver_option */ threaded_dest_driver_general_option : KW_RETRIES '(' positive_integer ')' { log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3); } | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); } | dest_driver_option ; /* implies source_driver_option and source_option */ threaded_source_driver_option : KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); } | KW_FLAGS '(' threaded_source_driver_option_flags ')' | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option | source_driver_option ; threaded_fetcher_driver_option : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); } | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); } ; threaded_source_driver_option_flags : string threaded_source_driver_option_flags { CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1); free($1); } | ; /* LogSource related options */ source_option /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */ : KW_LOG_IW_SIZE '(' positive_integer ')' { last_source_options->init_window_size = $3; } | KW_CHAIN_HOSTNAMES '(' yesno ')' { last_source_options->chain_hostnames = $3; } | KW_KEEP_HOSTNAME '(' yesno ')' { last_source_options->keep_hostname = $3; } | KW_PROGRAM_OVERRIDE '(' string ')' { last_source_options->program_override = g_strdup($3); free($3); } | KW_HOST_OVERRIDE '(' string ')' { last_source_options->host_override = g_strdup($3); free($3); } | KW_LOG_PREFIX '(' string ')' { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); } | KW_KEEP_TIMESTAMP '(' yesno ')' { last_source_options->keep_timestamp = $3; } | KW_READ_OLD_RECORDS '(' yesno ')' { last_source_options->read_old_records = $3; } | KW_USE_SYSLOGNG_PID '(' yesno ')' { last_source_options->use_syslogng_pid = $3; } | KW_TAGS '(' string_list ')' { log_source_options_set_tags(last_source_options, $3); } | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option ; /* LogReader related options, implies source_option */ source_reader_option /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */ : KW_CHECK_HOSTNAME '(' yesno ')' { last_reader_options->check_hostname = $3; } | KW_FLAGS '(' source_reader_option_flags ')' | KW_LOG_FETCH_LIMIT '(' positive_integer ')' { last_reader_options->fetch_limit = $3; } | KW_FORMAT '(' string ')' { last_reader_options->parse_options.format = g_strdup($3); free($3); } | { last_source_options = &last_reader_options->super; } source_option | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option ; source_reader_option_flags : string source_reader_option_flags { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); } | KW_CHECK_HOSTNAME source_reader_option_flags { log_reader_options_process_flag(last_reader_options, "check-hostname"); } | ; /* LogProtoSource related options */ source_proto_option : KW_ENCODING '(' string ')' { CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3), @3, "unknown encoding \"%s\"", $3); free($3); } | KW_LOG_MSG_SIZE '(' positive_integer ')' { last_proto_server_options->max_msg_size = $3; } | KW_TRIM_LARGE_MESSAGES '(' yesno ')' { last_proto_server_options->trim_large_messages = $3; } ; host_resolve_option : KW_USE_FQDN '(' yesno ')' { last_host_resolve_options->use_fqdn = $3; } | KW_USE_DNS '(' dnsmode ')' { last_host_resolve_options->use_dns = $3; } | KW_DNS_CACHE '(' yesno ')' { last_host_resolve_options->use_dns_cache = $3; } | KW_NORMALIZE_HOSTNAMES '(' yesno ')' { last_host_resolve_options->normalize_hostnames = $3; } ; msg_format_option : KW_TIME_ZONE '(' string ')' { last_msg_format_options->recv_time_zone = g_strdup($3); free($3); } | KW_DEFAULT_SEVERITY '(' severity_string ')' { if (last_msg_format_options->default_pri == 0xFFFF) last_msg_format_options->default_pri = LOG_USER; last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~SYSLOG_PRIMASK) | $3; } | KW_DEFAULT_FACILITY '(' facility_string ')' { if (last_msg_format_options->default_pri == 0xFFFF) last_msg_format_options->default_pri = LOG_NOTICE; last_msg_format_options->default_pri = (last_msg_format_options->default_pri & SYSLOG_PRIMASK) | $3; } | KW_SDATA_PREFIX '(' string ')' { CHECK_ERROR(msg_format_options_set_sdata_prefix(last_msg_format_options, $3), @3, "Prefix is too long \"%s\"", $3); free($3); } ; dest_writer_options : dest_writer_option dest_writer_options | ; dest_writer_option /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */ : KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; } | KW_FLUSH_LINES '(' nonnegative_integer ')' { last_writer_options->flush_lines = $3; } | KW_FLUSH_TIMEOUT '(' positive_integer ')' { } | KW_SUPPRESS '(' nonnegative_integer ')' { last_writer_options->suppress = $3; } | KW_TEMPLATE '(' string ')' { GError *error = NULL; last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error); CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template"); free($3); } | KW_TEMPLATE_ESCAPE '(' yesno ')' { log_writer_options_set_template_escape(last_writer_options, $3); } | KW_PAD_SIZE '(' nonnegative_integer ')' { last_writer_options->padding = $3; } | KW_TRUNCATE_SIZE '(' nonnegative_integer ')' { last_writer_options->truncate_size = $3; } | KW_MARK_FREQ '(' nonnegative_integer ')' { last_writer_options->mark_freq = $3; } | KW_MARK_MODE '(' KW_INTERNAL ')' { log_writer_options_set_mark_mode(last_writer_options, "internal"); } | KW_MARK_MODE '(' string ')' { CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3); log_writer_options_set_mark_mode(last_writer_options, $3); free($3); } | KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; } | { last_template_options = &last_writer_options->template_options; } template_option ; dest_writer_options_flags : normalized_flag dest_writer_options_flags { $$ = log_writer_options_lookup_flag($1) | $2; free($1); } | { $$ = 0; } ; file_perm_option : KW_OWNER '(' string_or_number ')' { file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); } | KW_OWNER '(' ')' { file_perm_options_dont_change_file_uid(last_file_perm_options); } | KW_GROUP '(' string_or_number ')' { file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); } | KW_GROUP '(' ')' { file_perm_options_dont_change_file_gid(last_file_perm_options); } | KW_PERM '(' LL_NUMBER ')' { file_perm_options_set_file_perm(last_file_perm_options, $3); } | KW_PERM '(' ')' { file_perm_options_dont_change_file_perm(last_file_perm_options); } | KW_DIR_OWNER '(' string_or_number ')' { file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); } | KW_DIR_OWNER '(' ')' { file_perm_options_dont_change_dir_uid(last_file_perm_options); } | KW_DIR_GROUP '(' string_or_number ')' { file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); } | KW_DIR_GROUP '(' ')' { file_perm_options_dont_change_dir_gid(last_file_perm_options); } | KW_DIR_PERM '(' LL_NUMBER ')' { file_perm_options_set_dir_perm(last_file_perm_options, $3); } | KW_DIR_PERM '(' ')' { file_perm_options_dont_change_dir_perm(last_file_perm_options); } ; template_option : KW_TS_FORMAT '(' string ')' { last_template_options->ts_format = cfg_ts_format_value($3); free($3); } | KW_FRAC_DIGITS '(' nonnegative_integer ')' { last_template_options->frac_digits = $3; } | KW_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); } | KW_SEND_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); } | KW_LOCAL_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); } | KW_ON_ERROR '(' string ')' { gint on_error; CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3); free($3); log_template_options_set_on_error(last_template_options, on_error); } ; matcher_option : KW_TYPE '(' string ')' { CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); } | KW_FLAGS '(' matcher_flags ')' ; matcher_flags : string matcher_flags { CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); } | ; value_pair_option : KW_VALUE_PAIRS { last_value_pairs = value_pairs_new(configuration); } '(' vp_options ')' { $$ = last_value_pairs; } ; vp_options : vp_option vp_options | ; vp_option : KW_PAIR '(' string ':' template_content ')' { value_pairs_add_pair(last_value_pairs, $3, $5); free($3); } | KW_PAIR '(' string template_content ')' { value_pairs_add_pair(last_value_pairs, $3, $4); free($3); } | KW_KEY '(' string KW_REKEY '(' { last_vp_transset = value_pairs_transform_set_new($3); value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE); free($3); } vp_rekey_options ')' { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')' | KW_KEY '(' string_list ')' { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); } | KW_REKEY '(' string { last_vp_transset = value_pairs_transform_set_new($3); free($3); } vp_rekey_options ')' { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } | KW_EXCLUDE '(' string_list ')' { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); } | KW_SCOPE '(' vp_scope_list ')' | KW_CAST '(' yesno ')' { value_pairs_set_cast_to_strings(last_value_pairs, $3); } | KW_INCLUDE_BYTES '(' yesno ')' { value_pairs_set_include_bytes(last_value_pairs, $3); } ; vp_scope_list : string vp_scope_list { value_pairs_add_scope(last_value_pairs, $1); free($1); } | ; vp_rekey_options : vp_rekey_option vp_rekey_options | ; vp_rekey_option : KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); } | KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); } | KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); } | KW_REPLACE_PREFIX '(' string string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_replace_prefix($3, $4)); free($3); free($4); } | KW_UPPER '(' ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_upper()); } | KW_LOWER '(' ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_lower()); } ; rewrite_expr_opt : KW_VALUE '(' string ')' { const gchar *p = $3; if (p[0] == '$') { msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates", evt_tag_str("value", $3), cfg_lexer_format_location_tag(lexer, &@3)); p++; } last_rewrite->value_handle = log_msg_get_value_handle(p); CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p); CHECK_ERROR(log_msg_is_value_name_valid(p), @3, "%s is not a valid name for a name-value pair, perhaps a misspelled .SDATA reference?", p); free($3); } | KW_INTERNAL '(' yesno ')' { log_pipe_set_internal(&last_rewrite->super, $3); } | rewrite_condition_opt ; rewrite_condition_opt : KW_CONDITION '(' { FilterExprNode *filter_expr; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1); log_rewrite_set_condition(last_rewrite, filter_expr); } ')' ; multi_line_option : KW_MULTI_LINE_MODE '(' string ')' { CHECK_ERROR(multi_line_options_set_mode(last_multi_line_options, $3), @3, "Invalid multi-line mode"); free($3); } | KW_MULTI_LINE_PREFIX '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(multi_line_options_set_prefix(last_multi_line_options, $3, &error), @3, error, "error compiling multi-line regexp"); free($3); } | KW_MULTI_LINE_GARBAGE '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(multi_line_options_set_garbage(last_multi_line_options, $3, &error), @3, error, "error compiling multi-line regexp"); free($3); } ; _root_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_ROOT, NULL, "root context"); }; _root_context_pop: { cfg_lexer_pop_context(lexer); }; _destination_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); }; _destination_context_pop: { cfg_lexer_pop_context(lexer); }; _source_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); }; _source_context_pop: { cfg_lexer_pop_context(lexer); }; _parser_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_PARSER, NULL, "parser statement"); }; _parser_context_pop: { cfg_lexer_pop_context(lexer); }; _rewrite_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_REWRITE, NULL, "rewrite statement"); }; _rewrite_context_pop: { cfg_lexer_pop_context(lexer); }; _filter_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_FILTER, NULL, "filter statement"); }; _filter_context_pop: { cfg_lexer_pop_context(lexer); }; _log_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_LOG, NULL, "log statement"); }; _log_context_pop: { cfg_lexer_pop_context(lexer); }; _block_def_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_BLOCK_DEF, block_def_keywords, "block definition"); }; _block_def_context_pop: { cfg_lexer_pop_context(lexer); }; _block_ref_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_BLOCK_REF, NULL, "block reference"); }; _block_ref_context_pop: { cfg_lexer_pop_context(lexer); }; _block_content_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_BLOCK_CONTENT, NULL, "block content"); }; _block_content_context_pop: { cfg_lexer_pop_context(lexer); }; _block_arg_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_BLOCK_ARG, NULL, "block argument"); }; _block_arg_context_pop: { cfg_lexer_pop_context(lexer); }; _inner_dest_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_INNER_DEST, NULL, "within destination"); }; _inner_dest_context_pop: { cfg_lexer_pop_context(lexer); }; _inner_src_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_INNER_SRC, NULL, "within source"); }; _inner_src_context_pop: { cfg_lexer_pop_context(lexer); }; _options_context_push: { cfg_lexer_push_context(lexer, LL_CONTEXT_OPTIONS, NULL, "options statement"); }; _options_context_pop: { cfg_lexer_pop_context(lexer); }; /* END_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/cfg-lex.l000066400000000000000000000520421450431004300176260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %{ #include "syslog-ng.h" #include "cfg-lexer.h" #include "cfg-lexer-subst.h" #include "cfg-grammar.h" #include "messages.h" #include "parse-number.h" #include #include static gboolean yy_input_run_backtick_substitution(CfgLexer *self, gchar *buf, gsize buf_size, gsize *len) { gchar *res; GError *error = NULL; CFG_LTYPE *cur_lloc = &self->include_stack[self->include_depth].lloc; res = cfg_lexer_subst_args_in_input(self->cfg->globals, NULL, NULL, buf, -1, len, &error); if (!res) { msg_error("Error performing backtick substitution in configuration file", evt_tag_str("error", error->message), evt_tag_str("filename", cur_lloc->name), evt_tag_printf("line", "%d:%d", cur_lloc->first_line, cur_lloc->first_column)); g_clear_error(&error); goto error; } else { if (*len > buf_size) { msg_error("Error performing backtick substitution in configuration file, the target buffer is too small", evt_tag_int("buf_size", buf_size), evt_tag_str("filename", cur_lloc->name), evt_tag_printf("line", "%d:%d", cur_lloc->first_line, cur_lloc->first_column)); goto error; } else { memcpy(buf, res, *len); } g_free(res); return TRUE; } error: return FALSE; } static gboolean yy_patch_include_statement(CfgLexer *self, gchar *buf, gsize buf_size, gsize *len) { CFG_LTYPE *cur_lloc = &self->include_stack[self->include_depth].lloc; gchar *p = buf; p += strspn(p, " \t"); if (strncmp(p, "include", 7) != 0) return TRUE; p += 7; if (*p != ' ' && *p != '\t') return TRUE; p = strrchr(p, ';'); if (!p) return TRUE; *p = ' '; if (!cfg_is_config_version_older(configuration, VERSION_VALUE_3_20)) { msg_error("Error parsing old style include statement (e.g. the one without the '@' prefix), " "support for it was removed in " VERSION_3_20 ", just add a '@' in front or revert to @version " VERSION_3_19 " or older", evt_tag_str("filename", cur_lloc->name), evt_tag_printf("line", "%d:%d", cur_lloc->first_line, cur_lloc->first_column)); return FALSE; } if (*len + 1 > buf_size) { msg_error("Error performing the `include' patching to @include, the target buffer is too small", evt_tag_int("buf_size", buf_size), evt_tag_str("filename", cur_lloc->name), evt_tag_printf("line", "%d:%d", cur_lloc->first_line, cur_lloc->first_column)); return FALSE; } memmove(buf + 1, buf, *len); buf[0] = '@'; *len += 1; msg_warning("WARNING: the `include' keyword based inclusion syntax (e.g. the one without a '@' " "character in front) has been removed in " VERSION_3_20 ". Please prepend a '@' " "character in front of your include statement while updating your configuration " "to match the new version", evt_tag_str("filename", cur_lloc->name), evt_tag_printf("line", "%d:%d", cur_lloc->first_line, cur_lloc->first_column)); return TRUE; } static gint yy_filter_input(CfgLexer *self, gchar *buf, gsize buf_size) { gsize len = strlen(buf); if (!yy_input_run_backtick_substitution(self, buf, buf_size, &len)) return -1; if (!yy_patch_include_statement(self, buf, buf_size, &len)) return -1; return len; } #define YY_INPUT(buf, result, max_size) \ do \ { \ if (!fgets(buf, max_size, yyin)) \ result = YY_NULL; \ else if (YY_START >= block) \ result = strlen(buf); \ else \ { \ gint rc; \ rc = yy_filter_input(yyextra, buf, max_size); \ if (rc < 0) \ { \ YY_FATAL_ERROR("configuration input filtering failure"); \ } \ else \ { \ result = rc; \ } \ } \ } while(0) #define YY_USER_ACTION \ do { \ CFG_LTYPE *cur_lloc = &yyextra->include_stack[yyextra->include_depth].lloc; \ if (YY_START == INITIAL) \ { \ cur_lloc->first_column = cur_lloc->last_column; \ } \ cur_lloc->last_column = cur_lloc->last_column + yyleng; \ if (yyextra->token_text) \ g_string_append_len(yyextra->token_text, yytext, yyleng); \ *yylloc = *cur_lloc; \ } while(0); #define YY_BREAK \ do { \ if (yyextra->token_text && YY_START == INITIAL) \ { \ g_string_append_len(yyextra->token_pretext, yyextra->token_text->str, yyextra->token_text->len); \ g_string_truncate(yyextra->token_text, 0); \ } \ } while (0); \ break; #define YY_FATAL_ERROR(msg) \ do { \ struct yyguts_t * __yyg = (struct yyguts_t*) yyscanner; \ \ msg_error("Fatal error in configuration lexer, giving up", \ evt_tag_str("error", msg)); \ longjmp(__yyg->yyextra_r->fatal_error, 1); \ } while(0) #define _process_commented_line(scanner,content,cond) \ do { \ int ch; \ \ ch = input(scanner); \ while (ch != '\n' && ch != EOF && ch != 0) \ { \ if (cond) \ g_string_append_c(content, ch); \ ch = input(scanner); \ } \ if (ch == '\n') \ { \ unput(ch); \ } \ } while (0) static void _cfg_lex_move_token_location_to_new_line(CfgLexer *lexer) { CfgIncludeLevel *level = &lexer->include_stack[lexer->include_depth]; /* if the last token span multiple lines (e.g. block references), it * might happen that last_line != first_line, in that case, initialize the * first_line of the token to the subsequent line after last_line */ level->lloc.first_line = level->lloc.last_line + 1; level->lloc.last_line = level->lloc.first_line; level->lloc.first_column = 1; level->lloc.last_column = 1; } static void _cfg_lex_extend_token_location_to_next_line(CfgLexer *lexer) { CfgIncludeLevel *level = &lexer->include_stack[lexer->include_depth]; /* this function is used when encountering an NL character within a * multi-line string literal. * * Example: * | "this is the start of the literal\ * | and this is the end" * * * In this case the string contains a escaped NL character, causing the * literal to span two distinct lines in the source file, which would be * dropped from the parsed string. * * In this case, we need to move yylloc to point from the end of the * current line to the beginning of the next line. This way, by the time * we return the entire token, yylloc would be spanning the * starting-ending lines of the string literal as needed. * */ level->lloc.last_line++; level->lloc.last_column = 1; } #define YYSTYPE CFG_STYPE #define YYLTYPE CFG_LTYPE %} %option bison-bridge bison-locations reentrant %option prefix="_cfg_lexer_" %option header-file="lex.yy.h" %option outfile="lex.yy.c" %option extra-type="CfgLexer *" %option noyywrap %option stack white [ \t] digit [0-9] xdigit [0-9a-fA-F] odigit [0-7] alpha [a-zA-Z] alphanum [a-zA-Z0-9] word [^ \#'"\(\)\{\}\[\]\\;\r\n\t,|\.@:] /* block related states must be last, as we use this fact in YY_INPUT */ %x string %x qstring %x block %x block_content %x block_string %x block_qstring %% \# { _process_commented_line(yyscanner,yyextra->token_text,yyextra->token_text); } ^@ { return LL_PRAGMA; } /* continuation line: just move the location and skip the newline character */ \\\r?\n { _cfg_lex_extend_token_location_to_next_line(yyextra); } \r?\n { *yylloc = yyextra->include_stack[yyextra->include_depth].lloc; _cfg_lex_move_token_location_to_new_line(yyextra); if (yyextra->tokenize_eol) return LL_EOL; else g_string_append(yyextra->string_buffer, yytext); } {white}+ ; \.\. { return LL_DOTDOT; } \.\.\. { return LL_DOTDOTDOT; } => { return LL_ARROW; } (-|\+)?{digit}+\.{digit}+ { yylval->fnum = strtod(yytext, NULL); return LL_FLOAT; } 0x{xdigit}+ { if (!parse_int64_base16(yytext, &yylval->num)) { return LL_ERROR; } return LL_NUMBER; } 0{odigit}+ { if (!parse_int64_base8(yytext, &yylval->num)) { return LL_ERROR; } return LL_NUMBER; } (-|\+)?{digit}+(M|m|G|g|k|K)?(i|I)?(b|B)? { if (!parse_int64_with_suffix(yytext, &yylval->num)) { return LL_ERROR; } return LL_NUMBER; } ({word}+(\.)?)*{word}+ { return cfg_lexer_map_word_to_token(yyextra, yylval, yylloc, yytext); } \, ; \" { g_string_truncate(yyextra->string_buffer, 0); yy_push_state(string, yyscanner); } \' { g_string_truncate(yyextra->string_buffer, 0); yy_push_state(qstring, yyscanner); } . { return (unsigned char) yytext[0]; } /* continuation line within a string: just move the location and skip the newline character as if it was never there */ \\\r?\n { _cfg_lex_extend_token_location_to_next_line(yyextra); } \\a { g_string_append_c(yyextra->string_buffer, 7); } \\n { g_string_append_c(yyextra->string_buffer, 10); } \\r { g_string_append_c(yyextra->string_buffer, 13); } \\t { g_string_append_c(yyextra->string_buffer, 9); } \\v { g_string_append_c(yyextra->string_buffer, 11); } \\x{xdigit}{1,2} { g_string_append_c(yyextra->string_buffer, strtol(yytext+2, NULL, 16)); } \\o{odigit}{1,3} { g_string_append_c(yyextra->string_buffer, strtol(yytext+2, NULL, 8)); } \\[^anrtv] { g_string_append_c(yyextra->string_buffer, yytext[1]); } \" { yy_pop_state(yyscanner); yylval->cptr = strdup(yyextra->string_buffer->str); return LL_STRING; } [^"\\\r\n]+ { g_string_append(yyextra->string_buffer, yytext); } [^'\r\n]+ { g_string_append(yyextra->string_buffer, yytext); } \' { yy_pop_state(yyscanner); yylval->cptr = strdup(yyextra->string_buffer->str); return LL_STRING; } /* the rule below will only be applied to embedded newlines within * string/qstring. There's a difference how we handle backslash quotation * of newline though. * * If a \\\n sequence is in a (e.g. quoted newline) * - the backslash is explicitly not allowed in the greedy rule that eats string characters * - thus <*>\\\r?\n rule gets applied, at the top of the file, removing the newline * - location tracking is preserved * * If a \n sequence is in a (e.g. embedded newline) * - the newline character is processed by the rule below, thus it is * included as a literal newline * * If a \\\n sequence is in a (e.g. quotation is not supported) * - the backslash is eaten by the greedy rule for qstring * - <*>\\\r?\n is not matching as the backslash is not there * - the rule below gets matched and the newline is included in the string * * If a \n sequence is in a (e.g. embedded newline) * - the rule below gets matched and the newline is included in the string */ \r?\n { g_string_append(yyextra->string_buffer, yytext); _cfg_lex_extend_token_location_to_next_line(yyextra); } /* continuation line within blocks: in the block header we just ignore * the continuation line, whereas in string/qstring we retain them * literally. */ \\\r?\n { _cfg_lex_extend_token_location_to_next_line(yyextra); } \\\r?\n { g_string_append(yyextra->string_buffer, yytext); _cfg_lex_extend_token_location_to_next_line(yyextra); } /* rules to parse a block as a LL_BLOCK token */ {white}+ ; [^{( \t\r\n]+ { YY_FATAL_ERROR("Expected opening bracket as block boundary, e.g. opening brace or parenthesis"); } \r?\n { _cfg_lex_move_token_location_to_new_line(yyextra); }; \({white}*\) { yy_pop_state(yyscanner); yylval->cptr = NULL; return LL_BLOCK; } \({white}*\"\"{white}*\) { yy_pop_state(yyscanner); yylval->cptr = g_strdup(""); return LL_BLOCK; } \({white}*\'\'{white}*\) { yy_pop_state(yyscanner); yylval->cptr = g_strdup(""); return LL_BLOCK; } /* start character of the block */ [{(] { if (yytext[0] != yyextra->block_boundary[0]) REJECT; g_string_truncate(yyextra->string_buffer, 0); yyextra->brace_count = 1; yy_push_state(block_content, yyscanner); } /* block_content, handle embedded string/qstring/comments properly, count * braces so we only end the block if they are pairing up, unless they are * in a string/qstring/comment. */ \" { g_string_append_c(yyextra->string_buffer, yytext[0]); yy_push_state(block_string, yyscanner); } \' { g_string_append_c(yyextra->string_buffer, yytext[0]); yy_push_state(block_qstring, yyscanner); } \# { g_string_append_c(yyextra->string_buffer, yytext[0]); _process_commented_line(yyscanner, yyextra->string_buffer, TRUE); } [{(] { g_string_append_c(yyextra->string_buffer, yytext[0]); if (yytext[0] == yyextra->block_boundary[0]) yyextra->brace_count++; } [})] { if (yytext[0] == yyextra->block_boundary[1]) yyextra->brace_count--; if (yyextra->brace_count == 0) { yy_pop_state(yyscanner); yy_pop_state(yyscanner); yylval->cptr = strdup(yyextra->string_buffer->str); return LL_BLOCK; } else { g_string_append_c(yyextra->string_buffer, yytext[0]); } } [^{}()\"\'\n\r#]+ { g_string_append(yyextra->string_buffer, yytext); } [^\\"\r\n]+ { g_string_append(yyextra->string_buffer, yytext); } \\. { g_string_append(yyextra->string_buffer, yytext); } \" { g_string_append_c(yyextra->string_buffer, yytext[0]); yy_pop_state(yyscanner); } \' { g_string_append_c(yyextra->string_buffer, yytext[0]); yy_pop_state(yyscanner); } [^'\r\n]+ { g_string_append(yyextra->string_buffer, yytext); } /* The newlines embedded in block_string/block_qstring/block_content is * literally coped into the block token, even if there's backslash as the * last character. Basically we behave just as if the entire block was a * qstring. */ \r?\n { g_string_append(yyextra->string_buffer, yytext); _cfg_lex_extend_token_location_to_next_line(yyextra); } <> { if (!cfg_lexer_start_next_include(yyextra)) { if (yyextra->include_depth == 0) { *yylloc = yyextra->include_stack[0].lloc; yyterminate(); } else return LL_ERROR; } } %% void cfg_lexer_unput_string(CfgLexer *self, const char *str) { int len = strlen(str); int i; for (i = len - 1; i >= 0; i--) { yyunput(str[i], _cfg_lexer_get_text(self->state), self->state); self->include_stack[self->include_depth].lloc.first_column--; self->include_stack[self->include_depth].lloc.last_column--; } } void cfg_lexer_start_block_state(CfgLexer *self, const gchar block_boundary[2]) { memcpy(&self->block_boundary, block_boundary, sizeof(self->block_boundary)); yy_push_state(block, self->state); } /* avoid warnings of unused symbols */ gpointer __dummy[] = { yy_top_state, yy_fatal_error }; syslog-ng-syslog-ng-4.4.0/lib/cfg-lexer-subst.c000066400000000000000000000203671450431004300213070ustar00rootroot00000000000000/* * Copyright (c) 2010-2013 Balabit * Copyright (c) 2010-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-lexer-subst.h" #include "cfg-args.h" #include "cfg-grammar.h" #include #include typedef enum _CfgLexerStringTrackState { CLS_NOT_STRING, CLS_WITHIN_STRING, CLS_WITHIN_STRING_QUOTE, CLS_WITHIN_STRING_QUOTED_CHARACTER, CLS_WITHIN_QSTRING, } CfgLexerStringTrackState; /* substitute backtick references into lexer input */ struct _CfgLexerSubst { CfgArgs *globals; CfgArgs *defs; CfgArgs *args; CfgLexerStringTrackState string_state; GString *result_buffer; }; static const gchar * _lookup_value(CfgLexerSubst *self, const gchar *name) { const gchar *arg; if (self->args && (arg = cfg_args_get(self->args, name))) ; else if (self->defs && (arg = cfg_args_get(self->defs, name))) ; else if (self->globals && (arg = cfg_args_get(self->globals, name))) ; else if ((arg = g_getenv(name))) ; else arg = NULL; return arg; } static CfgLexerStringTrackState _track_string_state(CfgLexerSubst *self, CfgLexerStringTrackState last_state, const gchar *p) { switch (last_state) { case CLS_NOT_STRING: if (*p == '"') return CLS_WITHIN_STRING; else if (*p == '\'') return CLS_WITHIN_QSTRING; return CLS_NOT_STRING; case CLS_WITHIN_STRING: case CLS_WITHIN_STRING_QUOTED_CHARACTER: if (*p == '\\') return CLS_WITHIN_STRING_QUOTE; else if (*p == '"') return CLS_NOT_STRING; return CLS_WITHIN_STRING; case CLS_WITHIN_STRING_QUOTE: return CLS_WITHIN_STRING_QUOTED_CHARACTER; case CLS_WITHIN_QSTRING: if (*p == '\'') return CLS_NOT_STRING; return CLS_WITHIN_QSTRING; default: g_assert_not_reached(); break; } g_assert_not_reached(); } static gchar * _extract_string_literal(const gchar *value) { CfgLexer *lexer; gint token, look_ahead_token; CFG_STYPE yylval, look_ahead_yylval; CFG_LTYPE yylloc, look_ahead_yylloc; gchar *result = NULL; lexer = cfg_lexer_new_buffer(configuration, value, strlen(value)); token = cfg_lexer_lex(lexer, &yylval, &yylloc); if (token == LL_STRING) { look_ahead_token = cfg_lexer_lex(lexer, &look_ahead_yylval, &look_ahead_yylloc); if (!look_ahead_token) result = g_strdup(yylval.cptr); cfg_lexer_free_token(&look_ahead_yylval); } cfg_lexer_free_token(&yylval); cfg_lexer_free(lexer); return result; } static gboolean _encode_as_string(CfgLexerSubst *self, const gchar *value, GError **error) { gint i; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); for (i = 0; value[i]; i++) { gchar p = value[i]; if (p == '"') g_string_append(self->result_buffer, "\\\""); else if (p == '\n') g_string_append(self->result_buffer, "\\n"); else if (p == '\r') g_string_append(self->result_buffer, "\\r"); else if (p == '\\') g_string_append(self->result_buffer, "\\\\"); else g_string_append_c(self->result_buffer, p); } return TRUE; } static gboolean _encode_as_qstring(CfgLexerSubst *self, const gchar *value, GError **error) { gint i; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); for (i = 0; value[i]; i++) { gchar p = value[i]; if (p == '\'') { g_set_error(error, CFG_LEXER_ERROR, CFG_LEXER_CANNOT_REPRESENT_APOSTROPHES_IN_QSTRINGS, "cannot represent apostrophes within apostroph-enclosed string"); return FALSE; } g_string_append_c(self->result_buffer, p); } return TRUE; } static gboolean _append_value(CfgLexerSubst *self, const gchar *value, GError **error) { g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); gboolean result = TRUE; if (self->string_state == CLS_NOT_STRING) { g_string_append(self->result_buffer, value); } else { gchar *string_literal; string_literal = _extract_string_literal(value); if (string_literal) { switch (self->string_state) { case CLS_WITHIN_STRING: result = _encode_as_string(self, string_literal, error); break; case CLS_WITHIN_QSTRING: result = _encode_as_qstring(self, string_literal, error); break; default: g_assert_not_reached(); break; } g_free(string_literal); } else g_string_append(self->result_buffer, value); } return result; } gchar * cfg_lexer_subst_invoke(CfgLexerSubst *self, const gchar *input, gssize input_len, gsize *output_length, GError **error) { gboolean backtick = FALSE; const gchar *p, *ref_start = input; GString *result; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if (input_len < 0) input_len = strlen(input); result = g_string_sized_new(32); self->result_buffer = result; p = input; while (p - input < input_len) { self->string_state = _track_string_state(self, self->string_state, p); if (!backtick && (*p) == '`') { if (self->string_state == CLS_WITHIN_STRING_QUOTED_CHARACTER) { g_set_error(error, CFG_LEXER_ERROR, CFG_LEXER_BACKTICKS_CANT_BE_SUBSTITUTED_AFTER_BACKSLASH, "cannot subsitute backticked values right after a string quote character"); goto error; } /* start of reference */ backtick = TRUE; ref_start = p + 1; } else if (backtick && (*p) == '`') { /* end of reference */ backtick = FALSE; if (ref_start == p) { /* empty ref, just include a ` character */ g_string_append_c(result, '`'); } else { const gchar *value; gchar *name; name = g_strndup(ref_start, p - ref_start); value = _lookup_value(self, name); g_free(name); if (!_append_value(self, value ? : "", error)) goto error; } } else if (!backtick) g_string_append_c(result, *p); p++; } self->result_buffer = NULL; if (backtick) { g_set_error(error, CFG_LEXER_ERROR, CFG_LEXER_MISSING_BACKTICK_PAIR, "missing closing backtick (`) character"); goto error; } *output_length = result->len; return g_string_free(result, FALSE); error: g_string_free(result, TRUE); return NULL; } CfgLexerSubst * cfg_lexer_subst_new(CfgArgs *globals, CfgArgs *defs, CfgArgs *args) { CfgLexerSubst *self = g_new0(CfgLexerSubst, 1); self->globals = globals; self->defs = defs; self->args = args; return self; } void cfg_lexer_subst_free(CfgLexerSubst *self) { cfg_args_unref(self->globals); cfg_args_unref(self->defs); cfg_args_unref(self->args); g_free(self); } gchar * cfg_lexer_subst_args_in_input(CfgArgs *globals, CfgArgs *defs, CfgArgs *args, const gchar *input, gssize input_length, gsize *output_length, GError **error) { CfgLexerSubst *subst = cfg_lexer_subst_new(cfg_args_ref(globals), cfg_args_ref(defs), cfg_args_ref(args)); gchar *result; result = cfg_lexer_subst_invoke(subst, input, input_length, output_length, error); cfg_lexer_subst_free(subst); return result; } syslog-ng-syslog-ng-4.4.0/lib/cfg-lexer-subst.h000066400000000000000000000032021450431004300213010ustar00rootroot00000000000000/* * Copyright (c) 2010-2013 Balabit * Copyright (c) 2010-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_LEXER_SUBST_H_INCLUDED #define CFG_LEXER_SUBST_H_INCLUDED 1 #include "syslog-ng.h" #include "cfg-args.h" typedef struct _CfgLexerSubst CfgLexerSubst; gchar *cfg_lexer_subst_invoke(CfgLexerSubst *self, const gchar *input, gssize input_len, gsize *output_length, GError **error); CfgLexerSubst *cfg_lexer_subst_new(CfgArgs *globals, CfgArgs *defs, CfgArgs *args); void cfg_lexer_subst_free(CfgLexerSubst *self); gchar * cfg_lexer_subst_args_in_input(CfgArgs *globals, CfgArgs *defs, CfgArgs *args, const gchar *input, gssize input_length, gsize *output_length, GError **error); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-lexer.c000066400000000000000000001046601450431004300201500ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-lexer.h" #include "cfg-lexer-subst.h" #include "cfg-block-generator.h" #include "cfg-grammar.h" #include "block-ref-parser.h" #include "pragma-parser.h" #include "messages.h" #include "pathutils.h" #include "plugin.h" #include "plugin-types.h" #include #include #include /* include header for generated lexer */ #define YYSTYPE CFG_STYPE #define YYLTYPE CFG_LTYPE #include "cfg-lex.h" #undef YYSTYPE #undef YYLTYPE /* * A token block is a series of tokens to be injected into the tokens * fetched by the lexer. It is assumed to be filled and then depleted, the * two operations cannot be intermixed. */ struct _CfgTokenBlock { gint pos; GArray *tokens; }; /** * CfgLexerContext: * * This object tells the lexer in which context it is operating right * now. The context influences the way the lexer works, for example in * LL_CONTEXT_BLOCK_DEF/REF all keyword resolutions are disabled. * * A textual description is also associated with the current context * in order to give better error messages. **/ typedef struct _CfgLexerContext { gint type; CfgLexerKeyword *keywords; gchar desc[0]; } CfgLexerContext; typedef enum { CLPR_ERROR, CLPR_OK, CLPR_LEX_AGAIN } CfgLexerPreprocessResult; /* * cfg_lexer_push_context: * * This function can be used to push a lexer context to the stack. The top * of the stack determines how an error is reported and can also influence * the lexer. */ void cfg_lexer_push_context(CfgLexer *self, gint type, CfgLexerKeyword *keywords, const gchar *desc) { CfgLexerContext *context; context = g_malloc(sizeof(CfgLexerContext) + strlen(desc) + 1); context->type = type ? type : cfg_lexer_get_context_type(self); context->keywords = keywords; memcpy(&context->desc, desc, strlen(desc) + 1); self->context_stack = g_list_prepend(self->context_stack, context); } /* * cfg_lexer_pop_context: * * Pop the topmost item off the stack. */ void cfg_lexer_pop_context(CfgLexer *self) { if (self->context_stack) { g_free((gchar *) self->context_stack->data); self->context_stack = g_list_delete_link(self->context_stack, self->context_stack); } } /* * cfg_lexer_get_context_type: * * Get the current context type (one of LL_CONTEXT_* values). */ gint cfg_lexer_get_context_type(CfgLexer *self) { GList *l; l = self->context_stack; if (l) return ((CfgLexerContext *) l->data)->type; return 0; } /* * cfg_lexer_get_context_description: * * Get the description of the current context. */ const gchar * cfg_lexer_get_context_description(CfgLexer *self) { GList *l; l = self->context_stack; if (l) return ((CfgLexerContext *) l->data)->desc; return "configuration"; } const gchar * cfg_lexer_format_location(CfgLexer *self, const CFG_LTYPE *yylloc, gchar *buf, gsize buf_len) { g_snprintf(buf, buf_len, "%s:%d:%d", yylloc->name ? : "#buffer", yylloc->first_line, yylloc->first_column); return buf; } EVTTAG * cfg_lexer_format_location_tag(CfgLexer *self, const CFG_LTYPE *yylloc) { gchar buf[256]; return evt_tag_str("location", cfg_lexer_format_location(self, yylloc, buf, sizeof(buf))); } void cfg_lexer_set_file_location(CfgLexer *self, const gchar *filename, gint line, gint column) { CfgIncludeLevel *level = &self->include_stack[self->include_depth]; level->lloc.name = g_intern_string(filename); level->lloc.first_line = level->lloc.last_line = line; level->lloc.first_column = level->lloc.last_column = column; level->lloc_changed_by_at_line = TRUE; } static int cfg_lexer_lookup_keyword(CfgLexer *self, CFG_STYPE *yylval, const CFG_LTYPE *yylloc, const char *token) { GList *l; l = self->context_stack; while (l) { CfgLexerContext *context = ((CfgLexerContext *) l->data); CfgLexerKeyword *keywords = context->keywords; if (keywords) { int i, j; for (i = 0; keywords[i].kw_name; i++) { if (strcmp(keywords[i].kw_name, CFG_KEYWORD_STOP) == 0) { yylval->type = LL_IDENTIFIER; yylval->cptr = strdup(token); return LL_IDENTIFIER; } for (j = 0; token[j] && keywords[i].kw_name[j]; j++) { if (token[j] == '-' || token[j] == '_') { if (keywords[i].kw_name[j] != '_') break; } else if (token[j] != keywords[i].kw_name[j]) break; } if (token[j] == 0 && keywords[i].kw_name[j] == 0) { /* match */ switch (keywords[i].kw_status) { case KWS_OBSOLETE: msg_warning("WARNING: Your configuration file uses an obsoleted keyword, please update your configuration", evt_tag_str("keyword", keywords[i].kw_name), evt_tag_str("change", keywords[i].kw_explain), cfg_lexer_format_location_tag(self, yylloc)); break; default: break; } keywords[i].kw_status = KWS_NORMAL; yylval->type = LL_TOKEN; yylval->token = keywords[i].kw_token; return keywords[i].kw_token; } } } l = l->next; } yylval->type = LL_IDENTIFIER; yylval->cptr = strdup(token); return LL_IDENTIFIER; } int cfg_lexer_map_word_to_token(CfgLexer *self, CFG_STYPE *yylval, const CFG_LTYPE *yylloc, const char *token) { int tok = cfg_lexer_lookup_keyword(self, yylval, yylloc, token); if (tok == LL_IDENTIFIER) { /* plugins registered into the current context use a separate token, * LL_PLUGIN, so that LL_IDENTIFIER can still be used in our grammar * to distinguish rules. This is used to allow plugins in our filter * expressions but still be able to use non-quoted literals */ if (self->cfg && plugin_is_plugin_available(&self->cfg->plugin_context, cfg_lexer_get_context_type(self), token)) return LL_PLUGIN; } return tok; } void cfg_lexer_init_include_level_file(CfgLexer *self, CfgIncludeLevel *level) { level->include_type = CFGI_FILE; } void cfg_lexer_include_level_file_add(CfgLexer *self, CfgIncludeLevel *level, const gchar *filename) { g_assert(level->include_type == CFGI_FILE); level->file.files = g_slist_insert_sorted(level->file.files, g_strdup(filename), (GCompareFunc) strcmp); msg_debug("Adding include file", evt_tag_str("filename", filename), evt_tag_int("depth", self->include_depth)); } gboolean cfg_lexer_include_level_file_open_buffer(CfgLexer *self, CfgIncludeLevel *level) { FILE *include_file; gchar *filename; g_assert(level->include_type == CFGI_FILE); filename = (gchar *) level->file.files->data; level->file.files = g_slist_delete_link(level->file.files, level->file.files); include_file = fopen(filename, "r"); if (!include_file) { msg_error("Error opening include file", evt_tag_str("filename", filename), evt_tag_int("depth", self->include_depth)); g_free(filename); return FALSE; } msg_debug("Starting to read include file", evt_tag_str("filename", filename), evt_tag_int("depth", self->include_depth)); level->lloc.name = g_intern_string(filename); g_free(filename); level->file.include_file = include_file; level->yybuf = _cfg_lexer__create_buffer(level->file.include_file, YY_BUF_SIZE, self->state); return TRUE; } void cfg_lexer_include_level_file_close_buffer(CfgLexer *self, CfgIncludeLevel *level) { if (level->file.include_file) { fclose(level->file.include_file); level->file.include_file = NULL; } } void cfg_lexer_init_include_level_buffer(CfgLexer *self, CfgIncludeLevel *level, const gchar *name, const gchar *buffer, gsize length) { level->include_type = CFGI_BUFFER; level->lloc.name = g_intern_string(name); gint lexer_buffer_len = length + 2; gchar *lexer_buffer = g_malloc(lexer_buffer_len); memcpy(lexer_buffer, buffer, length); /* need two NUL characters for flex */ lexer_buffer[length] = 0; lexer_buffer[length + 1] = 0; level->buffer.content = lexer_buffer; level->buffer.content_length = lexer_buffer_len; level->buffer.original_content = g_strdup(lexer_buffer); } gboolean cfg_lexer_include_level_buffer_open_buffer(CfgLexer *self, CfgIncludeLevel *level) { g_assert(level->include_type == CFGI_BUFFER); level->yybuf = _cfg_lexer__scan_buffer(level->buffer.content, level->buffer.content_length, self->state); return TRUE; } gboolean cfg_lexer_include_level_open_buffer(CfgLexer *self, CfgIncludeLevel *level) { g_assert(level->include_type == CFGI_BUFFER || level->include_type == CFGI_FILE); if (level->include_type == CFGI_BUFFER && !cfg_lexer_include_level_buffer_open_buffer(self, level)) return FALSE; if (level->include_type == CFGI_FILE && !cfg_lexer_include_level_file_open_buffer(self, level)) return FALSE; level->lloc.first_line = level->lloc.last_line = 1; level->lloc.first_column = level->lloc.last_column = 1; return TRUE; } void cfg_lexer_include_level_close_buffer(CfgLexer *self, CfgIncludeLevel *level) { g_assert(level->yybuf); _cfg_lexer__delete_buffer(level->yybuf, self->state); level->yybuf = NULL; if (level->include_type == CFGI_FILE) cfg_lexer_include_level_file_close_buffer(self, level); } void cfg_lexer_include_level_resume_from_buffer(CfgLexer *self, CfgIncludeLevel *level) { _cfg_lexer__switch_to_buffer(level->yybuf, self->state); } void cfg_lexer_include_level_clear(CfgLexer *self, CfgIncludeLevel *level) { if (level->yybuf) _cfg_lexer__delete_buffer(level->yybuf, self->state); if (level->include_type == CFGI_FILE) { if (level->file.include_file) fclose(level->file.include_file); g_slist_foreach(level->file.files, (GFunc) g_free, NULL); g_slist_free(level->file.files); } else if (level->include_type == CFGI_BUFFER) { g_free(level->buffer.content); g_free(level->buffer.original_content); } memset(level, 0, sizeof(*level)); } CfgIncludeLevel * cfg_lexer_alloc_include_level(CfgLexer *self, const gchar *include_target) { if (self->include_depth >= MAX_INCLUDE_DEPTH - 1) { msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile", evt_tag_str("include", include_target), evt_tag_int("depth", self->include_depth)); return NULL; } self->include_depth++; return &self->include_stack[self->include_depth]; } void cfg_lexer_drop_include_level(CfgLexer *self, CfgIncludeLevel *level) { g_assert(&self->include_stack[self->include_depth] == level); cfg_lexer_include_level_clear(self, level); self->include_depth--; } gboolean cfg_lexer_start_next_include(CfgLexer *self) { CfgIncludeLevel *level = &self->include_stack[self->include_depth]; gboolean level_finished = FALSE; if (self->include_depth == 0) { return FALSE; } if (level->yybuf) { msg_debug("Finishing include", evt_tag_str((level->include_type == CFGI_FILE ? "filename" : "content"), level->lloc.name), evt_tag_int("depth", self->include_depth)); if ((level->include_type == CFGI_BUFFER) || (level->include_type == CFGI_FILE && !level->file.files)) level_finished = TRUE; cfg_lexer_include_level_close_buffer(self, level); } if (level_finished) { /* we finished with an include statement that included a series of * files (e.g. directory include). We need to terminate the current * level and resume from our parent. */ cfg_lexer_drop_include_level(self, &self->include_stack[self->include_depth]); cfg_lexer_include_level_resume_from_buffer(self, &self->include_stack[self->include_depth]); return TRUE; } else { /* the level is not yet finished, let's go open the buffer and restart from there */ if (!cfg_lexer_include_level_open_buffer(self, level)) return FALSE; cfg_lexer_include_level_resume_from_buffer(self, level); return TRUE; } } static gboolean cfg_lexer_include_directory(CfgLexer *self, CfgIncludeLevel *level, const gchar *filename) { GDir *dir; GError *error = NULL; const gchar *entry; dir = g_dir_open(filename, 0, &error); if (!dir) { msg_error("Error opening directory for reading", evt_tag_str("filename", filename), evt_tag_str("error", error->message)); g_error_free(error); return FALSE; } while ((entry = g_dir_read_name(dir))) { const gchar *p; if (entry[0] == '.') { msg_debug("Skipping include file, it cannot begin with .", evt_tag_str("filename", entry)); continue; } for (p = entry; *p; p++) { if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '_') || (*p == '-') || (*p == '.'))) { msg_debug("Skipping include file, does not match pattern [\\-_a-zA-Z0-9]+", evt_tag_str("filename", entry)); p = NULL; break; } } if (p) { struct stat st; gchar *full_filename = g_build_filename(filename, entry, NULL); if (stat(full_filename, &st) < 0 || S_ISDIR(st.st_mode)) { msg_debug("Skipping include file as it is a directory", evt_tag_str("filename", entry)); g_free(full_filename); continue; } cfg_lexer_include_level_file_add(self, level, full_filename); g_free(full_filename); } } g_dir_close(dir); return TRUE; } static gboolean cfg_lexer_include_file_simple(CfgLexer *self, const gchar *filename) { CfgIncludeLevel *level; struct stat st; if (stat(filename, &st) < 0) { return FALSE; } level = cfg_lexer_alloc_include_level(self, filename); if (!level) return FALSE; cfg_lexer_init_include_level_file(self, level); if (S_ISDIR(st.st_mode)) { if (!cfg_lexer_include_directory(self, level, filename)) { cfg_lexer_drop_include_level(self, level); return FALSE; } if (!level->file.files) { /* no include files in the specified directory */ msg_debug("No files in this include directory", evt_tag_str("dir", filename)); cfg_lexer_drop_include_level(self, level); return TRUE; } } else { cfg_lexer_include_level_file_add(self, level, filename); } return cfg_lexer_start_next_include(self); } static int _cfg_lexer_glob_err (const char *p, gint e) { if (e != ENOENT) { msg_debug ("Error processing path for inclusion", evt_tag_str("path", p), evt_tag_errno("errno", e)); return -1; } return 0; } #ifndef GLOB_NOMAGIC #define GLOB_NOMAGIC 0 int __glob_pattern_p (const char *pattern) { register const char *p; int open = 0; for (p = pattern; *p != '\0'; ++p) switch (*p) { case '?': case '*': return 1; case '\\': if (p[1] != '\0') ++p; break; case '[': open = 1; break; case ']': if (open) return 1; break; } return 0; } #else #define SYSLOG_NG_HAVE_GLOB_NOMAGIC 1 #endif static gboolean cfg_lexer_include_file_glob_at(CfgLexer *self, CfgIncludeLevel *level, const gchar *pattern) { glob_t globbuf; size_t i; int r; r = glob(pattern, GLOB_NOMAGIC, _cfg_lexer_glob_err, &globbuf); if (r != 0) { globfree(&globbuf); if (r == GLOB_NOMATCH) { #ifndef SYSLOG_NG_HAVE_GLOB_NOMAGIC if (!__glob_pattern_p (pattern)) { cfg_lexer_include_level_file_add(self, level, pattern); return TRUE; } #endif return FALSE; } return TRUE; } for (i = 0; i < globbuf.gl_pathc; i++) { cfg_lexer_include_level_file_add(self, level, globbuf.gl_pathv[i]); } globfree(&globbuf); return TRUE; } static const gchar * _get_include_path(CfgLexer *self) { return self->cfg ? cfg_args_get(self->cfg->globals, "include-path") : NULL; } static gboolean cfg_lexer_include_file_glob_along_include_path(CfgLexer *self, CfgIncludeLevel *level, const gchar *path, const gchar *filename_) { gboolean result = FALSE; gchar **dirs; gchar *cf; gint i = 0; dirs = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 0); while (dirs && dirs[i]) { cf = g_build_filename(dirs[i], filename_, NULL); result |= cfg_lexer_include_file_glob_at(self, level, cf); g_free(cf); i++; } g_strfreev(dirs); return result; } static gboolean cfg_lexer_include_file_glob(CfgLexer *self, const gchar *filename_) { const gchar *path = _get_include_path(self); gboolean process = FALSE; CfgIncludeLevel *level; level = cfg_lexer_alloc_include_level(self, filename_); if (!level) return FALSE; cfg_lexer_init_include_level_file(self, level); if (filename_[0] == '/' || !path) process = cfg_lexer_include_file_glob_at(self, level, filename_); else process = cfg_lexer_include_file_glob_along_include_path(self, level, path, filename_); if (!process) { cfg_lexer_drop_include_level(self, level); return TRUE; } if (!cfg_lexer_start_next_include(self)) { msg_error("Include file/directory not found", evt_tag_str("filename", filename_), evt_tag_str("include-path", _get_include_path(self)), evt_tag_error("error")); return FALSE; } return TRUE; } gboolean cfg_lexer_include_file(CfgLexer *self, const gchar *filename_) { struct stat st; gchar *filename; msg_debug("Processing @include statement", evt_tag_str("filename", filename_), evt_tag_str("include-path", _get_include_path(self))); filename = find_file_in_path(_get_include_path(self), filename_, G_FILE_TEST_EXISTS); if (!filename || stat(filename, &st) < 0) { if (filename) g_free(filename); return cfg_lexer_include_file_glob(self, filename_); } else { gboolean result; result = cfg_lexer_include_file_simple(self, filename); g_free(filename); return result; } } gboolean cfg_lexer_include_buffer_without_backtick_substitution(CfgLexer *self, const gchar *name, const gchar *buffer, gsize length) { CfgIncludeLevel *level; g_assert(length >= 0); level = cfg_lexer_alloc_include_level(self, name); if (!level) return FALSE; cfg_lexer_init_include_level_buffer(self, level, name, buffer, length); return cfg_lexer_start_next_include(self); } /* NOTE: if length is negative, it indicates zero-terminated buffer and * length should be determined based on that */ gboolean cfg_lexer_include_buffer(CfgLexer *self, const gchar *name, const gchar *buffer, gssize length) { gchar *substituted_buffer; gsize substituted_length = 0; GError *error = NULL; gboolean result = FALSE; substituted_buffer = cfg_lexer_subst_args_in_input(self->cfg ? self->cfg->globals : NULL, NULL, NULL, buffer, length, &substituted_length, &error); if (!substituted_buffer) { msg_error("Error resolving backtick references in block or buffer", evt_tag_str("buffer", name), evt_tag_str("error", error->message)); g_clear_error(&error); return FALSE; } result = cfg_lexer_include_buffer_without_backtick_substitution(self, name, substituted_buffer, substituted_length); g_free(substituted_buffer); return result; } void cfg_lexer_inject_token_block(CfgLexer *self, CfgTokenBlock *block) { self->token_blocks = g_list_append(self->token_blocks, block); } typedef struct _GeneratorPlugin { Plugin super; CfgBlockGenerator *gen; } GeneratorPlugin; static gpointer _generator_plugin_construct(Plugin *s) { GeneratorPlugin *self = (GeneratorPlugin *) s; return cfg_block_generator_ref(self->gen); } static void _generator_plugin_free(Plugin *s) { GeneratorPlugin *self = (GeneratorPlugin *) s; cfg_block_generator_unref(self->gen); g_free((gchar *) self->super.name); g_free(s); } void cfg_lexer_register_generator_plugin(PluginContext *context, CfgBlockGenerator *gen) { GeneratorPlugin *plugin = g_new0(GeneratorPlugin, 1); plugin->super.type = gen->context | LL_CONTEXT_FLAG_GENERATOR; plugin->super.name = g_strdup(gen->name); plugin->super.free_fn = _generator_plugin_free; plugin->super.construct = _generator_plugin_construct; plugin->super.parser = &block_ref_parser; plugin->gen = gen; plugin_register(context, &plugin->super, 1); } static gboolean _is_generator_plugin(Plugin *p) { return p->type & LL_CONTEXT_FLAG_GENERATOR; } static Plugin * cfg_lexer_find_generator_plugin(CfgLexer *self, GlobalConfig *cfg, gint context, const gchar *name) { Plugin *p; p = plugin_find(&cfg->plugin_context, context | LL_CONTEXT_FLAG_GENERATOR, name); if (!p || !_is_generator_plugin(p)) return NULL; return p; } static CFG_STYPE cfg_lexer_copy_token(const CFG_STYPE *original) { CFG_STYPE dest; int type = original->type; dest.type = type; if (type == LL_TOKEN) { dest.token = original->token; } else if (type == LL_IDENTIFIER || type == LL_STRING || type == LL_BLOCK) { dest.cptr = strdup(original->cptr); } else if (type == LL_NUMBER) { dest.num = original->num; } else if (type == LL_FLOAT) { dest.fnum = original->fnum; } return dest; } void cfg_lexer_unput_token(CfgLexer *self, CFG_STYPE *yylval) { CfgTokenBlock *block; block = cfg_token_block_new(); cfg_token_block_add_token(block, yylval); cfg_lexer_inject_token_block(self, block); } /* * NOTE: the caller is expected to manage the CFG_STYPE instance itself (as * this is the way it is defined by the lexer), this function only frees its * contents. */ void cfg_lexer_free_token(CFG_STYPE *token) { if (token->type == LL_STRING || token->type == LL_IDENTIFIER || token->type == LL_BLOCK) free(token->cptr); } static int _invoke__cfg_lexer_lex(CfgLexer *self, CFG_STYPE *yylval, CFG_LTYPE *yylloc) { if (setjmp(self->fatal_error)) { CFG_LTYPE *cur_lloc = &self->include_stack[self->include_depth].lloc; *yylloc = *cur_lloc; return LL_ERROR; } return _cfg_lexer_lex(yylval, yylloc, self->state); } static gboolean cfg_lexer_consume_next_injected_token(CfgLexer *self, gint *tok, CFG_STYPE *yylval, CFG_LTYPE *yylloc) { CfgTokenBlock *block; CFG_STYPE *token; while (self->token_blocks) { block = self->token_blocks->data; token = cfg_token_block_get_token(block); if (token) { *yylval = *token; *yylloc = self->include_stack[self->include_depth].lloc; if (token->type == LL_TOKEN) *tok = token->token; else *tok = token->type; return TRUE; } else { self->token_blocks = g_list_delete_link(self->token_blocks, self->token_blocks); cfg_token_block_free(block); } } return FALSE; } static gint cfg_lexer_lex_next_token(CfgLexer *self, CFG_STYPE *yylval, CFG_LTYPE *yylloc) { yylval->type = 0; g_string_truncate(self->token_text, 0); g_string_truncate(self->token_pretext, 0); gint tok = _invoke__cfg_lexer_lex(self, yylval, yylloc); if (yylval->type == 0) yylval->type = tok; return tok; } static void cfg_lexer_append_preprocessed_output(CfgLexer *self, const gchar *token_text) { if (self->preprocess_output) g_string_append_printf(self->preprocess_output, "%s", token_text); } static gboolean cfg_lexer_parse_and_run_block_generator(CfgLexer *self, Plugin *p, CFG_STYPE *yylval) { gpointer *args = NULL; CfgIncludeLevel *level = &self->include_stack[self->include_depth]; CfgBlockGenerator *gen = plugin_construct(p); gboolean success = TRUE; self->preprocess_suppress_tokens++; gint saved_line = level->lloc.first_line; gint saved_column = level->lloc.first_column; CfgParser *gen_parser = p->parser; if (gen_parser && !cfg_parser_parse(gen_parser, self, (gpointer *) &args, NULL)) { cfg_parser_cleanup(gen_parser, args); level->lloc.first_line = saved_line; level->lloc.first_column = saved_column; free(yylval->cptr); self->preprocess_suppress_tokens--; success = FALSE; goto exit; } GString *result = g_string_sized_new(256); gchar buf[256]; level->lloc.first_line = saved_line; level->lloc.first_column = saved_column; self->preprocess_suppress_tokens--; success = cfg_block_generator_generate(gen, self->cfg, args, result, cfg_lexer_format_location(self, &level->lloc, buf, sizeof(buf))); free(yylval->cptr); cfg_parser_cleanup(gen_parser, args); if (!success) { g_string_free(result, TRUE); success = FALSE; goto exit; } cfg_block_generator_format_name(gen, buf, sizeof(buf)); if (gen->suppress_backticks) success = cfg_lexer_include_buffer_without_backtick_substitution(self, buf, result->str, result->len); else success = cfg_lexer_include_buffer(self, buf, result->str, result->len); g_string_free(result, TRUE); exit: cfg_block_generator_unref(gen); return success; } static gboolean cfg_lexer_parse_pragma(CfgLexer *self) { gpointer dummy; CfgIncludeLevel *level = &self->include_stack[self->include_depth]; cfg_lexer_append_preprocessed_output(self, "@"); gint saved_line = level->lloc.first_line; gint saved_column = level->lloc.first_column; if (!cfg_parser_parse(&pragma_parser, self, &dummy, NULL)) { level->lloc.first_line = saved_line; level->lloc.first_column = saved_column; return FALSE; } return TRUE; } static CfgLexerPreprocessResult cfg_lexer_preprocess(CfgLexer *self, gint tok, CFG_STYPE *yylval, CFG_LTYPE *yylloc) { /* * NOTE: * * This code is deeply coupled with GlobalConfig and most of it does * not make sense to execute if self->cfg is NULL. Thus, some of the * conditionals contain an explicit self->cfg check, in other cases it is * implicitly checked by the first conditional of a series of if-then-else * statements. * */ Plugin *p; if (tok == LL_IDENTIFIER && self->cfg && (p = cfg_lexer_find_generator_plugin(self, self->cfg, cfg_lexer_get_context_type(self), yylval->cptr))) { if (!cfg_lexer_parse_and_run_block_generator(self, p, yylval)) return CLPR_ERROR; return CLPR_LEX_AGAIN; } if (self->ignore_pragma || self->cfg == NULL) { /* only process @pragma/@include tokens in case pragma allowed is set * and the associated configuration is not NULL */ ; } else if (tok == LL_PRAGMA) { if (!cfg_lexer_parse_pragma(self)) return CLPR_ERROR; return CLPR_LEX_AGAIN; } return CLPR_OK; } int cfg_lexer_lex(CfgLexer *self, CFG_STYPE *yylval, CFG_LTYPE *yylloc) { /* * NOTE: * * String tokens are allocated by malloc/free and not * g_malloc/g_free, this is significant. The grammar contains the free() * call, so getting rid of that would require a lot of changes to the * grammar. (on Windows glib, malloc/g_malloc are NOT equivalent) * */ gint tok; gboolean is_token_injected; CfgLexerPreprocessResult preprocess_result; do { is_token_injected = cfg_lexer_consume_next_injected_token(self, &tok, yylval, yylloc); if (!is_token_injected) { if (cfg_lexer_get_context_type(self) == LL_CONTEXT_BLOCK_CONTENT) cfg_lexer_start_block_state(self, "{}"); else if (cfg_lexer_get_context_type(self) == LL_CONTEXT_BLOCK_ARG) cfg_lexer_start_block_state(self, "()"); tok = cfg_lexer_lex_next_token(self, yylval, yylloc); cfg_lexer_append_preprocessed_output(self, self->token_pretext->str); } preprocess_result = cfg_lexer_preprocess(self, tok, yylval, yylloc); if (preprocess_result == CLPR_ERROR) return LL_ERROR; } while (preprocess_result == CLPR_LEX_AGAIN); if (!is_token_injected && self->preprocess_suppress_tokens == 0) cfg_lexer_append_preprocessed_output(self, self->token_text->str); return tok; } static void cfg_lexer_init(CfgLexer *self, GlobalConfig *cfg) { CfgIncludeLevel *level; _cfg_lexer_lex_init_extra(self, &self->state); self->string_buffer = g_string_sized_new(32); self->token_text = g_string_sized_new(32); self->token_pretext = g_string_sized_new(32); self->cfg = cfg; level = &self->include_stack[0]; level->lloc.first_line = level->lloc.last_line = 1; level->lloc.first_column = level->lloc.last_column = 1; } /* NOTE: cfg might be NULL in some call sites, but in those cases the lexer * should remain operational, obviously skipping cases where it would be * using the configuration instance. The lexer and the configuration stuff * should be one-way dependent, right now it is a circular dependency. */ CfgLexer * cfg_lexer_new(GlobalConfig *cfg, FILE *file, const gchar *filename, GString *preprocess_output) { CfgLexer *self; CfgIncludeLevel *level; self = g_new0(CfgLexer, 1); cfg_lexer_init(self, cfg); self->preprocess_output = preprocess_output; level = &self->include_stack[0]; cfg_lexer_init_include_level_file(self, level); cfg_lexer_include_level_file_add(self, level, filename); cfg_lexer_include_level_open_buffer(self, level); cfg_lexer_include_level_resume_from_buffer(self, level); return self; } CfgLexer * cfg_lexer_new_buffer(GlobalConfig *cfg, const gchar *buffer, gsize length) { CfgLexer *self; CfgIncludeLevel *level; self = g_new0(CfgLexer, 1); cfg_lexer_init(self, cfg); self->ignore_pragma = TRUE; level = &self->include_stack[0]; cfg_lexer_init_include_level_buffer(self, level, "", buffer, length); cfg_lexer_include_level_open_buffer(self, level); cfg_lexer_include_level_resume_from_buffer(self, level); return self; } void cfg_lexer_free(CfgLexer *self) { gint i; for (i = 0; i <= self->include_depth; i++) cfg_lexer_include_level_clear(self, &self->include_stack[i]); self->include_depth = 0; _cfg_lexer_lex_destroy(self->state); g_string_free(self->string_buffer, TRUE); if (self->token_text) g_string_free(self->token_text, TRUE); if (self->token_pretext) g_string_free(self->token_pretext, TRUE); while (self->context_stack) cfg_lexer_pop_context(self); g_list_foreach(self->token_blocks, (GFunc) cfg_token_block_free, NULL); g_list_free(self->token_blocks); g_free(self); } static const gchar *lexer_contexts[] = { [LL_CONTEXT_ROOT] = "root", [LL_CONTEXT_DESTINATION] = "destination", [LL_CONTEXT_SOURCE] = "source", [LL_CONTEXT_PARSER] = "parser", [LL_CONTEXT_REWRITE] = "rewrite", [LL_CONTEXT_FILTER] = "filter", [LL_CONTEXT_LOG] = "log", [LL_CONTEXT_BLOCK_DEF] = "block-def", [LL_CONTEXT_BLOCK_ARG] = "block-arg", [LL_CONTEXT_BLOCK_REF] = "block-ref", [LL_CONTEXT_BLOCK_CONTENT] = "block-content", [LL_CONTEXT_PRAGMA] = "pragma", [LL_CONTEXT_FORMAT] = "format", [LL_CONTEXT_TEMPLATE_FUNC] = "template-func", [LL_CONTEXT_INNER_DEST] = "inner-dest", [LL_CONTEXT_INNER_SRC] = "inner-src", [LL_CONTEXT_CLIENT_PROTO] = "client-proto", [LL_CONTEXT_SERVER_PROTO] = "server-proto", [LL_CONTEXT_OPTIONS] = "options", [LL_CONTEXT_CONFIG] = "config", }; gint cfg_lexer_lookup_context_type_by_name(const gchar *name) { gint i; for (i = 0; i < G_N_ELEMENTS(lexer_contexts); i++) { if (lexer_contexts[i] && strcmp(lexer_contexts[i], name) == 0) return i; } return 0; } const gchar * cfg_lexer_lookup_context_name_by_type(gint type) { type &= ~LL_CONTEXT_FLAGS; g_assert(type < G_N_ELEMENTS(lexer_contexts)); return lexer_contexts[type]; } /* token blocks */ void cfg_token_block_add_and_consume_token(CfgTokenBlock *self, CFG_STYPE *token) { g_assert(self->pos == 0); g_array_append_val(self->tokens, *token); } void cfg_token_block_add_token(CfgTokenBlock *self, CFG_STYPE *token) { CFG_STYPE copied_token = cfg_lexer_copy_token(token); cfg_token_block_add_and_consume_token(self, &copied_token); } CFG_STYPE * cfg_token_block_get_token(CfgTokenBlock *self) { if (self->pos < self->tokens->len) { CFG_STYPE *result; result = &g_array_index(self->tokens, CFG_STYPE, self->pos); self->pos++; return result; } return NULL; } CfgTokenBlock * cfg_token_block_new(void) { CfgTokenBlock *self = g_new0(CfgTokenBlock, 1); self->tokens = g_array_new(FALSE, TRUE, sizeof(CFG_STYPE)); return self; } void cfg_token_block_free(CfgTokenBlock *self) { if (self->pos < self->tokens->len) { for (gint i = self->pos; i < self->tokens->len; i++) { CFG_STYPE *token = &g_array_index(self->tokens, CFG_STYPE, i); cfg_lexer_free_token(token); } } g_array_free(self->tokens, TRUE); g_free(self); } GQuark cfg_lexer_error_quark(void) { return g_quark_from_static_string("cfg-lexer-error-quark"); } syslog-ng-syslog-ng-4.4.0/lib/cfg-lexer.h000066400000000000000000000201101450431004300201400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_LEXER_H_INCLUDED #define CFG_LEXER_H_INCLUDED 1 #include "syslog-ng.h" #include "cfg-args.h" #include "cfg-block-generator.h" #include "messages.h" #include #include /* this module provides a higher level encapsulation for the configuration * file lexer. */ #define MAX_INCLUDE_DEPTH 256 typedef struct _CfgIncludeLevel CfgIncludeLevel; typedef struct _CfgTokenBlock CfgTokenBlock; /* * YYLTYPE/YYSTYPE naming conventions * * We use multiple bison generated grammars (basically one for each plugin) * with a single lexer and the same location/symbol types. Earlier we could * easily just define YYLTYPE and YYSTYPE here and all generated grammars * and the lexer used it properly. With the advent of the `api.prefix' * option for the grammars (and the deprecation of the old `name-prefix' * behaviors), we needed to complicate things somewhat. * * We have three contexts where we need to use proper type names: * - in our own code where we might need to use location information (e.g. YYLTYPE) * - in the generated lexer, * - in the generated grammars * * Our own code * ============ * Because of the various #define/typedef games that generated code uses, I * decided that our own code should not use the names YYLTYPE/YYSTYPE * directly. In those cases we use CFG_LTYPE and CFG_STYPE to indicate that * these are types related to our configuration language. None of the * grammars use the "CFG_" prefix (and should not in the future either). * * The generated lexer * =================== * * The lexer get these types by us #define-ing YYLTYPE/YYSTYPE to * CFG_LTYPE/STYPE but only privately, e.g. these definitions should not be * published to the rest of the codebase. We do this by defining these in * implementation files and not in the headers. This is because some of the * code would try to #ifdef based on the existance of these macros. * * The generated grammars * ====================== * The grammars each have an api.location.type and api.value.type options in * their .y files, which use the names CFG_LTYPE and CFG_STYPE respectively. * The generated code uses YYLTYPE and YYSTYPE internally (defined as * macros), but because of the previous points this does not create a * conflict. */ /* the location type to carry location information from the lexer to the grammar */ typedef struct CFG_LTYPE { int first_line; int first_column; int last_line; int last_column; const gchar *name; } CFG_LTYPE; /* symbol type that carries token related information to the grammar */ typedef struct CFG_STYPE { /* one of LL_ types that indicates which field is being used */ int type; union { gint token; gint64 num; double fnum; char *cptr; void *ptr; gpointer node; }; } CFG_STYPE; #define KWS_NORMAL 0 #define KWS_OBSOLETE 1 /* used to describe a syslog-ng keyword */ typedef struct _CfgLexerKeyword { const gchar *kw_name; gint kw_token; gint kw_status; const gchar *kw_explain; } CfgLexerKeyword; #define CFG_KEYWORD_STOP "@!#?" /* structure that describes a given location in the include stack */ struct _CfgIncludeLevel { enum { CFGI_NONE, CFGI_FILE, CFGI_BUFFER, } include_type; union { struct { GSList *files; FILE *include_file; } file; struct { /* the lexer mutates content, so save it for error reporting */ gchar *original_content; /* buffer for the lexer */ gchar *content; gsize content_length; } buffer; }; /* this value indicates that @line was used which changed lloc relative to * an actual file */ gboolean lloc_changed_by_at_line; CFG_LTYPE lloc; struct yy_buffer_state *yybuf; }; /* Lexer class that encapsulates a flex generated lexer. This can be * instantiated multiple times in parallel, e.g. doesn't use any global * state as we're using the "reentrant" code by flex */ struct _CfgLexer { /* flex state, not using yyscan_t as it is not defined */ gpointer state; jmp_buf fatal_error; CfgIncludeLevel include_stack[MAX_INCLUDE_DEPTH]; GList *context_stack; gint include_depth; gchar block_boundary[2]; gint brace_count; gint tokenize_eol; GList *token_blocks; GString *string_buffer; GString *preprocess_output; gint preprocess_suppress_tokens; GString *token_pretext; GString *token_text; GlobalConfig *cfg; guint ignore_pragma:1; }; /* pattern buffer */ void cfg_lexer_unput_token(CfgLexer *self, CFG_STYPE *yylval); void cfg_lexer_start_block_state(CfgLexer *self, const gchar block_boundary[2]); void cfg_lexer_append_string(CfgLexer *self, int length, char *str); void cfg_lexer_append_char(CfgLexer *self, char c); /* keyword handling */ void cfg_lexer_set_current_keywords(CfgLexer *self, CfgLexerKeyword *keywords); char *cfg_lexer_get_keyword_string(CfgLexer *self, int kw); int cfg_lexer_map_word_to_token(CfgLexer *self, CFG_STYPE *yylval, const CFG_LTYPE *yylloc, const char *token); /* include files */ gboolean cfg_lexer_start_next_include(CfgLexer *self); gboolean cfg_lexer_include_file(CfgLexer *self, const gchar *filename); gboolean cfg_lexer_include_buffer(CfgLexer *self, const gchar *name, const gchar *buffer, gssize length); gboolean cfg_lexer_include_buffer_without_backtick_substitution(CfgLexer *self, const gchar *name, const gchar *buffer, gsize length); const gchar *cfg_lexer_format_location(CfgLexer *self, const CFG_LTYPE *yylloc, gchar *buf, gsize buf_len); void cfg_lexer_set_file_location(CfgLexer *self, const gchar *filename, gint line, gint column); EVTTAG *cfg_lexer_format_location_tag(CfgLexer *self, const CFG_LTYPE *yylloc); /* context tracking */ void cfg_lexer_push_context(CfgLexer *self, gint context, CfgLexerKeyword *keywords, const gchar *desc); void cfg_lexer_pop_context(CfgLexer *self); const gchar *cfg_lexer_get_context_description(CfgLexer *self); gint cfg_lexer_get_context_type(CfgLexer *self); /* token blocks */ void cfg_lexer_inject_token_block(CfgLexer *self, CfgTokenBlock *block); int cfg_lexer_lex(CfgLexer *self, CFG_STYPE *yylval, CFG_LTYPE *yylloc); void cfg_lexer_free_token(CFG_STYPE *token); CfgLexer *cfg_lexer_new(GlobalConfig *cfg, FILE *file, const gchar *filename, GString *preprocess_output); CfgLexer *cfg_lexer_new_buffer(GlobalConfig *cfg, const gchar *buffer, gsize length); void cfg_lexer_free(CfgLexer *self); gint cfg_lexer_lookup_context_type_by_name(const gchar *name); const gchar *cfg_lexer_lookup_context_name_by_type(gint id); /* token block objects */ void cfg_token_block_add_and_consume_token(CfgTokenBlock *self, CFG_STYPE *token); void cfg_token_block_add_token(CfgTokenBlock *self, CFG_STYPE *token); CFG_STYPE *cfg_token_block_get_token(CfgTokenBlock *self); CfgTokenBlock *cfg_token_block_new(void); void cfg_token_block_free(CfgTokenBlock *self); void cfg_lexer_register_generator_plugin(PluginContext *context, CfgBlockGenerator *gen); #define CFG_LEXER_ERROR cfg_lexer_error_quark() GQuark cfg_lexer_error_quark(void); enum CfgLexerError { CFG_LEXER_MISSING_BACKTICK_PAIR, CFG_LEXER_CANNOT_REPRESENT_APOSTROPHES_IN_QSTRINGS, CFG_LEXER_BACKTICKS_CANT_BE_SUBSTITUTED_AFTER_BACKSLASH, }; #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-monitor.c000066400000000000000000000140251450431004300205130ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-monitor.h" #include "messages.h" #include "resolved-configurable-paths.h" #include "timeutils/misc.h" #include #if SYSLOG_NG_HAVE_INOTIFY #include #endif #define CFG_MONITOR_POLL_FREQ (15 * 60) typedef struct _CfgMonitorCallbackListItem { CfgMonitorEventCB cb; gpointer cb_data; } CfgMonitorCallbackListItem; struct _CfgMonitor { GList *callbacks; struct iv_timer poll_timer; time_t last_mtime; #if SYSLOG_NG_HAVE_INOTIFY gboolean in_started; const gchar *cfgfile_basename; struct iv_inotify inotify; struct iv_inotify_watch in_watch; #endif }; void cfg_monitor_add_watch(CfgMonitor *self, CfgMonitorEventCB cb, gpointer cb_data) { if (!cb) return; CfgMonitorCallbackListItem *item = g_new(CfgMonitorCallbackListItem, 1); item->cb = cb; item->cb_data = cb_data; self->callbacks = g_list_prepend(self->callbacks, item); } static gint _compare_callback(gconstpointer a, gconstpointer b) { const CfgMonitorCallbackListItem *item_a = (const CfgMonitorCallbackListItem *) a; const CfgMonitorCallbackListItem *item_b = (const CfgMonitorCallbackListItem *) b; gboolean equal = item_a->cb == item_b->cb && item_a->cb_data == item_b->cb_data; return equal ? 0 : -1; } void cfg_monitor_remove_watch(CfgMonitor *self, CfgMonitorEventCB cb, gpointer cb_data) { CfgMonitorCallbackListItem item = { cb, cb_data }; GList *i = g_list_find_custom(self->callbacks, &item, _compare_callback); if (!i) return; CfgMonitorCallbackListItem *removed_item = i->data; self->callbacks = g_list_delete_link(self->callbacks, i); g_free(removed_item); } static void _run_callbacks(CfgMonitor *self, const CfgMonitorEvent *event) { for (GList *i = self->callbacks; i; i = i->next) { CfgMonitorCallbackListItem *item = i->data; item->cb(event, item->cb_data); } } static void _run_callbacks_if_main_config_was_modified(CfgMonitor *self) { const gchar *main_cfg_file = resolved_configurable_paths.cfgfilename; struct stat st = {0}; stat(main_cfg_file, &st); if (self->last_mtime >= st.st_mtime) return; CfgMonitorEvent event = { .name = main_cfg_file, .event = MODIFIED, .st = st, }; _run_callbacks(self, &event); self->last_mtime = st.st_mtime; } static void _poll_start(CfgMonitor *self) { if (iv_timer_registered(&self->poll_timer)) return; iv_validate_now(); self->poll_timer.expires = iv_now; timespec_add_msec(&self->poll_timer.expires, CFG_MONITOR_POLL_FREQ * 1000); iv_timer_register(&self->poll_timer); } static void _poll_stop(CfgMonitor *self) { if (iv_timer_registered(&self->poll_timer)) iv_timer_unregister(&self->poll_timer); } static void _poll_timer_tick(gpointer c) { CfgMonitor *self = (CfgMonitor *) c; _run_callbacks_if_main_config_was_modified(self); _poll_start(self); } #if SYSLOG_NG_HAVE_INOTIFY static void _inotify_event_handler(void *c, struct inotify_event *event) { CfgMonitor *self = (CfgMonitor *) c; if (g_strcmp0(self->cfgfile_basename, event->name) == 0) _run_callbacks_if_main_config_was_modified(self); } /* moving/recreating the config directory itself is not implemented */ static gboolean _inotify_start(CfgMonitor *self) { if (self->in_started) return FALSE; IV_INOTIFY_INIT(&self->inotify); if (iv_inotify_register(&self->inotify) != 0) { msg_warning("Error creating configuration monitor instance, can not register inotify", evt_tag_error("errno")); return FALSE; } gchar *config_dir = g_path_get_dirname(resolved_configurable_paths.cfgfilename); IV_INOTIFY_WATCH_INIT(&self->in_watch); self->in_watch.inotify = &self->inotify; self->in_watch.pathname = config_dir; self->in_watch.mask = IN_CREATE | IN_MOVED_TO | IN_CLOSE_WRITE; self->in_watch.handler = _inotify_event_handler; self->in_watch.cookie = self; if (iv_inotify_watch_register(&self->in_watch) != 0) { iv_inotify_unregister(&self->inotify); g_free(config_dir); msg_warning("Error start configuration monitor, can not register inotify watch", evt_tag_error("errno")); return FALSE; } g_free(config_dir); self->cfgfile_basename = g_path_get_basename(resolved_configurable_paths.cfgfilename); self->in_started = TRUE; return TRUE; } static void _inotify_stop(CfgMonitor *self) { if (!self->in_started) return; iv_inotify_watch_unregister(&self->in_watch); iv_inotify_unregister(&self->inotify); g_free((gchar *) self->cfgfile_basename); self->in_started = FALSE; } #else #define _inotify_start(self) (FALSE) #define _inotify_stop(self) #endif void cfg_monitor_start(CfgMonitor *self) { if (!_inotify_start(self)) _poll_start(self); _run_callbacks_if_main_config_was_modified(self); } void cfg_monitor_stop(CfgMonitor *self) { _inotify_stop(self); _poll_stop(self); } void cfg_monitor_free(CfgMonitor *self) { g_list_free_full(self->callbacks, g_free); g_free(self); } CfgMonitor * cfg_monitor_new(void) { CfgMonitor *self = g_new0(CfgMonitor, 1); IV_TIMER_INIT(&self->poll_timer); self->poll_timer.handler = _poll_timer_tick; self->poll_timer.cookie = self; return self; } syslog-ng-syslog-ng-4.4.0/lib/cfg-monitor.h000066400000000000000000000031561450431004300205230ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_MONITOR_H #define CFG_MONITOR_H #include "syslog-ng.h" #include typedef struct _CfgMonitor CfgMonitor; typedef struct _CfgMonitorEvent { const gchar *name; struct stat st; enum { MODIFIED } event; } CfgMonitorEvent; typedef void (*CfgMonitorEventCB)(const CfgMonitorEvent *event, gpointer c); CfgMonitor *cfg_monitor_new(void); void cfg_monitor_free(CfgMonitor *self); void cfg_monitor_add_watch(CfgMonitor *self, CfgMonitorEventCB cb, gpointer cb_data); void cfg_monitor_remove_watch(CfgMonitor *self, CfgMonitorEventCB cb, gpointer cb_data); void cfg_monitor_start(CfgMonitor *self); void cfg_monitor_stop(CfgMonitor *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-parser.c000066400000000000000000000424441450431004300203260ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "cfg-grammar.h" #include #include extern int main_debug; /* defined in the parser */ int main_parse(CfgLexer *lexer, gpointer *dummy, gpointer arg); /* * PLEASE: if at all possible avoid adding keywords here, as these * keywords might collide with user-defined identifiers (e.g. source, * destination & block names). * * Add the keyword & the token to the parser of the module in question * instead, even if there are multiple modules using the same * keywords. * * Tokens (e.g. KW_xxx) associated with core keywords (e.g. those * listed here) should be declared only once and only in cfg-grammar.y * and NOT in external modules. */ static CfgLexerKeyword main_keywords[] = { /* statements */ { "source", KW_SOURCE }, { "filter", KW_FILTER }, { "parser", KW_PARSER }, { "rewrite", KW_REWRITE }, { "destination", KW_DESTINATION }, { "log", KW_LOG }, { "junction", KW_JUNCTION }, { "channel", KW_CHANNEL }, { "options", KW_OPTIONS }, { "include", KW_INCLUDE, }, { "block", KW_BLOCK }, { "if", KW_IF }, { "else", KW_ELSE }, { "elif", KW_ELIF }, /* source or destination items */ { "internal", KW_INTERNAL }, /* value pairs */ { "value_pairs", KW_VALUE_PAIRS }, { "exclude", KW_EXCLUDE }, { "pair", KW_PAIR }, { "key", KW_KEY }, { "scope", KW_SCOPE }, { "rekey", KW_REKEY }, { "shift", KW_SHIFT }, { "shift_levels", KW_SHIFT_LEVELS }, { "add_prefix", KW_ADD_PREFIX }, { "replace", KW_REPLACE_PREFIX, KWS_OBSOLETE, "replace_prefix" }, { "replace_prefix", KW_REPLACE_PREFIX }, { "cast", KW_CAST }, { "upper", KW_UPPER }, { "lower", KW_LOWER }, { "include_bytes", KW_INCLUDE_BYTES }, /* option items */ { "flags", KW_FLAGS }, { "pad_size", KW_PAD_SIZE }, { "truncate_size", KW_TRUNCATE_SIZE }, { "mark_freq", KW_MARK_FREQ }, { "mark", KW_MARK_FREQ, KWS_OBSOLETE, "mark_freq" }, { "mark_mode", KW_MARK_MODE }, { "stats_freq", KW_STATS_FREQ, KWS_OBSOLETE, "Use the stats() block. E.g. stats(freq(1));" }, { "stats_lifetime", KW_STATS_LIFETIME, KWS_OBSOLETE, "Use the stats() block. E.g. stats(lifetime(10));" }, { "stats_level", KW_STATS_LEVEL, KWS_OBSOLETE, "Use the stats() block. E.g. stats(level(1));" }, { "stats", KW_STATS }, { "stats_max_dynamics", KW_STATS_MAX_DYNAMIC, KWS_OBSOLETE, "Use the stats() block. E.g. stats(max-dynamics(10000));" }, { "freq", KW_FREQ }, { "level", KW_LEVEL }, { "lifetime", KW_LIFETIME }, { "max_dynamics", KW_MAX_DYNAMIC }, { "syslog_stats", KW_SYSLOG_STATS }, { "healthcheck_freq", KW_HEALTHCHECK_FREQ}, { "min_iw_size_per_reader", KW_MIN_IW_SIZE_PER_READER }, { "flush_lines", KW_FLUSH_LINES }, { "flush_timeout", KW_FLUSH_TIMEOUT, KWS_OBSOLETE, "Some drivers support batch-timeout() instead that you can specify at the destination level." }, { "suppress", KW_SUPPRESS }, { "sync_freq", KW_FLUSH_LINES, KWS_OBSOLETE, "flush_lines" }, { "sync", KW_FLUSH_LINES, KWS_OBSOLETE, "flush_lines" }, { "long_hostnames", KW_CHAIN_HOSTNAMES, KWS_OBSOLETE, "chain_hostnames" }, { "chain_hostnames", KW_CHAIN_HOSTNAMES }, { "normalize_hostnames", KW_NORMALIZE_HOSTNAMES }, { "keep_hostname", KW_KEEP_HOSTNAME }, { "check_hostname", KW_CHECK_HOSTNAME }, { "bad_hostname", KW_BAD_HOSTNAME }, { "custom_domain", KW_CUSTOM_DOMAIN }, { "keep_timestamp", KW_KEEP_TIMESTAMP }, { "encoding", KW_ENCODING }, { "ts_format", KW_TS_FORMAT }, { "frac_digits", KW_FRAC_DIGITS }, { "time_zone", KW_TIME_ZONE }, { "recv_time_zone", KW_RECV_TIME_ZONE }, { "send_time_zone", KW_SEND_TIME_ZONE }, { "local_time_zone", KW_LOCAL_TIME_ZONE }, { "format", KW_FORMAT }, { "use_time_recvd", KW_USE_TIME_RECVD, KWS_OBSOLETE, "Use R_ or S_ prefixed macros in templates or keep_timestamp(no)" }, { "use_fqdn", KW_USE_FQDN }, { "use_dns", KW_USE_DNS }, { "time_reopen", KW_TIME_REOPEN }, { "time_reap", KW_TIME_REAP }, { "time_sleep", KW_TIME_SLEEP, KWS_OBSOLETE, "time_sleep() has been deprecated" }, { "file_template", KW_FILE_TEMPLATE }, { "proto_template", KW_PROTO_TEMPLATE }, { "default_level", KW_DEFAULT_SEVERITY }, { "default_priority", KW_DEFAULT_SEVERITY }, { "default_severity", KW_DEFAULT_SEVERITY }, { "default_facility", KW_DEFAULT_FACILITY }, { "sdata_prefix", KW_SDATA_PREFIX }, { "threaded", KW_THREADED }, { "use_rcptid", KW_USE_RCPTID, KWS_OBSOLETE, "This has been deprecated, try use_uniqid() instead" }, { "use_uniqid", KW_USE_UNIQID }, { "log_level", KW_LOG_LEVEL }, { "log_fifo_size", KW_LOG_FIFO_SIZE }, { "log_fetch_limit", KW_LOG_FETCH_LIMIT }, { "log_iw_size", KW_LOG_IW_SIZE }, { "log_msg_size", KW_LOG_MSG_SIZE }, { "trim_large_messages", KW_TRIM_LARGE_MESSAGES }, { "log_prefix", KW_LOG_PREFIX, KWS_OBSOLETE, "program_override" }, { "program_override", KW_PROGRAM_OVERRIDE }, { "host_override", KW_HOST_OVERRIDE }, { "throttle", KW_THROTTLE }, { "create_dirs", KW_CREATE_DIRS }, { "optional", KW_OPTIONAL }, { "owner", KW_OWNER }, { "group", KW_GROUP }, { "perm", KW_PERM }, { "dir_owner", KW_DIR_OWNER }, { "dir_group", KW_DIR_GROUP }, { "dir_perm", KW_DIR_PERM }, { "template", KW_TEMPLATE }, { "template_escape", KW_TEMPLATE_ESCAPE }, { "template_function", KW_TEMPLATE_FUNCTION }, { "on_error", KW_ON_ERROR }, { "persist_only", KW_PERSIST_ONLY }, { "dns_cache_hosts", KW_DNS_CACHE_HOSTS }, { "dns_cache", KW_DNS_CACHE }, { "dns_cache_size", KW_DNS_CACHE_SIZE }, { "dns_cache_expire", KW_DNS_CACHE_EXPIRE }, { "dns_cache_expire_failed", KW_DNS_CACHE_EXPIRE_FAILED }, { "pass_unix_credentials", KW_PASS_UNIX_CREDENTIALS, KWS_OBSOLETE, "The use of pass-unix-credentials() has been deprecated in " VERSION_3_35 " in favour of " "the 'so-passcred()' source option or the 'ignore-aux-data' source flag" }, { "persist_name", KW_PERSIST_NAME, VERSION_VALUE_3_8 }, { "retries", KW_RETRIES }, { "workers", KW_WORKERS }, { "worker_partition_key", KW_WORKER_PARTITION_KEY }, { "batch_lines", KW_BATCH_LINES }, { "batch_timeout", KW_BATCH_TIMEOUT }, { "read_old_records", KW_READ_OLD_RECORDS}, { "use_syslogng_pid", KW_USE_SYSLOGNG_PID }, { "fetch_no_data_delay", KW_FETCH_NO_DATA_DELAY}, /* multi-line */ { "multi_line_mode", KW_MULTI_LINE_MODE }, { "multi_line_prefix", KW_MULTI_LINE_PREFIX }, { "multi_line_garbage", KW_MULTI_LINE_GARBAGE }, { "multi_line_suffix", KW_MULTI_LINE_GARBAGE }, { "parallelize", KW_PARALLELIZE }, { "partitions", KW_PARTITIONS }, { "partition_key", KW_PARTITION_KEY }, /* filter items */ { "type", KW_TYPE }, { "tags", KW_TAGS }, /* on/off switches */ { "yes", KW_YES }, { "on", KW_YES }, { "no", KW_NO }, { "off", KW_NO }, { "auto", KW_AUTO }, /* rewrite rules */ { "condition", KW_CONDITION }, { "value", KW_VALUE }, { NULL, 0 } }; CfgParser main_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &main_debug, #endif .name = "config", .context = LL_CONTEXT_ROOT, .keywords = main_keywords, .parse = main_parse, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(main_, MAIN_, gpointer *) /* display CONTEXT lines before and after the offending line */ #define CONTEXT 5 static void _format_source_prefix(gchar *line_prefix, gsize line_prefix_len, gint lineno, gboolean error_location) { g_snprintf(line_prefix, line_prefix_len, "%d", lineno); if (error_location) { for (gint i = strlen(line_prefix); i < 6; i++) g_strlcat(line_prefix, "-", line_prefix_len); g_strlcat(line_prefix, ">", line_prefix_len); } } static void _print_underline(const gchar *line, gint whitespace_before, gint number_of_carets) { for (gint i = 0; line[i] && i < whitespace_before; i++) { fprintf(stderr, "%c", line[i] == '\t' ? '\t' : ' '); } /* NOTE: sometimes the yylloc has zero characters, print a caret even in * this case, that's why i == 0 is there */ for (gint i = 0; i == 0 || i < number_of_carets; i++) fprintf(stderr, "^"); fprintf(stderr, "\n"); } static void _print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gint error_index) { gint line_ndx; gchar line_prefix[12]; gint error_length = yylloc->last_line - yylloc->first_line + 1; for (line_ndx = 0; lines[line_ndx]; line_ndx++) { gint lineno = yylloc->first_line + line_ndx - error_index; const gchar *line = lines[line_ndx]; gint line_len = strlen(line); gboolean line_ends_with_newline = line_len > 0 && line[line_len - 1] == '\n'; _format_source_prefix(line_prefix, sizeof(line_prefix), lineno, line_ndx >= error_index && line_ndx < error_index + error_length); fprintf(stderr, "%-8s%s%s", line_prefix, line, line_ends_with_newline ? "" : "\n"); if (line_ndx == error_index) { /* print the underline right below the source line we just printed */ fprintf(stderr, "%-8s", line_prefix); gboolean multi_line = yylloc->first_line != yylloc->last_line; _print_underline(line, yylloc->first_column - 1, multi_line ? strlen(&line[yylloc->first_column]) + 1 : yylloc->last_column - yylloc->first_column); } else if (line_ndx >= error_index + CONTEXT) break; } } static void _report_file_location(const gchar *filename, const CFG_LTYPE *yylloc) { FILE *f; gint lineno = 0; gsize buflen = 65520; gchar *buf = g_malloc(buflen); GPtrArray *context = g_ptr_array_new(); gint error_index = 0; f = fopen(filename, "r"); if (f) { while (fgets(buf, buflen, f)) { lineno++; if (lineno > (gint) yylloc->first_line + CONTEXT) break; else if (lineno < (gint) yylloc->first_line - CONTEXT) continue; else if (lineno == yylloc->first_line) error_index = context->len; g_ptr_array_add(context, g_strdup(buf)); } /* NOTE: do we have the appropriate number of lines? */ if (lineno <= yylloc->first_line) goto exit; g_ptr_array_add(context, NULL); fclose(f); } if (context->len > 0) _print_underlined_source_block(yylloc, (gchar **) context->pdata, error_index); exit: g_free(buf); g_ptr_array_foreach(context, (GFunc) g_free, NULL); g_ptr_array_free(context, TRUE); } static void _report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *yylloc) { gchar **lines = g_strsplit(buffer_content, "\n", yylloc->first_line + CONTEXT + 1); gint num_lines = g_strv_length(lines); if (num_lines <= yylloc->first_line) goto exit; gint start = yylloc->first_line - 1 - CONTEXT; gint error_index = CONTEXT; if (start < 0) { error_index += start; start = 0; } _print_underlined_source_block(yylloc, &lines[start], error_index); exit: g_strfreev(lines); } void report_syntax_error(CfgLexer *lexer, const CFG_LTYPE *yylloc, const char *what, const char *msg, gboolean in_main_grammar) { CfgIncludeLevel *level = &lexer->include_stack[lexer->include_depth], *from; for (from = level; from >= lexer->include_stack; from--) { const CFG_LTYPE *from_lloc; if (from == level) { /* the location on the initial level is the one we get as * argument, instead of what we have in the lexer's state. This * is because the lexer might be one token in advance (because of * LALR) and the grammar is kind enough to pass us the original * location. */ from_lloc = yylloc; fprintf(stderr, "Error parsing %s, %s in %s:%d:%d-%d:%d:\n", what, msg, from_lloc->name, from_lloc->first_line, from_lloc->first_column, from_lloc->last_line, from_lloc->last_column); } else { from_lloc = &from->lloc; fprintf(stderr, "Included from %s:%d:%d-%d:%d:\n", from_lloc->name, from_lloc->first_line, from_lloc->first_column, from_lloc->last_line, from_lloc->last_column); } if (from->include_type == CFGI_FILE) { _report_file_location(from_lloc->name, from_lloc); } else if (from->include_type == CFGI_BUFFER) { if (from->lloc_changed_by_at_line) _report_file_location(from_lloc->name, from_lloc); else _report_buffer_location(from->buffer.original_content, from_lloc); } fprintf(stderr, "\n"); } if (in_main_grammar) fprintf(stderr, "\nsyslog-ng documentation: %s\n" "contact: %s\n", PRODUCT_DOCUMENTATION, PRODUCT_CONTACT); } /* the debug flag for the main parser will be used for all parsers */ extern int cfg_parser_debug; gboolean cfg_parser_parse(CfgParser *self, CfgLexer *lexer, gpointer *instance, gpointer arg) { enum { OK, ERROR, MEMORY_EXHAUSTED } parse_result; gboolean success; if (cfg_parser_debug) { fprintf(stderr, "\n\nStarting parser %s\n", self->name); } if (self->debug_flag) (*self->debug_flag) = cfg_parser_debug; cfg_lexer_push_context(lexer, self->context, self->keywords, self->name); parse_result = self->parse(lexer, instance, arg); success = (parse_result == OK); cfg_lexer_pop_context(lexer); if (cfg_parser_debug) { fprintf(stderr, "\nStopping parser %s, result: %d\n", self->name, parse_result); } if (parse_result == MEMORY_EXHAUSTED) { fprintf(stderr, "\nToo many tokens found during parsing, consider increasing YYMAXDEPTH in lib/cfg-grammar.y and recompiling.\n"); } return success; } void cfg_parser_cleanup(CfgParser *self, gpointer instance) { if (instance && self->cleanup) self->cleanup(instance); } /* * This function can be used to parse flags in a flags(...) option. It * makes it quite easy to write a flags parser by specifying the * operations to be performed in a getopt-like array. */ gboolean cfg_process_flag(CfgFlagHandler *handlers, gpointer base, const gchar *flag_) { gint h; gchar flag[32]; for (h = 0; flag_[h] && h < sizeof(flag); h++) { if (flag_[h] == '_') flag[h] = '-'; else flag[h] = flag_[h]; } flag[h] = 0; for (h = 0; handlers[h].name; h++) { CfgFlagHandler *handler = &handlers[h]; if (strcmp(handlers[h].name, flag) == 0) { guint32 *field = ((guint32 *) (((gchar *) base) + handler->ofs)); switch (handler->op) { case CFH_SET: /* this works if handler->mask is unset and handler->param is a single bit only */ if (handler->mask) *field = ((*field) & ~handler->mask) | handler->param; else *field = (*field) | handler->param; return TRUE; case CFH_CLEAR: /* set the bitfield to zero */ if (handler->mask) *field = (*field) & ~handler->mask; else *field = (*field) & ~handler->param; return TRUE; default: g_assert_not_reached(); break; } } } return FALSE; } gboolean cfg_process_yesno(const gchar *yesno) { if (strcasecmp(yesno, "yes") == 0 || atoi(yesno) > 0) return TRUE; return FALSE; } syslog-ng-syslog-ng-4.4.0/lib/cfg-parser.h000066400000000000000000000105441450431004300203270ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_PARSER_H_INCLUDED #define CFG_PARSER_H_INCLUDED #include "syslog-ng.h" #include "cfg-lexer.h" /* high level interface to a configuration file parser, it encapsulates the * grammar/lexer pair. */ typedef struct _CfgParser { /* how to enable bison debug in the parser */ gint *debug_flag; gint context; const gchar *name; /* parser specific keywords to be pushed to the lexer */ CfgLexerKeyword *keywords; /* the parser entry point, returns the parsed object in *instance */ gint (*parse)(CfgLexer *lexer, gpointer *instance, gpointer arg); /* in case of parse failure and instance != NULL, this should free instance */ void (*cleanup)(gpointer instance); } CfgParser; gboolean cfg_parser_parse(CfgParser *self, CfgLexer *lexer, gpointer *instance, gpointer arg); void cfg_parser_cleanup(CfgParser *self, gpointer instance); enum { CFH_SET, CFH_CLEAR, }; typedef struct _CfgFlagHandler { const gchar *name; gint op; gint ofs; guint32 param; guint32 mask; } CfgFlagHandler; typedef enum _CfgYesNoAuto { CYNA_AUTO = -1, CYNA_NO = 0, CYNA_YES = 1, } CfgYesNoAuto; gboolean cfg_process_flag(CfgFlagHandler *handlers, gpointer base, const gchar *flag); gboolean cfg_process_yesno(const gchar *yesno); extern CfgParser main_parser; #define CFG_PARSER_DECLARE_LEXER_BINDING(parser_prefix, PARSER_PREFIX, root_type) \ int \ parser_prefix ## lex(CFG_STYPE *yylval, CFG_LTYPE *yylloc, CfgLexer *lexer); \ \ void \ parser_prefix ## error(const CFG_LTYPE *yylloc, CfgLexer *lexer, root_type instance, gpointer arg, const char *msg); #define CFG_PARSER_IMPLEMENT_LEXER_BINDING(parser_prefix, PARSER_PREFIX, root_type) \ int \ parser_prefix ## lex(CFG_STYPE *yylval, CFG_LTYPE *yylloc, CfgLexer *lexer) \ { \ int token; \ \ token = cfg_lexer_lex(lexer, yylval, yylloc); \ return token; \ } \ \ void \ parser_prefix ## error(const CFG_LTYPE *yylloc, CfgLexer *lexer, root_type instance, gpointer arg, const char *msg) \ { \ gboolean in_main_grammar = __builtin_strcmp( # parser_prefix, "main_") == 0; \ report_syntax_error(lexer, yylloc, cfg_lexer_get_context_description(lexer), msg, \ in_main_grammar); \ } void report_syntax_error(CfgLexer *lexer, const CFG_LTYPE *yylloc, const char *what, const char *msg, gboolean in_main_grammar); CFG_PARSER_DECLARE_LEXER_BINDING(main_, MAIN_, gpointer *) #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-path.c000066400000000000000000000024711450431004300177620ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Mehul Prajapati * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-path.h" void cfg_path_track_file(GlobalConfig *cfg, const gchar *file_path, const gchar *path_type) { CfgFilePath *cfg_file_path = g_new0(CfgFilePath, 1); cfg_file_path->path_type = g_strdup(path_type); cfg_file_path->file_path = g_strdup(file_path); cfg->file_list = g_list_append(cfg->file_list, cfg_file_path); } syslog-ng-syslog-ng-4.4.0/lib/cfg-path.h000066400000000000000000000023531450431004300177660ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Mehul Prajapati * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_PATH_H_INCLUDED #define CFG_PATH_H_INCLUDED #include "cfg.h" typedef struct _CfgFilePath { gchar *path_type; gchar *file_path; } CfgFilePath; void cfg_path_track_file(GlobalConfig *cfg, const gchar *file_path, const gchar *path_type); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-persist.c000066400000000000000000000051641450431004300205210ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-persist.h" #include "messages.h" typedef struct _PersistConfigEntry { gpointer value; GDestroyNotify destroy; } PersistConfigEntry; static void persist_config_entry_free(PersistConfigEntry *self) { if (self->destroy) { self->destroy(self->value); } g_free(self); } void persist_config_add(PersistConfig *self, const gchar *name, gpointer value, GDestroyNotify destroy) { PersistConfigEntry *p; if (g_hash_table_lookup(self->keys, name)) { msg_error("Internal error, duplicate configuration elements refer to the same persistent config", evt_tag_str("name", name)); if (destroy) destroy(value); return; } p = g_new0(PersistConfigEntry, 1); p->value = value; p->destroy = destroy; g_hash_table_insert(self->keys, g_strdup(name), p); return; } gpointer persist_config_fetch(PersistConfig *self, const gchar *name) { gpointer res = NULL; gchar *orig_key; PersistConfigEntry *p; gpointer tmp1, tmp2; if (g_hash_table_lookup_extended(self->keys, name, &tmp1, &tmp2)) { orig_key = (gchar *) tmp1; p = (PersistConfigEntry *) tmp2; res = p->value; g_hash_table_steal(self->keys, name); g_free(orig_key); g_free(p); } return res; } PersistConfig * persist_config_new(void) { PersistConfig *self = g_new0(PersistConfig, 1); self->keys = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) persist_config_entry_free); return self; } void persist_config_free(PersistConfig *self) { g_hash_table_destroy(self->keys); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/cfg-persist.h000066400000000000000000000026711450431004300205260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2023 Axoflow * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_PERSIST_H_INCLUDED #define CFG_PERSIST_H_INCLUDED 1 #include "syslog-ng.h" typedef struct _PersistConfig { GHashTable *keys; } PersistConfig; void persist_config_add(PersistConfig *self, const gchar *name, gpointer value, GDestroyNotify destroy); gpointer persist_config_fetch(PersistConfig *cfg, const gchar *name); PersistConfig *persist_config_new(void); void persist_config_free(PersistConfig *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-tree.c000066400000000000000000001405471450431004300177740ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-tree.h" #include "logmpx.h" #include "logpipe.h" #include "metrics-pipe.h" #include static void _log_expr_node_free(LogExprNode *self); LogExprNode * log_expr_node_ref(LogExprNode *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } LogExprNode * log_expr_node_unref(LogExprNode *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) { _log_expr_node_free(self); return NULL; } return self; } /* * Return the textual representation of a node content type. */ const gchar * log_expr_node_get_content_name(gint content) { switch (content) { case ENC_PIPE: return "log"; case ENC_SOURCE: return "source"; case ENC_FILTER: return "filter"; case ENC_PARSER: return "parser"; case ENC_REWRITE: return "rewrite"; case ENC_DESTINATION: return "destination"; default: g_assert_not_reached(); break; } } /* * Return the textual representation of a node layout. */ const gchar * log_expr_node_get_layout_name(gint layout) { switch (layout) { case ENL_SINGLE: return "single"; case ENL_REFERENCE: return "reference"; case ENL_SEQUENCE: return "sequence"; case ENL_JUNCTION: return "junction"; case ENL_CONDITIONAL: return "conditional"; default: g_assert_not_reached(); break; } } /* return the top-most rule that matches content. This is used to * query the enclosing rule for a given LogExprNode. It is looking up * the top-most node, so that we use the name of the enclosing block * that the user specified. In-line defined, and thus anonymous * expressions are automatically named. In that case this function * will return a node matching @content but without an actual name. */ LogExprNode * log_expr_node_get_container_rule(LogExprNode *self, gint content) { LogExprNode *node, *result = NULL; node = self->parent; while (node) { if (node->content == content) { result = node; } node = node->parent; } return result; } /** * log_expr_node_append: * @a: first LogExprNode * @b: second LogExprNode * * This function appends @b to @a in a linked list using the ep_next field * in LogExprNode. **/ void log_expr_node_append(LogExprNode *a, LogExprNode *b) { a->next = b; } LogExprNode * log_expr_node_append_tail(LogExprNode *a, LogExprNode *b) { if (a) { LogExprNode *p = a; while (p->next) p = p->next; log_expr_node_append(p, b); return a; } return b; } /* * Format the location information for a LogExprNode. For nodes that * have no location information, the parent is considered, this way * always returning something close to the location that defined the * node. */ const gchar * log_expr_node_format_location(LogExprNode *self, gchar *buf, gsize buf_len) { LogExprNode *node = self; while (node) { if (node->line || node->column) { g_snprintf(buf, buf_len, "%s:%d:%d", self->filename ? : "#buffer", node->line, node->column); break; } node = node->parent; } if (!node) g_strlcpy(buf, "#unknown", buf_len); return buf; } EVTTAG * log_expr_node_location_tag(LogExprNode *self) { gchar buf[128]; return evt_tag_str("location", log_expr_node_format_location(self, buf, sizeof(buf))); } /* * Set the list of children of a LogExprNode. It automatically updates * the children's "parent" pointers so that the tree can be traversed * upwards too. */ void log_expr_node_set_children(LogExprNode *self, LogExprNode *children) { LogExprNode *ep; /* we don't currently support setting the children list multiple * times. no inherent reason, just the proper free function would * need to be written, until then this assert would reveal the case * quite fast. */ g_assert(self->children == NULL); for (ep = children; ep; ep = ep->next) ep->parent = self; self->children = children; } /* * Set the object associated with a node. The "object" member is used * to store the LogPipe instance associated with ENL_SINGLE/ENC_PIPE * nodes. */ void log_expr_node_set_object(LogExprNode *self, gpointer object, GDestroyNotify destroy) { self->object = object; self->object_destroy = destroy; } /* * The aux object is the secondary object associated with a node, it * is mostly unused, except for nodes storing source and destination * statements, in which case this contains a reference to the last * item of the compiled sequence (for sources) or the first item of * the compiled sequence (destinations). * * This mechanism is used to avoid having to clone source/destination * pipes, which operation they don't support. */ void log_expr_node_set_aux(LogExprNode *self, gpointer aux, GDestroyNotify destroy) { self->aux = aux; self->aux_destroy = destroy; } void log_expr_node_set_name(LogExprNode *self, const gchar *name) { g_free(self->name); self->name = g_strdup(name); } /** * log_expr_node_new: * @layout: layout of the children (ENL_*) * @content: what kind of expression this node stores (ENC_*) * @name: name of this rule (optional) * @children: child nodes * @flags: a combination of LC_* flags as specified by the administrator * @yylloc: the lexer location in the configuration file. * * This function constructs a LogExprNode object which encapsulates a * log expression in the configuration. See the note in cfg-tree.h for * more information about LogExprNode objects and log expressions. **/ LogExprNode * log_expr_node_new(gint layout, gint content, const gchar *name, LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc) { LogExprNode *self = g_new0(LogExprNode, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->layout = layout; self->content = content; self->name = g_strdup(name); log_expr_node_set_children(self, children); self->flags = flags; if (yylloc) { self->filename = g_strdup(yylloc->name); self->line = yylloc->first_line; self->column = yylloc->first_column; } return self; } /** * log_expr_node_free: * @self: LogExprNode instance * * This function frees the LogExprNode object encapsulating a log * expression node pointed to by @self. **/ static void _log_expr_node_free(LogExprNode *self) { LogExprNode *next, *p; for (p = self->children ; p; p = next) { next = p->next; log_expr_node_unref(p); } if (self->object && self->object_destroy) self->object_destroy(self->object); if (self->aux && self->aux_destroy) self->aux_destroy(self->aux); g_free(self->name); g_free(self->filename); g_free(self); } LogExprNode * log_expr_node_new_pipe(LogPipe *pipe, CFG_LTYPE *yylloc) { LogExprNode *node = log_expr_node_new(ENL_SINGLE, ENC_PIPE, NULL, NULL, 0, yylloc); log_expr_node_set_object(node, pipe, (GDestroyNotify) log_pipe_unref); return node; } LogExprNode * log_expr_node_new_source(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_SOURCE, name, children, 0, yylloc); } LogExprNode * log_expr_node_new_source_reference(const gchar *name, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_REFERENCE, ENC_SOURCE, name, NULL, 0, yylloc); } LogExprNode * log_expr_node_new_destination(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_DESTINATION, name, children, 0, yylloc); } LogExprNode * log_expr_node_new_destination_reference(const gchar *name, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_REFERENCE, ENC_DESTINATION, name, NULL, 0, yylloc); } LogExprNode * log_expr_node_new_filter(const gchar *name, LogExprNode *child, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_FILTER, name, child, 0, yylloc); } LogExprNode * log_expr_node_new_filter_reference(const gchar *name, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_REFERENCE, ENC_FILTER, name, NULL, 0, yylloc); } LogExprNode * log_expr_node_new_parser(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_PARSER, name, children, 0, yylloc); } LogExprNode * log_expr_node_new_parser_reference(const gchar *name, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_REFERENCE, ENC_PARSER, name, NULL, 0, yylloc); } LogExprNode * log_expr_node_new_rewrite(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_REWRITE, name, children, 0, yylloc); } LogExprNode * log_expr_node_new_rewrite_reference(const gchar *name, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_REFERENCE, ENC_REWRITE, name, NULL, 0, yylloc); } LogExprNode * log_expr_node_new_log(LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_PIPE, NULL, children, flags, yylloc); } LogExprNode * log_expr_node_new_sequence(LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_SEQUENCE, ENC_PIPE, NULL, children, 0, yylloc); } LogExprNode * log_expr_node_new_junction(LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_JUNCTION, ENC_PIPE, NULL, children, 0, yylloc); } LogExprNode * log_expr_node_new_source_junction(LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_JUNCTION, ENC_SOURCE, NULL, children, 0, yylloc); } LogExprNode * log_expr_node_new_destination_junction(LogExprNode *children, CFG_LTYPE *yylloc) { return log_expr_node_new(ENL_JUNCTION, ENC_DESTINATION, NULL, children, 0, yylloc); } LogExprNode * log_expr_node_new_conditional(LogExprNode *filter_expr, LogExprNode *true_expr, LogExprNode *false_expr, CFG_LTYPE *yylloc) { LogExprNode *children = true_expr; log_expr_node_append(true_expr, false_expr); log_expr_node_append(false_expr, filter_expr); return log_expr_node_new(ENL_CONDITIONAL, ENC_PIPE, NULL, children, 0, yylloc); } /**************************************************************************** * Functions related to conditional nodes * * These are higher-level functions that map if-elif-else structure to * LogExprNode instances. Rather than using a higher level data struct * which then generates LogExprNode instances, we represent/manipulate the * if-elif-else structure right within LogExprNode. * * A conditional node is simply a junction with two children: * * 1) the first child is the "TRUE" branch, with the filter expression * attached and the final flag * * 2) the second child is the "FALSE" branch, possibly empty, but also * the final flag. * * Basically this is the equivalent to: * * junction { * channel { * filter { EXPRESSION; }; * flags(final); * }; * channel { * flags(final); * }; * }; * * When parsing an if block, we generate both children immediately, with the * empty 2nd channel, and then if an elif or else comes, the FALSE branch * gets replaced. * * The series of if-elif-else sequences is represented by its first * LogExprNode (e.g. the first if). When we need to add an else or elif, * we would have to locate the last dangling if statement based on this * first LogExprNode. The alternative would have been to store the last if * statement in a variable, however that becomes pretty complicated if we * need to handle nesting. * ****************************************************************************/ static LogExprNode * log_expr_node_conditional_get_true_branch(LogExprNode *node) { g_assert(node->layout == ENL_CONDITIONAL); LogExprNode *branches = node->children; g_assert(branches != NULL); g_assert(branches->next != NULL); /* first child */ return branches; } static LogExprNode * log_expr_node_conditional_get_false_branch(LogExprNode *node) { g_assert(node->layout == ENL_CONDITIONAL); LogExprNode *branches = node->children; g_assert(branches != NULL); g_assert(branches->next != NULL); /* second child */ return branches->next; } static gboolean log_expr_node_conditional_is_branch_empty(LogExprNode *node) { return node->children == NULL; } /* this function locates the last dangling if, based on the very first if * statement in a series of ifs at the same level */ static LogExprNode * _locate_last_conditional_along_nested_else_blocks(LogExprNode *head) { while (1) { g_assert(log_expr_node_conditional_get_true_branch(head) != NULL); g_assert(log_expr_node_conditional_get_false_branch(head) != NULL); LogExprNode *false_branch = log_expr_node_conditional_get_false_branch(head); /* check if this is the last else */ if (log_expr_node_conditional_is_branch_empty(false_branch)) return head; head = false_branch->children; } g_assert_not_reached(); } /* change the FALSE branch (e.g. the else case) of the last dangling if, specified by the head element */ void log_expr_node_conditional_set_false_branch_of_the_last_if(LogExprNode *conditional_head_node, LogExprNode *false_expr) { LogExprNode *conditional_node = _locate_last_conditional_along_nested_else_blocks(conditional_head_node); LogExprNode *branches = conditional_node->children; /* a conditional branch always have three children (see the constructor * below), the first one is the "true" branch and the second one is the * "false" branch, as they are constructed as final log channels with * filter statement in the first one as the "if" expression. */ /* assert that we only have two children */ g_assert(branches != NULL); g_assert(branches->next != NULL); LogExprNode *true_expr = branches; LogExprNode *old_false_expr = branches->next; LogExprNode *filter_expr = branches->next->next; /* construct the new false branch */ LogExprNode *new_false_expr = log_expr_node_new_log( false_expr, LC_FINAL, NULL ); /* unlink and free the old one */ g_assert(!filter_expr || filter_expr->parent == conditional_node); new_false_expr->parent = conditional_node; log_expr_node_append(true_expr, new_false_expr); log_expr_node_append(new_false_expr, filter_expr); log_expr_node_unref(old_false_expr); } /* */ LogExprNode * log_expr_node_new_simple_conditional(LogExprNode *filter_expr, LogExprNode *true_expr, CFG_LTYPE *yylloc) { /* * channel { * true_expr; * flags(final); * }; */ true_expr->flags |= LC_FINAL; /* * channel { * flags(final); * }; * * NOTE: the false branch may be modified later, once an else or elif is * encountered in the configuration, see * log_expr_node_conditional_set_false_branch_of_the_last_if() function * above. */ LogExprNode *false_expr = log_expr_node_new_log( NULL, LC_FINAL, NULL ); return log_expr_node_new_conditional(log_expr_node_new_filter(NULL, filter_expr, yylloc), true_expr, false_expr, yylloc); } LogExprNode * log_expr_node_new_compound_conditional(LogExprNode *block, CFG_LTYPE *yylloc) { /* * channel { * filtering_and_parsing_expr; * flags(final); * }; */ LogExprNode *true_expr = block; true_expr->flags |= LC_FINAL; /* * channel { * flags(final); * }; * * NOTE: the false branch may be modified later, once an else or elif is * encountered in the configuration, see * log_expr_node_conditional_set_false_branch_of_the_last_if() function * above. */ LogExprNode *false_expr = log_expr_node_new_log( NULL, LC_FINAL, NULL ); return log_expr_node_new_conditional(NULL, true_expr, false_expr, yylloc); } /****************************************************************************/ gint log_expr_node_lookup_flag(const gchar *flag) { if (strcmp(flag, "catch-all") == 0 || strcmp(flag, "catchall") == 0) return LC_CATCHALL; else if (strcmp(flag, "fallback") == 0) return LC_FALLBACK; else if (strcmp(flag, "final") == 0) return LC_FINAL; else if (strcmp(flag, "flow-control") == 0) return LC_FLOW_CONTROL; else if (strcmp(flag, "drop-unmatched") == 0) { msg_warning_once("WARNING: The drop-unmatched flag has been removed starting with " VERSION_4_1 ". " "Setting it has no effect on the log path"); return 0; } msg_error("Unknown log statement flag", evt_tag_str("flag", flag)); return 0; } static LogPipe * cfg_tree_assoc_pipe(CfgTree *self, LogExprNode *node, LogPipe *pipe, const gchar *info) { pipe->expr_node = node; g_ptr_array_add(self->initialized_pipes, pipe); log_pipe_add_info(pipe, info); return pipe; } static LogPipe * cfg_tree_new_pipe(CfgTree *self, LogExprNode *related_expr, const gchar *info) { return cfg_tree_assoc_pipe(self, related_expr, log_pipe_new(self->cfg), info); } static LogMultiplexer * cfg_tree_new_mpx(CfgTree *self, LogExprNode *related_expr, const gchar *info) { return (LogMultiplexer *) cfg_tree_assoc_pipe(self, related_expr, &log_multiplexer_new(self->cfg)->super, info); } MetricsPipe * cfg_tree_new_metrics_pipe(CfgTree *self, LogExprNode *related_expr) { return (MetricsPipe *) cfg_tree_assoc_pipe(self, related_expr, &metrics_pipe_new(self->cfg, related_expr->name)->super, "metrics-pipe"); } static gchar * _format_anon_rule_name(CfgTree *self, gint content) { return g_strdup_printf("#anon-%s%d", log_expr_node_get_content_name(content), self->anon_counters[content]++); } /* * Return the name of the rule that contains a LogExprNode. Generates * one automatically for anonymous log expressions. * * NOTE: this returns an allocated string, the caller must free that. */ gchar * cfg_tree_get_rule_name(CfgTree *self, gint content, LogExprNode *node) { gchar *rule_name; if (node) { LogExprNode *rule = log_expr_node_get_container_rule(node, content); if (!rule->name) rule->name = _format_anon_rule_name(self, content); rule_name = g_strdup(rule->name); } else { rule_name = _format_anon_rule_name(self, content); } return rule_name; } /* * Return a unique the name associated with a LogExprNode. It is of * the format #. * * NOTE: this returns an allocated string, the caller must free that. */ gchar * cfg_tree_get_child_id(CfgTree *self, gint content, LogExprNode *node) { gchar *rule_name = cfg_tree_get_rule_name(self, content, node); gint cur_child_id; gchar *res; if (node) { LogExprNode *rule = log_expr_node_get_container_rule(node, content); cur_child_id = rule->child_id++; } else cur_child_id = 0; res = g_strdup_printf("%s#%d", rule_name, cur_child_id); g_free(rule_name); return res; } /* hash foreach function to add all source objects to catch-all rules */ static void cfg_tree_add_all_sources(gpointer key, gpointer value, gpointer user_data) { gpointer *args = (gpointer *) user_data; LogExprNode *referring_rule = args[1]; LogExprNode *rule = (LogExprNode *) value; if (rule->content != ENC_SOURCE) return; /* prepend a source reference */ referring_rule->children = log_expr_node_append_tail(log_expr_node_new_source_reference(rule->name, NULL), referring_rule->children); } static gboolean cfg_tree_compile_node(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail); static gboolean cfg_tree_compile_single(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { LogPipe *pipe; g_assert(node->content == ENC_PIPE); /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */ g_assert(node->flags == 0); pipe = node->object; if ((pipe->flags & PIF_INLINED) == 0) { /* first reference to the pipe uses the same instance, further ones will get cloned */ pipe->flags |= PIF_INLINED; /* The pipe object is borrowed, so the reference counter must be increased. */ log_pipe_ref(pipe); } else { /* ok, we are using this pipe again, it needs to be cloned */ pipe = log_pipe_clone(pipe); if (!pipe) { msg_error("Error cloning pipe into its reference point, probably the element in question is not meant to be used in this situation", log_expr_node_location_tag(node)); goto error; } pipe->flags |= PIF_INLINED; } g_ptr_array_add(self->initialized_pipes, pipe); pipe->expr_node = node; if ((pipe->flags & PIF_SOURCE) == 0) *outer_pipe_head = pipe; *outer_pipe_tail = pipe; return TRUE; error: return FALSE; } static gboolean cfg_tree_compile_reference(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { LogExprNode *referenced_node; /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */ g_assert(node->flags == 0); if (!node->object) { referenced_node = cfg_tree_get_object(self, node->content, node->name); } else referenced_node = node->object; if (!referenced_node) { msg_error("Error resolving reference", evt_tag_str("content", log_expr_node_get_content_name(node->content)), evt_tag_str("name", node->name), log_expr_node_location_tag(node)); goto error; } switch (referenced_node->content) { case ENC_SOURCE: { LogMultiplexer *mpx; LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL; LogPipe *attach_pipe = NULL; if (!referenced_node->aux) { if (!cfg_tree_compile_node(self, referenced_node, &sub_pipe_head, &sub_pipe_tail)) goto error; log_expr_node_set_aux(referenced_node, log_pipe_ref(sub_pipe_tail), (GDestroyNotify) log_pipe_unref); } else { sub_pipe_tail = referenced_node->aux; } attach_pipe = cfg_tree_new_pipe(self, node, "source-attach"); if (sub_pipe_tail) { /* when the source is empty, we'll get a NULL tail in * sub_pipe_tail. We handle that by simply not connecting * anything to the attachment point */ if (!sub_pipe_tail->pipe_next) { mpx = cfg_tree_new_mpx(self, referenced_node, "mpx(source)"); log_pipe_append(sub_pipe_tail, &mpx->super); } else { mpx = (LogMultiplexer *) sub_pipe_tail->pipe_next; } log_multiplexer_add_next_hop(mpx, attach_pipe); } *outer_pipe_head = NULL; *outer_pipe_tail = attach_pipe; break; } case ENC_DESTINATION: { LogMultiplexer *mpx; LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL; if (!referenced_node->aux) { if (!cfg_tree_compile_node(self, referenced_node, &sub_pipe_head, &sub_pipe_tail)) goto error; log_expr_node_set_aux(referenced_node, log_pipe_ref(sub_pipe_head), (GDestroyNotify) log_pipe_unref); } else { sub_pipe_head = referenced_node->aux; } /* We need a new LogMultiplexer instance for two reasons: 1) we need to link something into the sequence, all reference based destination invocations need a separate LogPipe 2) we have to fork downwards to the destination, it may change the message but we need the original one towards our next chain */ mpx = cfg_tree_new_mpx(self, node, "mpx(destination-reference)"); log_multiplexer_disable_delivery_propagation(mpx); if (sub_pipe_head) { /* when the destination is empty */ log_multiplexer_add_next_hop(mpx, sub_pipe_head); } *outer_pipe_head = &mpx->super; *outer_pipe_tail = NULL; break; } default: return cfg_tree_compile_node(self, referenced_node, outer_pipe_head, outer_pipe_tail); } return TRUE; error: return FALSE; } static void cfg_tree_propagate_expr_node_properties_to_pipe(LogExprNode *node, LogPipe *pipe) { if (node->flags & LC_FALLBACK) pipe->flags |= PIF_BRANCH_FALLBACK; if (node->flags & LC_FINAL) pipe->flags |= PIF_BRANCH_FINAL; if (node->flags & LC_FLOW_CONTROL) pipe->flags |= PIF_HARD_FLOW_CONTROL; if (!pipe->expr_node) pipe->expr_node = node; } static gboolean _is_log_path_name_unique(CfgTree *self, const LogExprNode *node) { if (g_hash_table_contains(self->log_path_names, node->name)) return FALSE; g_hash_table_insert(self->log_path_names, g_strdup(node->name), NULL); return TRUE; } /** * cfg_tree_compile_sequence: * * Construct the sequential part of LogPipe pipeline as specified by * the user. The sequential part is where no branches exist, pipes are * merely linked to each other. This is in contrast with a "junction" * where the processing is forked into different branches. Junctions * are built using cfg_tree_compile_junction() above. * * The configuration is parsed into a series of LogExprNode * elements, each giving a reference to a source, filter, parser, * rewrite and destination. This function connects these so that their * log_pipe_queue() method will dispatch the message correctly (which * in turn boils down to setting the LogPipe->next member). * * The tree like structure is created using LogMultiplexer instances, * pipes are connected back with a simple LogPipe instance that only * forwards messages. * * The next member pointer is not holding a reference, but can be * assumed to be kept alive as long as the configuration is running. * * Parameters: * @self: the CfgTree instance * @rule: the series of LogExprNode instances encapsulates as a LogExprNode * @outer_pipe_tail: the last LogPipe to be used to chain further elements to this sequence * @cfg: GlobalConfig instance * @toplevel: whether this rule is a top-level one. **/ static gboolean cfg_tree_compile_sequence(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { LogExprNode *ep; LogPipe *first_pipe, /* the head of the constructed pipeline */ *last_pipe; /* the current tail of the constructed pipeline */ LogPipe *source_join_pipe = NULL; gboolean node_properties_propagated = FALSE; if ((node->flags & LC_CATCHALL) != 0) { /* the catch-all resolution code clears this flag */ msg_error("Error in configuration, catch-all flag can only be specified for top-level log statements"); goto error; } if (node->content == ENC_PIPE && node->name && !_is_log_path_name_unique(self, node)) { msg_error("Error in configuration, duplicate log path definition", evt_tag_str("log_path_name", node->name), log_expr_node_location_tag(node)); goto error; } /* the loop below creates a sequence of LogPipe instances which * essentially execute the user configuration once it is * started. * * The input of this is a log expression, denoted by a tree of * LogExprNode structures, built by the parser. We are storing the * sequence as a linked list, pipes are linked with their "next" * field. * * The head of this list is pointed to by @first_pipe, the current * end is known as @last_pipe. * * In case the sequence starts with a source LogPipe (PIF_SOURCE * flag), the head of the list is _not_ tracked, in that case * first_pipe is NULL. * */ first_pipe = last_pipe = NULL; for (ep = node->children; ep; ep = ep->next) { LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL; if (!cfg_tree_compile_node(self, ep, &sub_pipe_head, &sub_pipe_tail)) goto error; /* add pipe to the current pipe_line, e.g. after last_pipe, update last_pipe & first_pipe */ if (sub_pipe_head) { if (!node_properties_propagated) { cfg_tree_propagate_expr_node_properties_to_pipe(node, sub_pipe_head); node_properties_propagated = TRUE; } if (!first_pipe && !last_pipe) { /* we only remember the first pipe in case we're not in * source mode. In source mode, only last_pipe is set */ first_pipe = sub_pipe_head; } if (last_pipe) { g_assert(last_pipe->pipe_next == NULL); log_pipe_append(last_pipe, sub_pipe_head); } if (sub_pipe_tail) { last_pipe = sub_pipe_tail; } else { last_pipe = sub_pipe_head; /* look for the final pipe */ while (last_pipe->pipe_next) { last_pipe = last_pipe->pipe_next; } } sub_pipe_head = NULL; } else if (sub_pipe_tail) { /* source pipe */ if (first_pipe) { msg_error("Error compiling sequence, source-pipe follows a non-source one, please list source references/definitions first", log_expr_node_location_tag(ep)); goto error; } if (!source_join_pipe) { if (node->content == ENC_PIPE && node->name) { MetricsPipe *metrics_pipe = cfg_tree_new_metrics_pipe(self, node); source_join_pipe = last_pipe = &metrics_pipe->super; } else { source_join_pipe = last_pipe = cfg_tree_new_pipe(self, node, "source-join"); } } log_pipe_append(sub_pipe_tail, source_join_pipe); } } if (node->content == ENC_PIPE && node->name && first_pipe) { MetricsPipe *metrics_pipe = cfg_tree_new_metrics_pipe(self, node); log_pipe_append(&metrics_pipe->super, first_pipe); first_pipe = &metrics_pipe->super; } if (!first_pipe && !last_pipe) { /* this is an empty sequence, insert a do-nothing LogPipe */ first_pipe = last_pipe = cfg_tree_new_pipe(self, node, "noop"); } /* NOTE: if flow control is enabled, then we either need to have an * embedded log statement (in which case first_pipe is set, as we're not * starting with sources), OR we created a source_join_pipe already. * */ g_assert(((node->flags & LC_FLOW_CONTROL) && (first_pipe || source_join_pipe)) || !(node->flags & LC_FLOW_CONTROL)); if (!node_properties_propagated) { /* we never encountered anything that would produce a head_pipe, e.g. * this sequence only contains a source and nothing else. In that * case, apply node flags to the last pipe. It should be picked up * when LogMultiplexer iterates over the branch in * log_multiplexer_init() as long as last_pipe is linked into the * pipe_next list and is not forked off at a LogMultiplexer. * */ cfg_tree_propagate_expr_node_properties_to_pipe(node, last_pipe); node_properties_propagated = TRUE; } if (node->content == ENC_DESTINATION) { /* We want to leave pipe-next available to use for destinations. Config graph uses pipe-next to pass messages forward in a sequence layout. But pipe-next might be overridden (for example network destination with LogWriter) hence disjointing the config graph. This patch links destinations in T form, instead of single link. * (endpoint of sequence) | V * (multiplexer) -(next-hop)-> destination -(pipe-next*)-> logwriter | (pipe-next) | V * (rest of the sequence) That way destinations are free to use the pipe-next* */ last_pipe = first_pipe; } *outer_pipe_tail = last_pipe; *outer_pipe_head = first_pipe; return TRUE; error: /* we don't need to free anything, everything we allocated is recorded in * @self, thus will be freed whenever cfg_tree_free is called */ return FALSE; } /** * cfg_tree_compile_junction(): * * This function builds a junction within the configuration. A * junction is where processing is forked into several branches, each * doing its own business, and then the end of each branch is * collected at the end so that further processing can be done on the * combined output of each log branch. * * /-- branch --\ * / \ * ---+---- branch ----+--- * \ / * \-- branch --/ **/ static gboolean cfg_tree_compile_junction(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { LogExprNode *ep; LogPipe *join_pipe = NULL; /* the pipe where parallel branches are joined in a junction */ LogMultiplexer *fork_mpx = NULL; /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */ g_assert(node->flags == 0); for (ep = node->children; ep; ep = ep->next) { LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL; gboolean is_first_branch = (ep == node->children); if (!cfg_tree_compile_node(self, ep, &sub_pipe_head, &sub_pipe_tail)) goto error; if (sub_pipe_head) { /* ep is an intermediate LogPipe or a destination, we have to fork */ if (!is_first_branch && !fork_mpx) { msg_error("Error compiling junction, source and non-source branches are mixed", log_expr_node_location_tag(ep)); goto error; } if (!fork_mpx) { fork_mpx = cfg_tree_new_mpx(self, node, node->content == ENC_DESTINATION ? "mpx(destination-junction)" : (node->content == ENC_SOURCE ? "mpx(source-junction)" : "mpx(junction)")); if (node->content == ENC_DESTINATION) log_multiplexer_disable_delivery_propagation(fork_mpx); *outer_pipe_head = &fork_mpx->super; } log_multiplexer_add_next_hop(fork_mpx, sub_pipe_head); } else { /* ep is a "source" LogPipe (cause no sub_pipe_head returned by compile_node). */ if (fork_mpx) { msg_error("Error compiling junction, source and non-source branches are mixed", log_expr_node_location_tag(ep)); goto error; } } if (sub_pipe_tail && outer_pipe_tail) { if (!join_pipe) { join_pipe = cfg_tree_new_pipe(self, node, "junction-end"); } log_pipe_append(sub_pipe_tail, join_pipe); } } if (fork_mpx) { /* Groups of source drivers are enclosed into junctions, so that we * can attach to their tail end and do additional processing on the * emitted messages. * * In the case of sources, messages do not enter the junction in the * front, through the multiplexer, rather these messages originate from * one of the source drivers. * * In this scenario, the junction does not have a multiplexer in front * (hence fork_mpx == NULL) and this also means that we don't have to * close the loop. * * This conditional is only executed for non-source junctions, in * which case we do have a fork_mpx and we need to set * PIF_JUNCTION_END on the tail of the junction. */ g_assert(node->content != ENC_SOURCE); join_pipe->flags |= PIF_JUNCTION_END; } if (outer_pipe_tail) *outer_pipe_tail = join_pipe; return TRUE; error: /* we don't need to free anything, everything we allocated is recorded in * @self, thus will be freed whenever cfg_tree_free is called */ return FALSE; } /** * cfg_tree_compile_conditional(): **/ static gboolean cfg_tree_compile_conditional(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { LogPipe *join_pipe = NULL; /* the pipe where parallel branches are joined in a junction */ LogPipe *midpoint_pipe = NULL; LogMultiplexer *fork_mpx = NULL; /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */ g_assert(node->flags == 0); LogExprNode *true_branch = node->children; LogExprNode *false_branch = node->children->next; LogExprNode *filter_expr = node->children->next->next; LogPipe *true_pipe_head, *true_pipe_tail; if (!cfg_tree_compile_node(self, true_branch, &true_pipe_head, &true_pipe_tail)) goto error; LogPipe *false_pipe_head, *false_pipe_tail; if (!cfg_tree_compile_node(self, false_branch, &false_pipe_head, &false_pipe_tail)) goto error; fork_mpx = cfg_tree_new_mpx(self, node, "mpx(conditional)"); join_pipe = cfg_tree_new_pipe(self, node, "conditional-end"); join_pipe->flags |= PIF_JUNCTION_END; if (filter_expr) { LogPipe *filter_pipe_head, *filter_pipe_tail; if (!cfg_tree_compile_node(self, filter_expr, &filter_pipe_head, &filter_pipe_tail)) goto error; midpoint_pipe = cfg_tree_new_pipe(self, node, "conditional-midpoint"); midpoint_pipe->flags |= PIF_CONDITIONAL_MIDPOINT; log_pipe_append(filter_pipe_tail, midpoint_pipe); log_pipe_append(midpoint_pipe, true_pipe_head); true_pipe_head = filter_pipe_head; } log_multiplexer_add_next_hop(fork_mpx, true_pipe_head); log_multiplexer_add_next_hop(fork_mpx, false_pipe_head); log_pipe_append(true_pipe_tail, join_pipe); log_pipe_append(false_pipe_tail, join_pipe); if (outer_pipe_head) *outer_pipe_head = &fork_mpx->super; if (outer_pipe_tail) *outer_pipe_tail = join_pipe; return TRUE; error: /* we don't need to free anything, everything we allocated is recorded in * @self, thus will be freed whenever cfg_tree_free is called */ return FALSE; } /* * cfg_tree_compile_node: * * This function takes care of compiling a LogExprNode. * */ gboolean cfg_tree_compile_node(CfgTree *self, LogExprNode *node, LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail) { gboolean result = FALSE; static gint indent = -1; gchar buf[128]; indent++; msg_trace_printf("%-*sCompiling %s %s [%s] at [%s]", indent * 2, "", node->name ? : "#unnamed", log_expr_node_get_layout_name(node->layout), log_expr_node_get_content_name(node->content), log_expr_node_format_location(node, buf, sizeof(buf))); switch (node->layout) { case ENL_SINGLE: result = cfg_tree_compile_single(self, node, outer_pipe_head, outer_pipe_tail); break; case ENL_REFERENCE: result = cfg_tree_compile_reference(self, node, outer_pipe_head, outer_pipe_tail); break; case ENL_SEQUENCE: result = cfg_tree_compile_sequence(self, node, outer_pipe_head, outer_pipe_tail); break; case ENL_JUNCTION: result = cfg_tree_compile_junction(self, node, outer_pipe_head, outer_pipe_tail); break; case ENL_CONDITIONAL: result = cfg_tree_compile_conditional(self, node, outer_pipe_head, outer_pipe_tail); break; default: g_assert_not_reached(); } indent--; return result; } gboolean cfg_tree_compile_rule(CfgTree *self, LogExprNode *rule) { LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL; return cfg_tree_compile_node(self, rule, &sub_pipe_head, &sub_pipe_tail); } static gboolean cfg_tree_objects_equal(gconstpointer v1, gconstpointer v2) { LogExprNode *r1 = (LogExprNode *) v1; LogExprNode *r2 = (LogExprNode *) v2; if (r1->content != r2->content) return FALSE; /* we assume that only rules with a name are hashed */ return strcmp(r1->name, r2->name) == 0; } static guint cfg_tree_objects_hash(gconstpointer v) { LogExprNode *r = (LogExprNode *) v; /* we assume that only rules with a name are hashed */ return r->content + g_str_hash(r->name); } gboolean cfg_tree_add_object(CfgTree *self, LogExprNode *rule) { gboolean res = TRUE; if (rule->name && rule->content != ENC_PIPE) { /* only named rules can be stored as objects to be referenced later */ /* check if already present */ res = (g_hash_table_lookup(self->objects, rule) == NULL); /* key is the same as the object */ g_hash_table_replace(self->objects, rule, rule); } else { /* unnamed rules are simply put in the rules array */ g_ptr_array_add(self->rules, rule); } return res; } LogExprNode * cfg_tree_get_object(CfgTree *self, gint content, const gchar *name) { LogExprNode lookup_node; memset(&lookup_node, 0, sizeof(lookup_node)); lookup_node.content = content; lookup_node.name = (gchar *) name; return g_hash_table_lookup(self->objects, &lookup_node); } GList * cfg_tree_get_objects(CfgTree *self) { return g_hash_table_get_values(self->objects); } gboolean cfg_tree_add_template(CfgTree *self, LogTemplate *template_obj) { gboolean res = (g_hash_table_lookup(self->templates, template_obj->name) == NULL); g_hash_table_replace(self->templates, template_obj->name, template_obj); return res; } LogTemplate * cfg_tree_lookup_template(CfgTree *self, const gchar *name) { if (name) return log_template_ref(g_hash_table_lookup(self->templates, name)); return NULL; } LogTemplate * cfg_tree_check_inline_template(CfgTree *self, const gchar *template_or_name, GError **error) { LogTemplate *template = cfg_tree_lookup_template(self, template_or_name); if (template == NULL) { template = log_template_new(self->cfg, NULL); if (!log_template_compile(template, template_or_name, error)) { log_template_unref(template); return NULL; } template->def_inline = TRUE; } return template; } gboolean cfg_tree_compile(CfgTree *self) { gint i; /* resolve references within the configuration */ if (self->compiled) return TRUE; for (i = 0; i < self->rules->len; i++) { LogExprNode *rule = (LogExprNode *) g_ptr_array_index(self->rules, i); if ((rule->flags & LC_CATCHALL)) { gpointer args[] = { self, rule }; g_hash_table_foreach(self->objects, cfg_tree_add_all_sources, args); rule->flags &= ~LC_CATCHALL; } if (!cfg_tree_compile_rule(self, rule)) { return FALSE; } } self->compiled = TRUE; return TRUE; } static gboolean _verify_unique_persist_names_among_pipes(const GPtrArray *initialized_pipes) { GHashTable *pipe_persist_names = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); gboolean result = TRUE; for (gint i = 0; i < initialized_pipes->len; ++i) { LogPipe *current_pipe = g_ptr_array_index(initialized_pipes, i); const gchar *current_pipe_name = g_strdup(log_pipe_get_persist_name(current_pipe)); if (current_pipe_name != NULL) { LogPipe *other_pipe = g_hash_table_lookup(pipe_persist_names, current_pipe_name); if (other_pipe) { msg_error("Automatic assignment of persist names failed, as " "conflicting persist-names were found. Please override " "the automatically assigned identifier using an " "explicit perist-name() option or remove the duplicated " "configuration elements", evt_tag_str("persist_name", current_pipe_name), log_pipe_location_tag(current_pipe), log_pipe_location_tag(other_pipe)); result = FALSE; } else { g_hash_table_replace(pipe_persist_names, (gpointer) current_pipe_name, current_pipe); } } } g_hash_table_destroy(pipe_persist_names); return result; } gboolean cfg_tree_start(CfgTree *self) { gint i; g_assert(self->compiled); /* * As there are pipes that are dynamically created during init, these * pipes must be deinited before destroying the configuration, otherwise * circular references will inhibit the free of the configuration * structure. */ for (i = 0; i < self->initialized_pipes->len; i++) { LogPipe *pipe = g_ptr_array_index(self->initialized_pipes, i); if (!log_pipe_init(pipe)) { msg_error("Error initializing message pipeline", evt_tag_str("plugin_name", pipe->plugin_name ? pipe->plugin_name : "not a plugin"), log_pipe_location_tag(pipe)); return FALSE; } } return _verify_unique_persist_names_among_pipes(self->initialized_pipes); } gboolean cfg_tree_stop(CfgTree *self) { gboolean success = TRUE; gint i; for (i = 0; i < self->initialized_pipes->len; i++) { if (!log_pipe_deinit(g_ptr_array_index(self->initialized_pipes, i))) success = FALSE; } return success; } gboolean cfg_tree_pre_config_init(CfgTree *self) { gint i; g_assert(self->compiled); for (i = 0; i < self->initialized_pipes->len; i++) { LogPipe *pipe = g_ptr_array_index(self->initialized_pipes, i); if (!log_pipe_pre_config_init(pipe)) { msg_error("Error executing pre_config_init hook", evt_tag_str("plugin_name", pipe->plugin_name ? pipe->plugin_name : "not a plugin"), log_pipe_location_tag(pipe)); return FALSE; } } return TRUE; } gboolean cfg_tree_post_config_init(CfgTree *self) { gint i; for (i = 0; i < self->initialized_pipes->len; i++) { LogPipe *pipe = g_ptr_array_index(self->initialized_pipes, i); if (!log_pipe_post_config_init(pipe)) { msg_error("Error executing post_config_init hook", evt_tag_str("plugin_name", pipe->plugin_name ? pipe->plugin_name : "not a plugin"), log_pipe_location_tag(pipe)); return FALSE; } } return TRUE; } void cfg_tree_init_instance(CfgTree *self, GlobalConfig *cfg) { memset(self, 0, sizeof(*self)); self->initialized_pipes = g_ptr_array_new(); self->objects = g_hash_table_new_full(cfg_tree_objects_hash, cfg_tree_objects_equal, NULL, (GDestroyNotify) log_expr_node_unref); self->templates = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) log_template_unref); self->log_path_names = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); self->rules = g_ptr_array_new(); self->cfg = cfg; } void cfg_tree_free_instance(CfgTree *self) { g_ptr_array_foreach(self->initialized_pipes, (GFunc) log_pipe_unref, NULL); g_ptr_array_free(self->initialized_pipes, TRUE); g_ptr_array_foreach(self->rules, (GFunc) log_expr_node_unref, NULL); g_ptr_array_free(self->rules, TRUE); g_hash_table_destroy(self->objects); g_hash_table_destroy(self->templates); g_hash_table_destroy(self->log_path_names); self->cfg = NULL; } syslog-ng-syslog-ng-4.4.0/lib/cfg-tree.h000066400000000000000000000170721450431004300177750ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFGTREE_H_INCLUDED #define CFGTREE_H_INCLUDED #include "syslog-ng.h" #include "template/templates.h" #include "cfg-lexer.h" #include "messages.h" #include "atomic.h" const gchar *log_expr_node_get_content_name(gint content); #define LC_CATCHALL 1 #define LC_FALLBACK 2 #define LC_FINAL 4 #define LC_FLOW_CONTROL 8 enum { /* expr node content type */ ENC_SOURCE, ENC_DESTINATION, ENC_FILTER, ENC_PARSER, ENC_REWRITE, ENC_MAX, /* */ ENC_PIPE, /* expr node layouts type */ ENL_SINGLE, ENL_REFERENCE, ENL_SEQUENCE, ENL_JUNCTION, ENL_CONDITIONAL, }; typedef struct _LogExprNode LogExprNode; /** * Log Expressions * =============== * * Everything except a few things are parsed from the configuration as * a log expression. The few exceptions are: templates, global options and blocks. * * Sources, destinations, filters, parsers, rewrite rules and global * log statements are log expressions. * * Log expressions describe a graph, which is then traversed by * messages received by syslog-ng. The graph used to be a tree * (e.g. no cycles), but this limitation was lifted in syslog-ng 3.4, * when the concept of log expression was introduced. * * Log expression is a part of the graph, the larger graph is created * by connecting these parts as dictated by the configuration. * * Each log expression is represented using a tree of LogExprNode * elements. Each node in this tree defines the layout how its children * are to be connected: * - simple element: holds a single LogPipe, no children * - reference: used to reference log expressions defined elsewhere, no children * - sequence: holds a sequence of LogExprNodes * - junction: holds a junction * - conditional: holds a conditional (simple or compound if), three children: filter, true_expr, false_expr * * Sometimes syslog-ng needs to know what kind of object the user * originally defined, this is stored in the "content" member. * * ENC_PIPE: content is a single LogPipe instance (in the "object" member) * ENC_SOURCE: content is a source log expression node (source statement or one defined inline) * ENC_DESTINATION: content is a destination node * ENC_FILTER: content is a filter node * ENC_PARSER: content is a parser node * ENC_REWRITE: content is a rewrite node */ struct _LogExprNode { GAtomicCounter ref_cnt; gint16 layout; gint16 content; guint32 flags; /* name of the rule for named rules and name of the named rule for references */ gchar *name; /* parent node */ LogExprNode *parent; /* list of children */ LogExprNode *children; /* next sibling */ LogExprNode *next; gpointer object; GDestroyNotify object_destroy; /* used during construction in case a rule specific object needs to be created. */ gpointer aux; GDestroyNotify aux_destroy; gchar *filename; gint line, column; gint child_id; }; gint log_expr_node_lookup_flag(const gchar *flag); LogExprNode *log_expr_node_append_tail(LogExprNode *a, LogExprNode *b); void log_expr_node_set_object(LogExprNode *self, gpointer object, GDestroyNotify destroy); void log_expr_node_set_name(LogExprNode *self, const gchar *name); const gchar *log_expr_node_format_location(LogExprNode *self, gchar *buf, gsize buf_len); EVTTAG *log_expr_node_location_tag(LogExprNode *self); LogExprNode *log_expr_node_new(gint layout, gint content, const gchar *name, LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_ref(LogExprNode *self); LogExprNode *log_expr_node_unref(LogExprNode *self); LogExprNode *log_expr_node_new_pipe(LogPipe *pipe, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_source(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_source_reference(const gchar *name, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_destination(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_destination_reference(const gchar *name, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_filter(const gchar *name, LogExprNode *node, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_filter_reference(const gchar *name, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_parser(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_parser_reference(const gchar *name, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_rewrite(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_rewrite_reference(const gchar *name, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_log(LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_sequence(LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_junction(LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_source_junction(LogExprNode *children, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_destination_junction(LogExprNode *children, CFG_LTYPE *yylloc); void log_expr_node_conditional_set_false_branch_of_the_last_if(LogExprNode *conditional_node, LogExprNode *false_expr); LogExprNode *log_expr_node_new_simple_conditional(LogExprNode *filter_expr, LogExprNode *true_expr, CFG_LTYPE *yylloc); LogExprNode *log_expr_node_new_compound_conditional(LogExprNode *block, CFG_LTYPE *yylloc); typedef struct _CfgTree { GlobalConfig *cfg; GPtrArray *initialized_pipes; gint anon_counters[ENC_MAX]; /* hash of predefined source/filter/rewrite/parser/destination objects */ GHashTable *objects; /* list of top-level rules */ GPtrArray *rules; GHashTable *templates; gboolean compiled; GHashTable *log_path_names; } CfgTree; gboolean cfg_tree_add_object(CfgTree *self, LogExprNode *rule); LogExprNode *cfg_tree_get_object(CfgTree *self, gint type, const gchar *name); GList *cfg_tree_get_objects(CfgTree *self); gboolean cfg_tree_add_template(CfgTree *self, LogTemplate *template_obj); LogTemplate *cfg_tree_lookup_template(CfgTree *self, const gchar *name); LogTemplate *cfg_tree_check_inline_template(CfgTree *self, const gchar *template_or_name, GError **error); gchar *cfg_tree_get_rule_name(CfgTree *self, gint content, LogExprNode *node); gchar *cfg_tree_get_child_id(CfgTree *self, gint content, LogExprNode *node); gboolean cfg_tree_compile(CfgTree *self); gboolean cfg_tree_start(CfgTree *self); gboolean cfg_tree_stop(CfgTree *self); gboolean cfg_tree_pre_config_init(CfgTree *self); gboolean cfg_tree_post_config_init(CfgTree *self); void cfg_tree_init_instance(CfgTree *self, GlobalConfig *cfg); void cfg_tree_free_instance(CfgTree *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg-walker.c000066400000000000000000000044071450431004300203140ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-walker.h" #include "logpipe.h" Arc * arc_new(LogPipe *from, LogPipe *to, ArcType arc_type) { Arc *self = g_new0(Arc, 1); self->from = from; self->to = to; self->arc_type = arc_type; return self; }; void arc_free(Arc *self) { g_free(self); } static guint arc_hash(Arc *arc) { return g_direct_hash(arc->from); } static gboolean arc_equal(Arc *arc1, Arc *arc2) { return arc1->to == arc2->to; } static void walk_pipe(LogPipe *self, gpointer *user_data); static void _add_arc_and_walk(Arc *arc, gpointer *user_data) { GHashTable **arcs = user_data[1]; g_hash_table_insert(*arcs, arc, NULL); walk_pipe(arc->to, user_data); } static void walk_pipe(LogPipe *self, gpointer *user_data) { GHashTable **nodes = user_data[0]; if (g_hash_table_contains(*nodes, self)) return; g_hash_table_insert(*nodes, self, NULL); GList *new_arcs = log_pipe_get_arcs(self); g_list_foreach(new_arcs, (GFunc)_add_arc_and_walk, user_data); g_list_free(new_arcs); } void cfg_walker_get_graph(GPtrArray *start_nodes, GHashTable **nodes, GHashTable **arcs) { *nodes = g_hash_table_new(g_direct_hash, g_direct_equal); *arcs = g_hash_table_new_full((GHashFunc)arc_hash, (GEqualFunc)arc_equal, (GDestroyNotify)arc_free, NULL); g_ptr_array_foreach(start_nodes, (GFunc)walk_pipe, (gpointer []) { nodes, arcs }); } syslog-ng-syslog-ng-4.4.0/lib/cfg-walker.h000066400000000000000000000025321450431004300203160ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_WALKER_H_INCLUDED #define CFG_WALKER_H_INCLUDED #include "syslog-ng.h" typedef enum { ARC_TYPE_PIPE_NEXT, ARC_TYPE_NEXT_HOP } ArcType; typedef struct { LogPipe *from; LogPipe *to; ArcType arc_type; } Arc; void cfg_walker_get_graph(GPtrArray *start_nodes, GHashTable **nodes, GHashTable **arcs); Arc *arc_new(LogPipe *from, LogPipe *to, ArcType arc_type); void arc_free(Arc *self); #endif syslog-ng-syslog-ng-4.4.0/lib/cfg.c000066400000000000000000000564511450431004300170370ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg.h" #include "cfg-path.h" #include "cfg-grammar.h" #include "module-config.h" #include "cfg-tree.h" #include "messages.h" #include "template/templates.h" #include "userdb.h" #include "logmsg/logmsg.h" #include "dnscache.h" #include "serialize.h" #include "plugin.h" #include "cfg-parser.h" #include "stats/stats-registry.h" #include "logproto/logproto-builtins.h" #include "reloc.h" #include "hostname.h" #include "rcptid.h" #include "resolved-configurable-paths.h" #include "mainloop.h" #include "timeutils/format.h" #include "apphook.h" #include #include #include #include #include #include #include #define CONFIG_HASH_LENGTH SHA256_DIGEST_LENGTH #define CONFIG_HASH_STR_LENGTH (CONFIG_HASH_LENGTH * 2 + 1) gint cfg_ts_format_value(gchar *format) { if (strcmp(format, "rfc3164") == 0 || strcmp(format, "bsd") == 0) return TS_FMT_BSD; else if (strcmp(format, "rfc3339") == 0 || strcmp(format, "iso") == 0) return TS_FMT_ISO; else if (strcmp(format, "full") == 0) return TS_FMT_FULL; else if (strcmp(format, "unix") == 0 || strcmp(format, "utc") == 0) return TS_FMT_UNIX; else { msg_error("Invalid ts_format() value", evt_tag_str("value", format)); return TS_FMT_BSD; } } void cfg_bad_hostname_set(GlobalConfig *self, gchar *bad_hostname_re) { if (self->bad_hostname_re) g_free(self->bad_hostname_re); self->bad_hostname_re = g_strdup(bad_hostname_re); } gint cfg_lookup_mark_mode(const gchar *mark_mode) { if (!strcmp(mark_mode, "internal")) return MM_INTERNAL; if (!strcmp(mark_mode, "dst_idle") || !strcmp(mark_mode, "dst-idle")) return MM_DST_IDLE; if (!strcmp(mark_mode, "host_idle") || !strcmp(mark_mode, "host-idle")) return MM_HOST_IDLE; if (!strcmp(mark_mode, "periodical")) return MM_PERIODICAL; if (!strcmp(mark_mode, "none")) return MM_NONE; if (!strcmp(mark_mode, "global")) return MM_GLOBAL; return -1; } void cfg_set_mark_mode(GlobalConfig *self, const gchar *mark_mode) { self->mark_mode = cfg_lookup_mark_mode(mark_mode); } gboolean cfg_set_log_level(GlobalConfig *self, const gchar *log_level) { gint ll = msg_map_string_to_log_level(log_level); if (ll < 0) return FALSE; configuration->log_level = ll; return TRUE; } static void _invoke_module_init(gchar *key, ModuleConfig *mc, gpointer *args) { GlobalConfig *cfg = (GlobalConfig *) args[0]; gboolean *result = (gboolean *) args[1]; if (!module_config_init(mc, cfg)) *result = FALSE; } static void _invoke_module_deinit(gchar *key, ModuleConfig *mc, gpointer user_data) { GlobalConfig *cfg = (GlobalConfig *) user_data; module_config_deinit(mc, cfg); } gboolean cfg_load_module_with_args(GlobalConfig *cfg, const gchar *module_name, CfgArgs *args) { return plugin_load_module(&cfg->plugin_context, module_name, args); } gboolean cfg_load_module(GlobalConfig *cfg, const gchar *module_name) { return cfg_load_module_with_args(cfg, module_name, NULL); } void cfg_load_forced_modules(GlobalConfig *self) { static const gchar *module_list[] = { #if (!SYSLOG_NG_ENABLE_FORCED_SERVER_MODE) "license" #endif }; if (!self->enable_forced_modules) return; int i; for (i=0; iuse_plugin_discovery) { if (!plugin_has_discovery_run(&self->plugin_context)) plugin_discover_candidate_modules(&self->plugin_context); } } gboolean cfg_is_module_available(GlobalConfig *self, const gchar *module_name) { /* NOTE: if plugin discovery is disabled, the only way to know if a module * is available is to actually load it */ if (!self->use_plugin_discovery) return cfg_load_module(self, module_name); else return plugin_is_module_available(&self->plugin_context, module_name); } Plugin * cfg_find_plugin(GlobalConfig *cfg, gint plugin_type, const gchar *plugin_name) { return plugin_find(&cfg->plugin_context, plugin_type, plugin_name); } static CfgTokenBlock * _construct_plugin_prelude(GlobalConfig *cfg, Plugin *plugin, CFG_LTYPE *yylloc) { CfgTokenBlock *block; CFG_STYPE token; /* we inject two tokens to a new token-block: * 1) the plugin type (in order to make it possible to support different * plugins from the same grammar) * * 2) the keyword equivalent of the plugin name * * These tokens are automatically inserted into the token stream, so that * the module specific grammar finds it there before any other token. * These tokens are used to branch out for multiple different * plugins within the same module, e.g. grammar. */ block = cfg_token_block_new(); /* add plugin->type as a token */ memset(&token, 0, sizeof(token)); token.type = LL_TOKEN; token.token = plugin->type; cfg_token_block_add_and_consume_token(block, &token); /* start a new lexer context, so plugin specific keywords are recognized, * we only do this to lookup the parser name. */ cfg_lexer_push_context(cfg->lexer, plugin->parser->context, plugin->parser->keywords, plugin->parser->name); cfg_lexer_map_word_to_token(cfg->lexer, &token, yylloc, plugin->name); cfg_lexer_pop_context(cfg->lexer); /* add plugin name token */ cfg_token_block_add_and_consume_token(block, &token); return block; } /* construct a plugin instance by parsing its relevant portion from the * configuration file */ gpointer cfg_parse_plugin(GlobalConfig *cfg, Plugin *plugin, CFG_LTYPE *yylloc, gpointer arg) { cfg_lexer_inject_token_block(cfg->lexer, _construct_plugin_prelude(cfg, plugin, yylloc)); return plugin_construct_from_config(plugin, cfg->lexer, arg); } static gboolean cfg_init_modules(GlobalConfig *cfg) { gboolean result = TRUE; gpointer args[] = { cfg, &result }; g_hash_table_foreach(cfg->module_config, (GHFunc) _invoke_module_init, args); return result; } static void cfg_deinit_modules(GlobalConfig *cfg) { g_hash_table_foreach(cfg->module_config, (GHFunc) _invoke_module_deinit, cfg); } /* Request that this configuration shuts down and terminates. Right now, as * there's only one configuration executed in a syslog-ng process, it will * cause the mainloop to exit. Should there be multiple configs running in * the same process at a future point, this would only terminate one and * continue with the rest. */ void cfg_shutdown(GlobalConfig *cfg) { MainLoop *main_loop = main_loop_get_instance(); main_loop_exit(main_loop); } gboolean cfg_is_shutting_down(GlobalConfig *cfg) { MainLoop *main_loop = main_loop_get_instance(); return main_loop_is_terminating(main_loop); } gboolean cfg_init(GlobalConfig *cfg) { gint regerr; msg_apply_config_log_level(cfg->log_level); if (cfg->file_template_name && !(cfg->file_template = cfg_tree_lookup_template(&cfg->tree, cfg->file_template_name))) msg_error("Error resolving file template", evt_tag_str("name", cfg->file_template_name)); if (cfg->proto_template_name && !(cfg->proto_template = cfg_tree_lookup_template(&cfg->tree, cfg->proto_template_name))) msg_error("Error resolving protocol template", evt_tag_str("name", cfg->proto_template_name)); if (cfg->bad_hostname_re) { if ((regerr = regcomp(&cfg->bad_hostname, cfg->bad_hostname_re, REG_NOSUB | REG_EXTENDED)) != 0) { gchar buf[256]; regerror(regerr, &cfg->bad_hostname, buf, sizeof(buf)); msg_error("Error compiling bad_hostname regexp", evt_tag_str("error", buf)); } else { cfg->bad_hostname_compiled = TRUE; } } if (!rcptid_init(cfg->state, cfg->use_uniqid)) return FALSE; stats_reinit(&cfg->stats_options); dns_caching_update_options(&cfg->dns_cache_options); hostname_reinit(cfg->custom_domain); host_resolve_options_init_globals(&cfg->host_resolve_options); log_template_options_init(&cfg->template_options, cfg); if (!cfg_init_modules(cfg)) return FALSE; if (!cfg_tree_compile(&cfg->tree)) return FALSE; app_config_pre_pre_init(); if (!cfg_tree_pre_config_init(&cfg->tree)) return FALSE; app_config_pre_init(); if (!cfg_tree_start(&cfg->tree)) return FALSE; /* * TLDR: A half-initialized pipeline turned out to be really hard to deinitialize * correctly when dedicated source/destination threads are spawned (because we * would have to wait for workers to stop and guarantee some internal * task/timer/fdwatch ordering in ivykis during this action). * See: https://github.com/syslog-ng/syslog-ng/pull/3176#issuecomment-638849597 */ g_assert(cfg_tree_post_config_init(&cfg->tree)); return TRUE; } gboolean cfg_deinit(GlobalConfig *cfg) { cfg_deinit_modules(cfg); rcptid_deinit(); return cfg_tree_stop(&cfg->tree); } void cfg_set_version_without_validation(GlobalConfig *self, gint version) { self->user_version = version; } gboolean cfg_set_version(GlobalConfig *self, gint version) { if (self->user_version != 0) { msg_warning("WARNING: you have multiple @version directives in your configuration, only the first one is considered", cfg_format_config_version_tag(self), cfg_format_version_tag("new-version", version)); return TRUE; } cfg_set_version_without_validation(self, version); if (cfg_is_config_version_older(self, VERSION_VALUE_3_0)) { msg_error("ERROR: compatibility with configurations below 3.0 was dropped in " VERSION_3_13 ", please update your configuration accordingly", cfg_format_config_version_tag(self)); return FALSE; } if (cfg_is_config_version_older(self, VERSION_VALUE_LAST_SEMANTIC_CHANGE)) { msg_warning("WARNING: Configuration file format is too old, syslog-ng is running in compatibility mode. " "Please update it to use the " VERSION_PRODUCT_CURRENT " format at your time of convenience. " "To upgrade the configuration, please review the warnings about incompatible changes printed " "by syslog-ng, and once completed change the @version header at the top of the configuration " "file", cfg_format_config_version_tag(self)); } else if (version_convert_from_user(self->user_version) > VERSION_VALUE_CURRENT) { if (cfg_is_experimental_feature_enabled(self)) { msg_warning("WARNING: experimental behaviors of the future " VERSION_4_0 " are now enabled. This mode of " "operation is meant to solicit feedback and allow the evaluation of the new features. USE THIS " "MODE AT YOUR OWN RISK, please share feedback via GitHub, Gitter.im or email to the authors", cfg_format_config_version_tag(self)); } else { msg_warning("WARNING: Configuration file format is newer than the current version, please specify the " "current version number (" VERSION_STR_CURRENT ") in the @version directive. " "syslog-ng will operate at its highest supported version in this mode", cfg_format_config_version_tag(self)); self->user_version = VERSION_VALUE_CURRENT; } } if (cfg_is_config_version_older(self, VERSION_VALUE_3_3)) { msg_warning("WARNING: global: the default value of log_fifo_size() has changed to 10000 in " VERSION_3_3 " to reflect log_iw_size() changes for tcp()/udp() window size changes", cfg_format_config_version_tag(self)); } return TRUE; } gboolean cfg_set_current_version(GlobalConfig *self) { msg_info("Setting current version as config version", evt_tag_str("version", VERSION_STR_CURRENT)); return cfg_set_version(self, VERSION_VALUE_CURRENT); } gboolean cfg_allow_config_dups(GlobalConfig *self) { const gchar *s; if (cfg_is_config_version_older(self, VERSION_VALUE_3_3)) return TRUE; s = cfg_args_get(self->globals, "allow-config-dups"); if (s && atoi(s)) { return TRUE; } else { /* duplicate found, but allow-config-dups is not enabled, hint the user that he might want to use allow-config-dups */ msg_warning_once("WARNING: Duplicate configuration objects (sources, destinations, ...) are not allowed by default starting with syslog-ng 3.3, add \"@define allow-config-dups 1\" to your configuration to re-enable"); return FALSE; } } static void cfg_register_builtin_plugins(GlobalConfig *self) { log_proto_register_builtin_plugins(&self->plugin_context); } GlobalConfig * cfg_new(gint version) { GlobalConfig *self = g_new0(GlobalConfig, 1); self->module_config = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) module_config_free); self->globals = cfg_args_new(); self->user_version = version; self->config_hash = g_malloc0(CONFIG_HASH_LENGTH * sizeof(guint8)); self->flush_lines = 100; self->mark_freq = 1200; /* 20 minutes */ self->mark_mode = MM_HOST_IDLE; self->chain_hostnames = 0; self->time_reopen = 60; self->time_reap = 60; self->log_fifo_size = 10000; self->log_msg_size = 65536; file_perm_options_global_defaults(&self->file_perm_options); dns_cache_options_defaults(&self->dns_cache_options); self->threaded = TRUE; self->pass_unix_credentials = -1; log_template_options_global_defaults(&self->template_options); host_resolve_options_global_defaults(&self->host_resolve_options); self->recv_time_zone = NULL; self->keep_timestamp = TRUE; self->log_level = -1; self->use_uniqid = FALSE; /* The rcptid part of use_uniqid() is used in trace messages, enable it * explicitly. We don't care about performance if trace is enabled. */ if (trace_flag) self->use_uniqid = TRUE; stats_options_defaults(&self->stats_options); healthcheck_stats_options_defaults(&self->healthcheck_options); self->min_iw_size_per_reader = 100; cfg_tree_init_instance(&self->tree, self); plugin_context_init_instance(&self->plugin_context); self->use_plugin_discovery = TRUE; self->enable_forced_modules = TRUE; cfg_register_builtin_plugins(self); return self; } GlobalConfig * cfg_new_snippet(void) { GlobalConfig *self = cfg_new(VERSION_VALUE_CURRENT); self->use_plugin_discovery = FALSE; self->enable_forced_modules = FALSE; return self; } /* This function creates a GlobalConfig instance that shares the set of * available plugins as a master one. */ GlobalConfig * cfg_new_subordinate(GlobalConfig *master) { GlobalConfig *self = cfg_new_snippet(); plugin_context_copy_candidates(&self->plugin_context, &master->plugin_context); return self; } void cfg_set_global_paths(GlobalConfig *self) { gchar *include_path; cfg_args_set(self->globals, "syslog-ng-root", get_installation_path_for(SYSLOG_NG_PATH_PREFIX)); cfg_args_set(self->globals, "syslog-ng-data", get_installation_path_for(SYSLOG_NG_PATH_DATADIR)); cfg_args_set(self->globals, "syslog-ng-include", get_installation_path_for(SYSLOG_NG_PATH_CONFIG_INCLUDEDIR)); cfg_args_set(self->globals, "syslog-ng-sysconfdir", get_installation_path_for(SYSLOG_NG_PATH_SYSCONFDIR)); cfg_args_set(self->globals, "scl-root", get_installation_path_for(SYSLOG_NG_PATH_SCLDIR)); cfg_args_set(self->globals, "module-path", resolved_configurable_paths.initial_module_path); cfg_args_set(self->globals, "module-install-dir", resolved_configurable_paths.initial_module_path); include_path = g_strdup_printf("%s:%s", get_installation_path_for(SYSLOG_NG_PATH_SYSCONFDIR), get_installation_path_for(SYSLOG_NG_PATH_CONFIG_INCLUDEDIR)); cfg_args_set(self->globals, "include-path", include_path); g_free(include_path); } gboolean cfg_run_parser(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg) { gboolean res; GlobalConfig *old_cfg; CfgLexer *old_lexer; old_cfg = configuration; configuration = self; old_lexer = self->lexer; self->lexer = lexer; cfg_set_global_paths(self); res = cfg_parser_parse(parser, lexer, result, arg); cfg_lexer_free(lexer); self->lexer = NULL; self->lexer = old_lexer; configuration = old_cfg; return res; } gboolean cfg_run_parser_with_main_context(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg, const gchar *desc) { gboolean ret_val; cfg_lexer_push_context(lexer, main_parser.context, main_parser.keywords, desc); ret_val = cfg_run_parser(self, lexer, parser, result, arg); return ret_val; } static void cfg_dump_processed_config(GString *preprocess_output, gchar *output_filename) { FILE *output_file; if (strcmp(output_filename, "-")==0) { fprintf(stdout, "%s", preprocess_output->str); return; } output_file = fopen(output_filename, "w+"); if (!output_file) { msg_error("Error opening preprocess-into file", evt_tag_str(EVT_TAG_FILENAME, output_filename), evt_tag_error(EVT_TAG_OSERROR)); return; } fprintf(output_file, "%s", preprocess_output->str); fclose(output_file); } static GString * _load_file_into_string(const gchar *fname) { gchar *buff; GString *content = g_string_new(""); if (g_file_get_contents(fname, &buff, NULL, NULL)) { g_string_append(content, buff); g_free(buff); } return content; } static void _cfg_file_path_free(gpointer data) { CfgFilePath *self = (CfgFilePath *)data; g_free(self->file_path); g_free(self->path_type); g_free(self); } static inline const gchar * _format_config_hash(GlobalConfig *self, gchar *str, size_t str_size) { for (gsize i = 0; i < CONFIG_HASH_LENGTH; ++i) { g_snprintf(str + (i * 2), str_size - (i * 2), "%02x", self->config_hash[i]); } return str; } void cfg_set_user_config_id(GlobalConfig *self, const gchar *id) { g_free(self->user_config_id); self->user_config_id = g_strdup(id); } void cfg_format_id(GlobalConfig *self, GString *id) { gchar buf[CONFIG_HASH_STR_LENGTH]; if (self->user_config_id) g_string_printf(id, "%s (%s)", self->user_config_id, _format_config_hash(self, buf, sizeof(buf))); else g_string_assign(id, _format_config_hash(self, buf, sizeof(buf))); } static void cfg_hash_config(GlobalConfig *self) { SHA256((const guchar *) self->preprocess_config->str, self->preprocess_config->len, self->config_hash); } gboolean cfg_read_config(GlobalConfig *self, const gchar *fname, gchar *preprocess_into) { FILE *cfg_file; gint res; cfg_discover_candidate_modules(self); cfg_load_forced_modules(self); self->filename = fname; if ((cfg_file = fopen(fname, "r")) != NULL) { CfgLexer *lexer; self->preprocess_config = g_string_sized_new(8192); self->original_config = _load_file_into_string(fname); lexer = cfg_lexer_new(self, cfg_file, fname, self->preprocess_config); res = cfg_run_parser(self, lexer, &main_parser, (gpointer *) &self, NULL); fclose(cfg_file); cfg_hash_config(self); if (preprocess_into) { cfg_dump_processed_config(self->preprocess_config, preprocess_into); } if (self->user_version == 0) { msg_error("ERROR: configuration files without a version number have become unsupported in " VERSION_3_13 ", please specify a version number using @version as the first line in the configuration file"); return FALSE; } if (res) { /* successfully parsed */ return TRUE; } } else { msg_error("Error opening configuration file", evt_tag_str(EVT_TAG_FILENAME, fname), evt_tag_error(EVT_TAG_OSERROR)); } return FALSE; } void cfg_free(GlobalConfig *self) { g_assert(self->persist == NULL); g_free(self->file_template_name); g_free(self->proto_template_name); log_template_unref(self->file_template); log_template_unref(self->proto_template); log_template_options_destroy(&self->template_options); host_resolve_options_destroy(&self->host_resolve_options); if (self->bad_hostname_compiled) regfree(&self->bad_hostname); g_free(self->recv_time_zone); if (self->source_mangle_callback_list) g_list_free(self->source_mangle_callback_list); g_free(self->bad_hostname_re); dns_cache_options_destroy(&self->dns_cache_options); g_free(self->custom_domain); plugin_context_deinit_instance(&self->plugin_context); cfg_tree_free_instance(&self->tree); g_hash_table_unref(self->module_config); cfg_args_unref(self->globals); if (self->state) persist_state_free(self->state); if (self->preprocess_config) g_string_free(self->preprocess_config, TRUE); if (self->original_config) g_string_free(self->original_config, TRUE); g_list_free_full(self->file_list, _cfg_file_path_free); g_free(self->user_config_id); g_free(self->config_hash); g_free(self); } void cfg_persist_config_move(GlobalConfig *src, GlobalConfig *dest) { if (dest->persist != NULL) persist_config_free(dest->persist); dest->persist = src->persist; dest->state = src->state; src->persist = NULL; src->state = NULL; } void cfg_persist_config_add(GlobalConfig *cfg, const gchar *name, gpointer value, GDestroyNotify destroy) { if (!value) return; if (!cfg->persist) { if (destroy) destroy(value); return; } persist_config_add(cfg->persist, name, value, destroy); } gpointer cfg_persist_config_fetch(GlobalConfig *cfg, const gchar *name) { if (!cfg->persist) return NULL; return persist_config_fetch(cfg->persist, name); } gint cfg_get_user_version(const GlobalConfig *cfg) { return cfg->user_version; } void register_source_mangle_callback(GlobalConfig *src, mangle_callback cb) { src->source_mangle_callback_list = g_list_append(src->source_mangle_callback_list, cb); } gboolean is_source_mangle_callback_registered(GlobalConfig *src, mangle_callback cb) { return !!g_list_find(src->source_mangle_callback_list, cb); } void uregister_source_mangle_callback(GlobalConfig *src, mangle_callback cb) { src->source_mangle_callback_list = g_list_remove(src->source_mangle_callback_list, cb); } const gchar * cfg_get_filename(const GlobalConfig *cfg) { return cfg->filename; } syslog-ng-syslog-ng-4.4.0/lib/cfg.h000066400000000000000000000207671450431004300170450ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CFG_H_INCLUDED #define CFG_H_INCLUDED #include "syslog-ng.h" #include "cfg-tree.h" #include "cfg-lexer.h" #include "cfg-parser.h" #include "cfg-persist.h" #include "plugin.h" #include "persist-state.h" #include "template/templates.h" #include "host-resolve.h" #include "logmsg/type-hinting.h" #include "stats/stats.h" #include "healthcheck/healthcheck-stats.h" #include "dnscache.h" #include "file-perms.h" #include #include /* destination mark modes */ enum { MM_INTERNAL = 1, MM_DST_IDLE, MM_HOST_IDLE, MM_PERIODICAL, MM_NONE, MM_GLOBAL, }; /* configuration data as loaded from the config file */ struct _GlobalConfig { /* version number specified by the user, set _after_ parsing is complete */ /* hex-encoded syslog-ng major/minor, e.g. 0x0201 is syslog-ng 2.1 format */ gint user_version; /* config identifier specified by the user */ gchar *user_config_id; guint8 *config_hash; const gchar *filename; PluginContext plugin_context; gboolean use_plugin_discovery; gboolean enable_forced_modules; CfgLexer *lexer; CfgArgs *globals; StatsOptions stats_options; HealthCheckStatsOptions healthcheck_options; gint mark_freq; gint flush_lines; gint mark_mode; gboolean threaded; gboolean pass_unix_credentials; gboolean chain_hostnames; gboolean keep_hostname; gboolean check_hostname; gboolean bad_hostname_compiled; regex_t bad_hostname; gchar *bad_hostname_re; gchar *custom_domain; DNSCacheOptions dns_cache_options; gint time_reopen; gint time_reap; gint suppress; gint type_cast_strictness; gint log_fifo_size; gint log_msg_size; gboolean trim_large_messages; gint log_level; gboolean create_dirs; FilePermOptions file_perm_options; GList *source_mangle_callback_list; gboolean use_uniqid; gboolean keep_timestamp; gchar *recv_time_zone; LogTemplateOptions template_options; HostResolveOptions host_resolve_options; gchar *file_template_name; gchar *proto_template_name; LogTemplate *file_template; LogTemplate *proto_template; guint min_iw_size_per_reader; PersistConfig *persist; PersistState *state; GHashTable *module_config; CfgTree tree; GString *preprocess_config; GString *original_config; GList *file_list; }; gboolean cfg_load_module_with_args(GlobalConfig *cfg, const gchar *module_name, CfgArgs *args); gboolean cfg_load_module(GlobalConfig *cfg, const gchar *module_name); gboolean cfg_is_module_available(GlobalConfig *self, const gchar *module_name); void cfg_discover_candidate_modules(GlobalConfig *self); Plugin *cfg_find_plugin(GlobalConfig *cfg, gint plugin_type, const gchar *plugin_name); gpointer cfg_parse_plugin(GlobalConfig *cfg, Plugin *plugin, CFG_LTYPE *yylloc, gpointer arg); gboolean cfg_allow_config_dups(GlobalConfig *self); void cfg_bad_hostname_set(GlobalConfig *self, gchar *bad_hostname_re); gint cfg_lookup_mark_mode(const gchar *mark_mode); void cfg_set_mark_mode(GlobalConfig *self, const gchar *mark_mode); gboolean cfg_set_log_level(GlobalConfig *self, const gchar *log_level); gint cfg_tz_convert_value(gchar *convert); gint cfg_ts_format_value(gchar *format); void cfg_set_version_without_validation(GlobalConfig *self, gint version); gboolean cfg_set_version(GlobalConfig *self, gint version); gboolean cfg_set_current_version(GlobalConfig *self); void cfg_set_user_config_id(GlobalConfig *self, const gchar *id); void cfg_format_id(GlobalConfig *self, GString *id); void cfg_set_global_paths(GlobalConfig *self); GlobalConfig *cfg_new(gint version); GlobalConfig *cfg_new_snippet(void); GlobalConfig *cfg_new_subordinate(GlobalConfig *master); gboolean cfg_run_parser(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg); gboolean cfg_run_parser_with_main_context(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg, const gchar *desc); gboolean cfg_read_config(GlobalConfig *cfg, const gchar *fname, gchar *preprocess_into); void cfg_load_forced_modules(GlobalConfig *self); void cfg_shutdown(GlobalConfig *self); gboolean cfg_is_shutting_down(GlobalConfig *cfg); void cfg_free(GlobalConfig *self); gboolean cfg_init(GlobalConfig *cfg); gboolean cfg_deinit(GlobalConfig *cfg); PersistConfig *persist_config_new(void); void persist_config_free(PersistConfig *self); void cfg_persist_config_move(GlobalConfig *src, GlobalConfig *dest); void cfg_persist_config_add(GlobalConfig *cfg, const gchar *name, gpointer value, GDestroyNotify destroy); gpointer cfg_persist_config_fetch(GlobalConfig *cfg, const gchar *name); typedef gboolean(* mangle_callback)(GlobalConfig *cfg, LogMessage *msg, gpointer user_data); void register_source_mangle_callback(GlobalConfig *src, mangle_callback cb); gboolean is_source_mangle_callback_registered(GlobalConfig *src, mangle_callback cb); void uregister_source_mangle_callback(GlobalConfig *src, mangle_callback cb); static inline gboolean __cfg_is_config_version_older(GlobalConfig *cfg, gint req) { if (!cfg) return FALSE; if (version_convert_from_user(cfg->user_version) >= req) return FALSE; return TRUE; } /* VERSION_VALUE_LAST_SEMANTIC_CHANGE needs to be bumped in versioning.h whenever * we add a conditional on the config version anywhere in the codebase. The * G_STATIC_ASSERT checks that we indeed did that. * * We also allow merging the features for the upcoming major version. */ #define cfg_is_config_version_older(__cfg, __req) \ ({ \ /* check that VERSION_VALUE_LAST_SEMANTIC_CHANGE is set correctly */ G_STATIC_ASSERT((__req) <= VERSION_VALUE_LAST_SEMANTIC_CHANGE || (__req) == VERSION_VALUE_NEXT_MAJOR); \ __cfg_is_config_version_older(__cfg, __req); \ }) /* This function returns TRUE if a version based feature flip is enabled. * This will enable or disable feature related upgrade warnings. * * This was initially introduced for "typing" support, where the following * is implemented: * * As long as we are using a 3.x version number (less than 3.255), the upgrade * warnings are suppressed and compatibility mode is enabled. Once @version * is something equal or larger than 3.255, we still enable compatibility but * warnings will NOT be suppressed. This is controlled with * FEATURE_TYPING_MIN_VERSION. * * Once we release 4.0, FEATURE_TYPING_MIN_VERSION needs to be set to zero in * versioning.h With that all upgrade notices start to appear when syslog-ng * finds a 3.x configuration. */ #define __cfg_is_feature_enabled(cfg, min_version) \ ({ \ /* the flip-over for min_version reached, set min_version to 0 */ G_STATIC_ASSERT(min_version == 0 || VERSION_VALUE_CURRENT < ((min_version) - 1)); \ version_convert_from_user(cfg->user_version) >= (min_version) - 1; \ }) #define cfg_is_feature_enabled(cfg, topic) __cfg_is_feature_enabled(cfg, FEATURE_ ## topic ## _MIN_VERSION) #define cfg_is_typing_feature_enabled(cfg) cfg_is_feature_enabled(cfg, TYPING) #define cfg_is_experimental_feature_enabled(cfg) 0 static inline void cfg_set_use_uniqid(gboolean flag) { configuration->use_uniqid = !!flag; } gint cfg_get_user_version(const GlobalConfig *cfg); guint cfg_get_parsed_version(const GlobalConfig *cfg); const gchar *cfg_get_filename(const GlobalConfig *cfg); static inline EVTTAG * cfg_format_version_tag(const gchar *tag_name, gint version) { return evt_tag_printf(tag_name, "%d.%d", (version & 0xFF00) >> 8, version & 0xFF); } static inline EVTTAG * cfg_format_config_version_tag(GlobalConfig *self) { return cfg_format_version_tag("config-version", self->user_version); } #endif syslog-ng-syslog-ng-4.4.0/lib/children.c000066400000000000000000000045601450431004300200620ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "children.h" typedef struct _ChildEntry { pid_t pid; gpointer callback_data; GDestroyNotify callback_data_destroy; void (*exit_callback)(pid_t pid, int status, gpointer user_data); } ChildEntry; GHashTable *child_hash; static void child_manager_child_entry_free(ChildEntry *ce) { if (ce->callback_data_destroy) ce->callback_data_destroy(ce->callback_data); g_free(ce); } void child_manager_register(pid_t pid, void (*callback)(pid_t, int, gpointer), gpointer user_data, GDestroyNotify callback_data_destroy) { ChildEntry *ce = g_new0(ChildEntry, 1); ce->pid = pid; ce->exit_callback = callback; ce->callback_data = user_data; ce->callback_data_destroy = callback_data_destroy; g_hash_table_insert(child_hash, &ce->pid, ce); } void child_manager_unregister(pid_t pid) { if (g_hash_table_lookup(child_hash, &pid)) { g_hash_table_remove(child_hash, &pid); } } void child_manager_sigchild(pid_t pid, int status) { ChildEntry *ce; ce = g_hash_table_lookup(child_hash, &pid); if (ce) { ce->exit_callback(pid, status, ce->callback_data); g_hash_table_remove(child_hash, &pid); } } void child_manager_init(void) { child_hash = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify) child_manager_child_entry_free); } void child_manager_deinit(void) { g_hash_table_destroy(child_hash); } syslog-ng-syslog-ng-4.4.0/lib/children.h000066400000000000000000000027531450431004300200710ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CHILDREN_H_INCLUDED #define CHILDREN_H_INCLUDED #include "syslog-ng.h" #include void child_manager_register(pid_t pid, void (*callback)(pid_t, int, gpointer), gpointer user_data, GDestroyNotify user_data_destroy); void child_manager_register_external_sigchld_handler(void (*callback)(int)); void child_manager_unregister(pid_t pid); void child_manager_sigchild(pid_t pid, int status); void child_manager_init(void); void child_manager_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/compat/000077500000000000000000000000001450431004300174045ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/compat/CMakeLists.txt000066400000000000000000000014141450431004300221440ustar00rootroot00000000000000set(COMPAT_HEADERS compat/compat.h compat/getutent.h compat/glib.h compat/lfs.h compat/pio.h compat/socket.h compat/string.h compat/time.h compat/openssl_support.h compat/pcre.h compat/getent.h compat/getent-sun.h compat/getent-openbsd.h compat/getent-generic.h compat/un.h compat/cpp-start.h compat/cpp-end.h PARENT_SCOPE) set(COMPAT_SOURCES compat/getutent.c compat/glib.c compat/inet_aton.c compat/memrchr.c compat/pio.c compat/strcasestr.c compat/strtok_r.c compat/strnlen.c compat/getline.c compat/time.c compat/openssl_support.c compat/getent-sun.c compat/getent-openbsd.c compat/getent-generic.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/compat/Makefile.am000066400000000000000000000017061450431004300214440ustar00rootroot00000000000000compatincludedir = ${pkgincludedir}/compat EXTRA_DIST += \ lib/compat/CMakeLists.txt compatinclude_HEADERS = \ lib/compat/compat.h \ lib/compat/getutent.h \ lib/compat/glib.h \ lib/compat/lfs.h \ lib/compat/pio.h \ lib/compat/socket.h \ lib/compat/string.h \ lib/compat/time.h \ lib/compat/openssl_support.h \ lib/compat/pcre.h \ lib/compat/getent.h \ lib/compat/getent-sun.h \ lib/compat/getent-openbsd.h \ lib/compat/getent-generic.h \ lib/compat/un.h \ lib/compat/cpp-start.h \ lib/compat/cpp-end.h compat_sources = \ lib/compat/getutent.c \ lib/compat/inet_aton.c \ lib/compat/memrchr.c \ lib/compat/pio.c \ lib/compat/glib.c \ lib/compat/strcasestr.c \ lib/compat/strtok_r.c \ lib/compat/strnlen.c \ lib/compat/getline.c \ lib/compat/time.c \ lib/compat/openssl_support.c \ lib/compat/getent-sun.c \ lib/compat/getent-openbsd.c \ lib/compat/getent-generic.c include lib/compat/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/compat/compat.h000066400000000000000000000061661450431004300210510ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* * The compat subdirectory is a placeholder for missing functionality on * various platforms. Here are the rules to follow when a specific platform * lacks a given functionality. * * NOTE: compat is the place for simple functions and fixups that should * have been defined by the system but isn't for some reason (old version, * weird platform etc). It is not the place for extensive logic, complex * implementations and so on. It is a strong indicator that we are doing * something wrong if a .c file in compat is more than a 100 lines. For * those, a proper syslog-ng style API with several implementations is the * way to go. * * NOTE/2: please don't implement dummy, empty functions for things that * make no sense on a specific platforms. In that case, please modify the * call-site instead. Whenever you read a call-site of code that resides in * compat it shouldn't misguide you that it doesn't do anything. For these * changing the call-site is better. * * File organization, call sites: * * 1) Add a header for that subsystem under lib/compat, this should in turn * include "compat/compat.h" first, and then add all headers required by * the interface itself. * * 2) compat.h will take care about including no code under * compat should do the same. * * 3) Add the implementation to one or more .c files. If the functions are * unrelated, it's preferred to have a separate .c file for each, with a * single header. In other cases you can simply use the same name for * the .c as you did for the .h * * 4) call sites should include compat/XXXX.h, preferably _instead_ of the * system header that defines the given functionality. The compat header * will include the required system headers anyway, no need to do that * multiple times. * * 5) compat.h shouldn't be included by call-sites directly. * * If a function is missing on a set of platforms, they should be named as * POSIX named them (if they are standard), or if not, they should be named * as on Linux. */ #ifndef COMPAT_COMPAT_H_INCLUDED #define COMPAT_COMPAT_H_INCLUDED #include #endif syslog-ng-syslog-ng-4.4.0/lib/compat/cpp-end.h000066400000000000000000000020701450431004300211020ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* * See "compat/cpp-start.h" for details on how to use this header. */ #ifdef __cplusplus } #undef this #endif syslog-ng-syslog-ng-4.4.0/lib/compat/cpp-start.h000066400000000000000000000066241450431004300215020ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* * C++ compat helper headers: "compat/cpp-start.h" and "compat/cpp-end.h" * * Starting your C++ header with #include "compat/cpp-start.h" and ending it * with #include "compat/cpp-end.h" helps you with two things: * - You will be able to include C headers. * - C files will be able to include your C++ header. * * Limitations: * - Obviously you can only write code in your C++ header which is * syntactically correct in a C code, so you cannot define classes, etc. * Do these in either your .cpp file or in a separate .hpp file, which * does not get included in your C code. * - As we are not preparing each C header to be includable in C++ code, * but we are trying to include them with these helpers on the call site, * we cannot be sure that any additional C header include will work. * This adds a level of uncertainty to developing a plugin in C++. * * If you find a C header that cannot be imported to C++ with these helpers, * please try to fix those headers first. If it is not possible, extend this * file with a workaround so others do not run into that issue again. * * Best practices: * - Minimize the C++ code in your plugin, if you can write and build/link * something as C code, do so, for example boilerplates: parser.{c,h} * and plugin.c. This minimizes the chance of including an incompatible * C header. * - Build/link the C++ code as C++ separately and link to that from your * C lib. Adding -lstdc++ to LIBADD is neccessary in this case as it is * automatically added while linking the C++ object itself, but not when * linking to the C++ object from a C lib. * - In your C++ code it is not possible to derive from a C class in the * usual C way by adding a super field and filling its free_fn, because * we do our own reference counting and freeing logic and we cannot rely * on the casting trick of struct packing. You can create a struct * in the usual C inheritance way and have a pointer to your C++ class * in it and you can store a pointer to this struct in your C++ class as * super, so you can access its fields. You can set the necessary virtual * functions with wrapper functions of your real C++ functions in the * ctor of the C style "class" == struct. * * You can see an example usage of the C++ plugin support at: * modules/examples/sources/random-choice-generator */ #ifdef __cplusplus #define this this_ extern "C" { #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-generic.c000066400000000000000000000075651450431004300224650ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/getent-generic.h" #ifndef SYSLOG_NG_HAVE_GETPROTOBYNUMBER_R #include #include G_LOCK_DEFINE_STATIC(getproto); /* this code does not support proto aliases, as we wouldn't be using * them anyway. Should we ever want to support it, we would need to * suballocate @buf and store all of the aliases in the same character * array. */ static void _extract_protoent_fields(struct protoent *dst, struct protoent *src, char *buf, size_t buflen) { g_strlcpy(buf, src->p_name, buflen); dst->p_name = buf; dst->p_aliases = NULL; dst->p_proto = src->p_proto; } int _compat_generic__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { struct protoent *pe; G_LOCK(getproto); pe = getprotobynumber(proto); if (pe) { _extract_protoent_fields(result_buf, pe, buf, buflen); *result = result_buf; errno = 0; } G_UNLOCK(getproto); return errno; } int _compat_generic__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { struct protoent *pe; G_LOCK(getproto); pe = getprotobyname(name); if (pe) { _extract_protoent_fields(result_buf, pe, buf, buflen); *result = result_buf; errno = 0; } G_UNLOCK(getproto); return errno; } G_LOCK_DEFINE_STATIC(getserv); /* this code does not support service aliases or using the s_proto field, as * we wouldn't be using them anyway. Should we ever want to support it, we * would need to suballocate @buf and store all of the aliases in the same * character array. */ static void _extract_servent_fields(struct servent *dst, struct servent *src, char *buf, size_t buflen) { g_strlcpy(buf, src->s_name, buflen); dst->s_name = buf; dst->s_aliases = NULL; dst->s_port = src->s_port; /* we don't support s_proto */ dst->s_proto = NULL; } int _compat_generic__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { struct servent *se; G_LOCK(getserv); se = getservbyport(port, proto); if (se) { _extract_servent_fields(result_buf, se, buf, buflen); *result = result_buf; errno = 0; } G_UNLOCK(getserv); return errno; } int _compat_generic__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { struct servent *se; G_LOCK(getserv); se = getservbyname(name, proto); if (se) { _extract_servent_fields(result_buf, se, buf, buflen); *result = result_buf; errno = 0; } G_UNLOCK(getserv); return errno; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-generic.h000066400000000000000000000040401450431004300224530ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GETENT_GENERIC_H_INCLUDED #define COMPAT_GETENT_GENERIC_H_INCLUDED #include "compat/compat.h" #ifndef SYSLOG_NG_HAVE_GETPROTOBYNUMBER_R #include #include #include #include int _compat_generic__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_generic__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_generic__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); int _compat_generic__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-openbsd.c000066400000000000000000000060761450431004300224770ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/getent-openbsd.h" #ifdef __OpenBSD__ #include #include int _compat_openbsd__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { struct protoent_data *data_buf = (struct protoent_data *)buf; if (buflen < sizeof(*data_buf)) { *result = NULL; return ERANGE; } if (getprotobynumber_r(proto, result_buf, data_buf) == -1) { *result = NULL; return errno; } *result = result_buf; return 0; } int _compat_openbsd__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { struct protoent_data *data_buf = (struct protoent_data *)buf; if (buflen < sizeof(*data_buf)) { *result = NULL; return ERANGE; } if (getprotobyname_r(name, result_buf, data_buf) == -1) { *result = NULL; return errno; } *result = result_buf; return 0; } int _compat_openbsd__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { struct servent_data *data_buf = (struct servent_data *)buf; if (buflen < sizeof(*data_buf)) { *result = NULL; return ERANGE; } if (getservbyport_r(port, proto, result_buf, data_buf) == -1) { *result = NULL; return errno; } *result = result_buf; return 0; } int _compat_openbsd__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { struct servent_data *data_buf = (struct servent_data *)buf; if (buflen < sizeof(*data_buf)) { *result = NULL; return ERANGE; } if (getservbyname_r(name, proto, result_buf, data_buf) == -1) { *result = NULL; return errno; } *result = result_buf; return 0; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-openbsd.h000066400000000000000000000040111450431004300224670ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GETENT_OPENBSD_H_INCLUDED #define COMPAT_GETENT_OPENBSD_H_INCLUDED #include "compat/compat.h" #ifdef __OpenBSD__ #include #include #include #include int _compat_openbsd__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_openbsd__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_openbsd__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); int _compat_openbsd__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-sun.c000066400000000000000000000043251450431004300216450ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/getent-sun.h" #if defined(sun) || defined(__sun) #include int _compat_sun__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { *result = getprotobynumber_r(proto, result_buf, buf, buflen); return (*result ? NULL : errno); } int _compat_sun__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result) { *result = getprotobyname_r(name, result_buf, buf, buflen); return (*result ? NULL : errno); } int _compat_sun__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { *result = getservbyport_r(port, proto, result_buf, buf, buflen); return (*result ? NULL : errno); } int _compat_sun__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result) { *result = getservbyname_r(name, proto, result_buf, buf, buflen); return (*result ? NULL : errno); } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent-sun.h000066400000000000000000000037411450431004300216530ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GETENT_SUN_H_INCLUDED #define COMPAT_GETENT_SUN_H_INCLUDED #include "compat/compat.h" #if defined(sun) || defined(__sun) #include #include #include #include int _compat_sun__getprotobynumber_r(int proto, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_sun__getprotobyname_r(const char *name, struct protoent *result_buf, char *buf, size_t buflen, struct protoent **result); int _compat_sun__getservbyport_r(int port, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); int _compat_sun__getservbyname_r(const char *name, const char *proto, struct servent *result_buf, char *buf, size_t buflen, struct servent **result); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getent.h000066400000000000000000000036371450431004300210540ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GETENT_H_INCLUDED #define COMPAT_GETENT_H_INCLUDED #include "compat/compat.h" #ifndef SYSLOG_NG_HAVE_GETPROTOBYNUMBER_R #include "getent-generic.h" #define getprotobynumber_r _compat_generic__getprotobynumber_r #define getprotobyname_r _compat_generic__getprotobyname_r #define getservbyport_r _compat_generic__getservbyport_r #define getservbyname_r _compat_generic__getservbyname_r #elif defined(__OpenBSD__) #include "getent-openbsd.h" #define getprotobynumber_r _compat_openbsd__getprotobynumber_r #define getprotobyname_r _compat_openbsd__getprotobyname_r #define getservbyport_r _compat_openbsd__getservbyport_r #define getservbyname_r _compat_openbsd__getservbyname_r #elif defined(sun) || defined(__sun) #include "getent-sun.h" #define getprotobynumber_r _compat_sun__getprotobynumber_r #define getprotobyname_r _compat_sun__getprotobyname_r #define getservbyport_r _compat_sun__getservbyport_r #define getservbyname_r _compat_sun__getservbyname_r #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getline.c000066400000000000000000000074401450431004300212040ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ /* * This code has been copied from NetBSD libc implementation with a * permissive license. */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "compat/string.h" #ifndef SYSLOG_NG_HAVE_GETLINE #include #include #include #include #include ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) { char *ptr, *eptr; if (*buf == NULL || *bufsiz == 0) { *bufsiz = BUFSIZ; if ((*buf = malloc(*bufsiz)) == NULL) return -1; } for (ptr = *buf, eptr = *buf + *bufsiz;;) { int c = fgetc(fp); if (c == -1) { if (feof(fp)) { ssize_t diff = (ssize_t)(ptr - *buf); if (diff != 0) { *ptr = '\0'; return diff; } } return -1; } *ptr++ = c; if (c == delimiter) { *ptr = '\0'; return ptr - *buf; } if (ptr + 2 >= eptr) { char *nbuf; size_t nbufsiz = *bufsiz * 2; ssize_t d = ptr - *buf; if ((nbuf = realloc(*buf, nbufsiz)) == NULL) return -1; *buf = nbuf; *bufsiz = nbufsiz; eptr = nbuf + nbufsiz; ptr = nbuf + d; } } } ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) { return getdelim(buf, bufsiz, '\n', fp); } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getutent.c000066400000000000000000000034031450431004300214070ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/getutent.h" #include #include #include #include #if !defined(SYSLOG_NG_HAVE_GETUTENT) && !defined(SYSLOG_NG_HAVE_GETUTXENT) && defined(SYSLOG_NG_HAVE_UTMP_H) static int utent_fd = -1; #ifndef _PATH_UTMP #define _PATH_UTMP "/var/log/utmp" #endif struct utmp *getutent(void) { static struct utmp ut; int rc; if (utent_fd == -1) { utent_fd = open(_PATH_UTMP, O_RDONLY | O_NOCTTY); } if (utent_fd == -1) return NULL; rc = read(utent_fd, &ut, sizeof(ut)); if (rc <= 0) { close(utent_fd); utent_fd = -1; return NULL; } else { return &ut; } } void endutent(void) { if (utent_fd != -1) { close(utent_fd); utent_fd = -1; } } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/getutent.h000066400000000000000000000025261450431004300214210ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GETUTENT_H_INCLUDED #define COMPAT_GETUTENT_H_INCLUDED #include "compat/compat.h" #include #include #ifdef SYSLOG_NG_HAVE_UTMPX_H #include #else #include #endif #if !defined(SYSLOG_NG_HAVE_GETUTENT) && !defined(SYSLOG_NG_HAVE_GETUTXENT) struct utmp *getutent(void); void endutent(void); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/glib.c000066400000000000000000000176651450431004300205040ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "glib.h" #ifndef SYSLOG_NG_HAVE_G_LIST_COPY_DEEP /* Less efficient than the original implementation in glib 2.53.2 that I wanted to port back, because this version iterates through the list twice. Though the original version depends on the internal api of GList (for example in terms on memory allocation), so I felt safer to reduce the problem to use public glib api only: g_list_copy and iteration. */ GList * g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data) { if (!list) return NULL; GList *new_list = g_list_copy(list); if (func) { GList *iter = new_list; while (iter != NULL) { iter->data = func(iter->data, user_data); iter = g_list_next(iter); } } return new_list; } #endif #ifndef SYSLOG_NG_HAVE_G_PTR_ARRAY_FIND_WITH_EQUAL_FUNC gboolean g_ptr_array_find_with_equal_func (GPtrArray *haystack, gconstpointer needle, GEqualFunc equal_func, guint *index_) { guint i; g_return_val_if_fail (haystack != NULL, FALSE); if (equal_func == NULL) equal_func = g_direct_equal; for (i = 0; i < haystack->len; i++) { if (equal_func (g_ptr_array_index (haystack, i), needle)) { if (index_ != NULL) *index_ = i; return TRUE; } } return FALSE; } #endif #ifndef SYSLOG_NG_HAVE_G_CANONICALIZE_FILENAME #include /** * g_canonicalize_filename: * @filename: (type filename): the name of the file * @relative_to: (type filename) (nullable): the relative directory, or %NULL * to use the current working directory * * Gets the canonical file name from @filename. All triple slashes are turned into * single slashes, and all `..` and `.`s resolved against @relative_to. * * Symlinks are not followed, and the returned path is guaranteed to be absolute. * * If @filename is an absolute path, @relative_to is ignored. Otherwise, * @relative_to will be prepended to @filename to make it absolute. @relative_to * must be an absolute path, or %NULL. If @relative_to is %NULL, it'll fallback * to g_get_current_dir(). * * This function never fails, and will canonicalize file paths even if they don't * exist. * * No file system I/O is done. * * Returns: (type filename) (transfer full): a newly allocated string with the * canonical file path * Since: 2.58 */ gchar * g_canonicalize_filename (const gchar *filename, const gchar *relative_to) { gchar *canon, *start, *p, *q; guint i; g_return_val_if_fail (relative_to == NULL || g_path_is_absolute (relative_to), NULL); if (!g_path_is_absolute (filename)) { gchar *cwd_allocated = NULL; const gchar *cwd; if (relative_to != NULL) cwd = relative_to; else cwd = cwd_allocated = g_get_current_dir (); canon = g_build_filename (cwd, filename, NULL); g_free (cwd_allocated); } else { canon = g_strdup (filename); } start = (char *)g_path_skip_root (canon); if (start == NULL) { /* This shouldn't really happen, as g_get_current_dir() should return an absolute pathname, but bug 573843 shows this is not always happening */ g_free (canon); return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL); } /* POSIX allows double slashes at the start to * mean something special (as does windows too). * So, "//" != "/", but more than two slashes * is treated as "/". */ i = 0; for (p = start - 1; (p >= canon) && G_IS_DIR_SEPARATOR (*p); p--) i++; if (i > 2) { i -= 1; start -= i; memmove (start, start+i, strlen (start+i) + 1); } /* Make sure we're using the canonical dir separator */ p++; while (p < start && G_IS_DIR_SEPARATOR (*p)) *p++ = G_DIR_SEPARATOR; p = start; while (*p != 0) { if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) { memmove (p, p+1, strlen (p+1)+1); } else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) { q = p + 2; /* Skip previous separator */ p = p - 2; if (p < start) p = start; while (p > start && !G_IS_DIR_SEPARATOR (*p)) p--; if (G_IS_DIR_SEPARATOR (*p)) *p++ = G_DIR_SEPARATOR; memmove (p, q, strlen (q)+1); } else { /* Skip until next separator */ while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) p++; if (*p != 0) { /* Canonicalize one separator */ *p++ = G_DIR_SEPARATOR; } } /* Remove additional separators */ q = p; while (*q && G_IS_DIR_SEPARATOR (*q)) q++; if (p != q) memmove (p, q, strlen (q) + 1); } /* Remove trailing slashes */ if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) *(p-1) = 0; return canon; } #endif #if !GLIB_CHECK_VERSION(2, 54, 0) /** * g_base64_encode: * @data: (array length=len) (element-type guint8): the binary data to encode * @len: the length of @data * * Encode a sequence of binary data into its Base-64 stringified * representation. * * Returns: (transfer full): a newly allocated, zero-terminated Base-64 * encoded string representing @data. The returned string must * be freed with g_free(). * * Since: 2.12 */ gchar * g_base64_encode_fixed(const guchar *data, gsize len) { gchar *out; gint state = 0, outlen; gint save = 0; g_return_val_if_fail (data != NULL || len == 0, NULL); /* We can use a smaller limit here, since we know the saved state is 0, +1 is needed for trailing \0, also check for unlikely integer overflow */ if (len >= ((G_MAXSIZE - 1) / 4 - 1) * 3) g_error("%s: input too large for Base64 encoding (%"G_GSIZE_FORMAT" chars)", G_STRLOC, len); out = g_malloc ((len / 3 + 1) * 4 + 1); outlen = g_base64_encode_step (data, len, FALSE, out, &state, &save); /*FIX BEGINS; copied from tf_base64encode*/ if (((unsigned char *) &save)[0] == 1) ((unsigned char *) &save)[2] = 0; /*FIX ENDS*/ outlen += g_base64_encode_close (FALSE, out + outlen, &state, &save); out[outlen] = '\0'; return (gchar *) out; } #endif #if !GLIB_CHECK_VERSION(2, 40, 0) gboolean slng_g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value) { gboolean exists = g_hash_table_contains(hash_table, key); #undef g_hash_table_insert g_hash_table_insert(hash_table, key, value); return !exists; } #endif #if !GLIB_CHECK_VERSION(2, 64, 0) gunichar g_utf8_get_char_validated_fixed(const gchar *p, gssize max_len) { // https://github.com/GNOME/glib/commit/1963821a57584b4674c20895e8a5adccd2d9effd #undef g_utf8_get_char_validated if (*p == '\0' && max_len > 0) return (gunichar)-2; return g_utf8_get_char_validated(p, max_len); } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/glib.h000066400000000000000000000042771450431004300205040ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2011 Ryan Lortie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_GLIB_H_INCLUDED #define COMPAT_GLIB_H_INCLUDED 1 #include "compat/compat.h" #include #ifndef SYSLOG_NG_HAVE_G_LIST_COPY_DEEP GList *g_list_copy_deep (GList *list, GCopyFunc func, gpointer user_data); #endif #ifndef SYSLOG_NG_HAVE_G_CANONICALIZE_FILENAME gchar *g_canonicalize_filename (const gchar *filename, const gchar *relative_to); #endif #ifndef SYSLOG_NG_HAVE_G_PTR_ARRAY_FIND_WITH_EQUAL_FUNC gboolean g_ptr_array_find_with_equal_func (GPtrArray *haystack, gconstpointer needle, GEqualFunc equal_func, guint *index_); #endif #if !GLIB_CHECK_VERSION(2, 54, 0) #define g_base64_encode g_base64_encode_fixed gchar *g_base64_encode_fixed(const guchar *data, gsize len); #endif #if !GLIB_CHECK_VERSION(2, 40, 0) #define g_hash_table_insert slng_g_hash_table_insert gboolean slng_g_hash_table_insert (GHashTable *hash_table, gpointer key, gpointer value); #endif #if !GLIB_CHECK_VERSION(2, 64, 0) #define g_utf8_get_char_validated g_utf8_get_char_validated_fixed gunichar g_utf8_get_char_validated_fixed (const gchar *p, gssize max_len); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/inet_aton.c000066400000000000000000000022511450431004300215300ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/socket.h" #ifndef SYSLOG_NG_HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *dst) { in_addr_t s = 0; s = inet_addr(cp); if (s == INADDR_NONE) return 0; dst->s_addr = s; return 1; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/lfs.h000066400000000000000000000021711450431004300203420ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* largefile support */ #ifndef COMPAT_LFS_H_INCLUDED #define COMPAT_LFS_H_INCLUDED #include "compat/compat.h" #ifndef SYSLOG_NG_HAVE_O_LARGEFILE #define O_LARGEFILE 0 #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/memrchr.c000066400000000000000000000024311450431004300212050ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/string.h" #ifndef SYSLOG_NG_HAVE_MEMRCHR #include void * memrchr(const void *s, int c, size_t n) { unsigned char *p = (unsigned char *) s + n - 1; while (p >= (unsigned char *) s) { if (*p == c) return p; p--; } return NULL; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/openssl_support.c000066400000000000000000000150471450431004300230360ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/openssl_support.h" #include "syslog-ng.h" #include "thread-utils.h" #include #include #if !SYSLOG_NG_HAVE_DECL_SSL_CTX_GET0_PARAM X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) { return ctx->param; } #endif #if !SYSLOG_NG_HAVE_DECL_X509_STORE_CTX_GET0_CERT X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx) { return ctx->cert; } #endif #if !SYSLOG_NG_HAVE_DECL_X509_GET_EXTENSION_FLAGS uint32_t X509_get_extension_flags(X509 *x) { return x->ex_flags; } #endif /* ThreadID callbacks for various OpenSSL versions */ #if OPENSSL_VERSION_NUMBER < 0x10000000 static unsigned long _ssl_thread_id(void) { return (unsigned long) get_thread_id(); } static void _init_threadid_callback(void) { CRYPTO_set_id_callback(_ssl_thread_id); } #elif OPENSSL_VERSION_NUMBER < 0x10100000L static void _ssl_thread_id2(CRYPTO_THREADID *id) { CRYPTO_THREADID_set_numeric(id, (unsigned long) get_thread_id()); } static void _init_threadid_callback(void) { CRYPTO_THREADID_set_callback(_ssl_thread_id2); } #endif /* locking callbacks for OpenSSL prior to 1.1.0 */ #if OPENSSL_VERSION_NUMBER < 0x10100000L static gint ssl_lock_count; static GMutex *ssl_locks; static void _ssl_locking_callback(int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) { g_mutex_lock(&ssl_locks[type]); } else { g_mutex_unlock(&ssl_locks[type]); } } static void _init_locks(void) { gint i; ssl_lock_count = CRYPTO_num_locks(); ssl_locks = g_new(GMutex, ssl_lock_count); for (i = 0; i < ssl_lock_count; i++) { g_mutex_init(&ssl_locks[i]); } CRYPTO_set_locking_callback(_ssl_locking_callback); } static void _deinit_locks(void) { gint i; for (i = 0; i < ssl_lock_count; i++) { g_mutex_clear(&ssl_locks[i]); } g_free(ssl_locks); } void openssl_crypto_init_threading(void) { _init_locks(); _init_threadid_callback(); } void openssl_crypto_deinit_threading(void) { _deinit_locks(); } #else void openssl_crypto_init_threading(void) { } void openssl_crypto_deinit_threading(void) { } #endif void openssl_init(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif } void openssl_ctx_setup_ecdh(SSL_CTX *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* No need to setup as ECDH auto is the default */ #elif OPENSSL_VERSION_NUMBER >= 0x10002000L SSL_CTX_set_ecdh_auto(ctx, 1); #elif OPENSSL_VERSION_NUMBER >= 0x10001000L EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!ecdh) return; SSL_CTX_set_tmp_ecdh(ctx, ecdh); EC_KEY_free(ecdh); #endif } gboolean openssl_ctx_setup_dh(SSL_CTX *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x30000000L return SSL_CTX_set_dh_auto(ctx, 1); #else DH *dh = DH_new(); if (!dh) return 0; /* * "2048-bit MODP Group" from RFC3526, Section 3. * * The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } * * RFC3526 specifies a generator of 2. */ BIGNUM *g = NULL; BN_dec2bn(&g, "2"); if (!DH_set0_pqg(dh, BN_get_rfc3526_prime_2048(NULL), NULL, g)) { BN_free(g); DH_free(dh); return 0; } long ctx_dh_success = SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); return ctx_dh_success; #endif } #if OPENSSL_VERSION_NUMBER < 0x30000000L static long _is_dh_valid(DH *dh) { if (!dh) return 0; int check_flags; if (!DH_check(dh, &check_flags)) return 0; long error_flag_is_set = check_flags & (DH_CHECK_P_NOT_PRIME | DH_UNABLE_TO_CHECK_GENERATOR | DH_CHECK_P_NOT_SAFE_PRIME | DH_NOT_SUITABLE_GENERATOR); return !error_flag_is_set; } #endif gboolean openssl_ctx_load_dh_from_file(SSL_CTX *ctx, const gchar *dhparam_file) { BIO *bio = BIO_new_file(dhparam_file, "r"); if (!bio) return 0; #if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY *dh_params = PEM_read_bio_Parameters(bio, NULL); BIO_free(bio); if (!dh_params) return 0; int ctx_dh_success = SSL_CTX_set0_tmp_dh_pkey(ctx, dh_params); if (!ctx_dh_success) EVP_PKEY_free(dh_params); return ctx_dh_success; #else DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (!_is_dh_valid(dh)) { DH_free(dh); return 0; } long ctx_dh_success = SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); return ctx_dh_success; #endif } #if !SYSLOG_NG_HAVE_DECL_DH_SET0_PQG && OPENSSL_VERSION_NUMBER < 0x30000000L int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL)) return 0; if (p != NULL) { BN_free(dh->p); dh->p = p; } if (q != NULL) { BN_free(dh->q); dh->q = q; } if (g != NULL) { BN_free(dh->g); dh->g = g; } if (q != NULL) dh->length = BN_num_bits(q); return 1; } #endif #if !SYSLOG_NG_HAVE_DECL_BN_GET_RFC3526_PRIME_2048 BIGNUM * BN_get_rfc3526_prime_2048(BIGNUM *bn) { return get_rfc3526_prime_2048(bn); } #endif void openssl_ctx_setup_session_tickets(SSL_CTX *ctx) { /* This is a workaround for an OpenSSL TLS 1.3 bug that results in data loss * when one-way protocols are used and a connection is closed by the client * right after sending data. * * Remove this call, or make it version-dependent after the bug has been fixed: * - https://github.com/openssl/openssl/issues/10880 * - https://github.com/openssl/openssl/issues/7948 */ #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET_NUM_TICKETS SSL_CTX_set_num_tickets(ctx, 0); #endif } syslog-ng-syslog-ng-4.4.0/lib/compat/openssl_support.h000066400000000000000000000050531450431004300230370ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef OPENSSL_SUPPORT_H_INCLUDED #define OPENSSL_SUPPORT_H_INCLUDED #include "compat/compat.h" #include #include #include #if !SYSLOG_NG_HAVE_DECL_SSL_CTX_GET0_PARAM X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx); #endif #if !SYSLOG_NG_HAVE_DECL_X509_STORE_CTX_GET0_CERT X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx); #endif #if !SYSLOG_NG_HAVE_DECL_X509_GET_EXTENSION_FLAGS #include uint32_t X509_get_extension_flags(X509 *x); #endif #if SYSLOG_NG_HAVE_DECL_EVP_MD_CTX_RESET #include #define EVP_MD_CTX_cleanup EVP_MD_CTX_reset #define DECLARE_EVP_MD_CTX(md_ctx) EVP_MD_CTX * md_ctx = EVP_MD_CTX_create() #else #define DECLARE_EVP_MD_CTX(md_ctx) EVP_MD_CTX _##md_ctx; EVP_MD_CTX * md_ctx = & _##md_ctx #define EVP_MD_CTX_destroy(md_ctx) EVP_MD_CTX_cleanup(md_ctx) #endif #if !SYSLOG_NG_HAVE_DECL_ASN1_STRING_GET0_DATA #define ASN1_STRING_get0_data ASN1_STRING_data #endif #if OPENSSL_VERSION_NUMBER < 0x30000000L #define SYSLOG_NG_HAVE_DECL_DIGEST_MD4 1 #endif #if !SYSLOG_NG_HAVE_DECL_DH_SET0_PQG && OPENSSL_VERSION_NUMBER < 0x30000000L int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); #endif #if !SYSLOG_NG_HAVE_DECL_BN_GET_RFC3526_PRIME_2048 BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *bn); #endif void openssl_ctx_setup_session_tickets(SSL_CTX *ctx); void openssl_ctx_setup_ecdh(SSL_CTX *ctx); gboolean openssl_ctx_setup_dh(SSL_CTX *ctx); gboolean openssl_ctx_load_dh_from_file(SSL_CTX *ctx, const gchar *dhparam_file); void openssl_init(void); void openssl_crypto_init_threading(void); void openssl_crypto_deinit_threading(void); #endif syslog-ng-syslog-ng-4.4.0/lib/compat/pcre.h000066400000000000000000000022251450431004300205070ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_PCRE_H_INCLUDED #define COMPAT_PCRE_H_INCLUDED #include "compat/compat.h" #define PCRE2_CODE_UNIT_WIDTH 8 #include #endif /* COMPAT_PCRE_H_INCLUDED */ syslog-ng-syslog-ng-4.4.0/lib/compat/pio.c000066400000000000000000000035661450431004300203510ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/pio.h" #if !defined(SYSLOG_NG_HAVE_PREAD) || defined(SYSLOG_NG_HAVE_BROKEN_PREAD) #include #include ssize_t bb__pread(int fd, void *buf, size_t count, off_t offset) { ssize_t ret; off_t old_offset; old_offset = lseek(fd, 0, SEEK_CUR); if (old_offset == -1) return -1; if (lseek(fd, offset, SEEK_SET) < 0) return -1; ret = read(fd, buf, count); if (ret < 0) return -1; if (lseek(fd, old_offset, SEEK_SET) < 0) return -1; return ret; } ssize_t bb__pwrite(int fd, const void *buf, size_t count, off_t offset) { ssize_t ret; off_t old_offset; old_offset = lseek(fd, 0, SEEK_CUR); if (old_offset == -1) return -1; if (lseek(fd, offset, SEEK_SET) < 0) return -1; ret = write(fd, buf, count); if (ret < 0) return -1; if (lseek(fd, old_offset, SEEK_SET) < 0) return -1; return ret; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/pio.h000066400000000000000000000030121450431004300203400ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_PIO_H_INCLUCED #define COMPAT_PIO_H_INCLUDED 1 #include "compat.h" #include #include /* NOTE: bb__ prefix is used for function names that might clash with system * supplied symbols. */ #if !defined(SYSLOG_NG_HAVE_PREAD) || defined(SYSLOG_NG_HAVE_BROKEN_PREAD) # ifdef pread # undef pread # endif # ifdef pwrite # undef pwrite # endif #define pread bb__pread #define pwrite bb__pwrite ssize_t bb__pread(int fd, void *buf, size_t count, off_t offset); ssize_t bb__pwrite(int fd, const void *buf, size_t count, off_t offset); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/socket.h000066400000000000000000000030151450431004300210440ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_SOCKET_H_INCLUDED #define COMPAT_SOCKET_H_INCLUDED 1 #include "compat/compat.h" #include #include #include #include #include #ifndef SYSLOG_NG_HAVE_STRUCT_SOCKADDR_STORAGE struct sockaddr_storage { union { sa_family_t ss_family; struct sockaddr __sa; struct sockaddr_un __sun; struct sockaddr_in __sin; #if SYSLOG_NG_ENABLE_IPV6 struct sockaddr_in6 __sin6; #endif }; }; #endif #ifndef SYSLOG_NG_HAVE_INET_ATON int inet_aton(const char *cp, struct in_addr *dst); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/strcasestr.c000066400000000000000000000066471450431004300217620ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ /* * This code has been copied from NetBSD libc implementation with a * permissive license with this CVSID, from * * https://github.com/NetBSD/src/blob/trunk/lib/libc/string/strcasestr.c * * $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "compat/string.h" #ifndef SYSLOG_NG_HAVE_STRCASESTR #include #include #include /* * Find the first occurrence of find in s, ignore case. */ char * strcasestr(const char *s, const char *find) { char c, sc; size_t len; if ((c = *find++) != 0) { c = tolower((unsigned char)c); len = strlen(find); do { do { if ((sc = *s++) == 0) return (NULL); } while ((char)tolower((unsigned char)sc) != c); } while (strncasecmp(s, find, len) != 0); s--; } return (char *) s; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/string.h000066400000000000000000000036041450431004300210660ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_STRING_H_INCLUDED #define COMPAT_STRING_H_INCLUDED #include "compat.h" #include #include #include #ifndef SYSLOG_NG_HAVE_STRTOLL # if SYSLOG_NG_HAVE_STRTOIMAX || defined(strtoimax) /* HP-UX has an strtoimax macro, not a function */ #include #define strtoll(nptr, endptr, base) strtoimax(nptr, endptr, base) # else /* this requires Glib 2.12 */ #define strtoll(nptr, endptr, base) g_ascii_strtoll(nptr, endptr, base) # endif #endif #ifndef SYSLOG_NG_HAVE_STRCASESTR char *strcasestr(const char *s, const char *find); #endif #ifndef SYSLOG_NG_HAVE_MEMRCHR void *memrchr(const void *s, int c, size_t n); #endif #ifndef SYSLOG_NG_HAVE_STRTOK_R char *strtok_r(char *string, const char *delim, char **saveptr); #endif #ifndef SYSLOG_NG_HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen); #endif #ifndef SYSLOG_NG_HAVE_GETLINE ssize_t getline(char **buf, size_t *bufsiz, FILE *fp); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/compat/strnlen.c000066400000000000000000000022151450431004300212350ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/string.h" #ifndef SYSLOG_NG_HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen) { const char *p = memchr(s, 0, maxlen); return p ? p-s : maxlen; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/strtok_r.c000066400000000000000000000030761450431004300214250ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/string.h" #if !defined(SYSLOG_NG_HAVE_STRTOK_R) || defined(TEST_STRTOK_R) char * strtok_r(char *str, const char *delim, char **saveptr) { char *it; char *head; if (str) *saveptr = str; if (!*saveptr) return NULL; it = *saveptr; /*find the first non-delimiter*/ it += strspn(it, delim); head = it; if (!it || !*it) { *saveptr = NULL; return NULL; } /* find the first delimiter */ it = strpbrk(it, delim); /* skip all the delimiters */ while (it && *it && strchr(delim, *it)) { *it = '\0'; it++; } *saveptr = it; return head; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/tests/000077500000000000000000000000001450431004300205465ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/compat/tests/CMakeLists.txt000066400000000000000000000000561450431004300233070ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_strtok_r) syslog-ng-syslog-ng-4.4.0/lib/compat/tests/Makefile.am000066400000000000000000000005771450431004300226130ustar00rootroot00000000000000lib_compat_tests_TESTS = \ lib/compat/tests/test_strtok_r EXTRA_DIST += \ lib/compat/tests/CMakeLists.txt check_PROGRAMS += ${lib_compat_tests_TESTS} lib_compat_tests_test_strtok_r_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/compat/tests lib_compat_tests_test_strtok_r_LDADD = $(TEST_LDADD) lib_compat_tests_test_strtok_r_SOURCES = \ lib/compat/tests/test_strtok_r.c syslog-ng-syslog-ng-4.4.0/lib/compat/tests/test_strtok_r.c000066400000000000000000000071071450431004300236250ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "syslog-ng.h" #include #include #include #include #include #include #include #include /* * NOTE: this macro magic is needed in order to make this program test the * internal strtok_r implementation even if the system has an implementation * available. * * We include the implementation file directly, redefining the name of the * function to something else. */ #ifdef strtok_r #undef strtok_r #endif #define TEST_STRTOK_R #define strtok_r __test_strtok_r #include "../strtok_r.c" #undef strtok_r #undef TEST_STRTOK_R typedef char *(STRTOK_R_FUN)(char *str, const char *delim, char **saveptr); void assert_if_tokenizer_concatenated_result_not_match(STRTOK_R_FUN tokenizer, const char *delim, const char *input, const char *expected) { gchar *token; gchar *saveptr; gchar *result = (char *)g_malloc(strlen(input)+1); gchar *raw_string; gchar *result_ref = NULL; int result_idx = 0; int token_length; raw_string = g_strdup(input); for (token = tokenizer(raw_string, delim, &saveptr); token; token = tokenizer(NULL, delim, &saveptr)) { token_length = strlen(token); memcpy(result + result_idx, token, token_length); result_idx += token_length; } result[result_idx] = '\0'; if (result_idx) result_ref = result; if (NULL == expected) cr_assert_null(result_ref); else cr_expect_str_eq(result_ref, expected, "strtok return value mismatch"); g_free(raw_string); g_free(result); } struct strtok_params { char *delim; char *input; char *expected; }; ParameterizedTestParameters(strtok, with_literals) { static struct strtok_params params[] = { { ".", "token1.token2", "token1token2" }, { ".", ".token", "token" }, { ".", "token.", "token" }, { ".", ".", NULL }, { "...", ".", NULL }, { "... ", " ", NULL }, { "..*,;-", ";-*token1...*****token2**,;;;.", "token1token2" }, { "..*,;- ", ";-*token1...*****token2**,;;;.token3", "token1token2token3" }, { "..*,;- ", ";-*token1...*****token2**,;;;.token3 ", "token1token2token3" } }; return cr_make_param_array(struct strtok_params, params, sizeof(params)/sizeof(params[0])); } ParameterizedTest(struct strtok_params *param, strtok, with_literals) { assert_if_tokenizer_concatenated_result_not_match(__test_strtok_r, param->delim, param->input, param->expected); } syslog-ng-syslog-ng-4.4.0/lib/compat/time.c000066400000000000000000000027201450431004300205070ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/time.h" #if !defined(SYSLOG_NG_HAVE_CLOCK_GETTIME) && defined(__APPLE__) && defined(__MACH__) int clock_gettime(clock_t clock_id, struct timespec *timestamp) { clock_serv_t clock_server; mach_timespec_t mach_timestamp; host_get_clock_service(mach_host_self(), clock_id, &clock_server); clock_get_time(clock_server, &mach_timestamp); timestamp->tv_sec = mach_timestamp.tv_sec; timestamp->tv_nsec = mach_timestamp.tv_nsec; mach_port_deallocate(mach_task_self(), clock_server); return 0; } #endif syslog-ng-syslog-ng-4.4.0/lib/compat/time.h000066400000000000000000000030671450431004300205210ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_TIME_H_INCLUDED #define COMPAT_TIME_H_INCLUDED #include "compat/compat.h" #include #if !defined(SYSLOG_NG_HAVE_CLOCK_GETTIME) && defined(__APPLE__) && defined(__MACH__) #include #include #define CLOCK_REALTIME CALENDAR_CLOCK #define CLOCK_MONOTONIC SYSTEM_CLOCK int clock_gettime(clock_t clock_id, struct timespec *timestamp); #else #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC CLOCK_REALTIME #endif #endif /* !SYSLOG_NG_HAVE_CLOCK_GETTIME && __APPLE__ && __MACH__ */ #endif /* COMPAT_TIME_H_INCLUDED */ syslog-ng-syslog-ng-4.4.0/lib/compat/un.h000066400000000000000000000025031450431004300201770ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMPAT_UN_H_INCLUDED #define COMPAT_UN_H_INCLUDED 1 #include /* SUN_LEN is not a POSIX standard, thus not available on all platforms. If it is available we should rely on it. Otherwise we use the formula from the Linux man page. */ #ifndef SUN_LEN #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path)) #endif #endif syslog-ng-syslog-ng-4.4.0/lib/control/000077500000000000000000000000001450431004300176015ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/control/CMakeLists.txt000066400000000000000000000007771450431004300223540ustar00rootroot00000000000000set(CONTROL_HEADERS control/control.h control/control-commands.h control/control-command-thread.h control/control-main.h control/control-server.h control/control-server-unix.h control/control-connection.h PARENT_SCOPE) set(CONTROL_SOURCES control/control-commands.c control/control-command-thread.c control/control-main.c control/control-server.c control/control-server-unix.c control/control-connection.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/control/Makefile.am000066400000000000000000000012441450431004300216360ustar00rootroot00000000000000controlincludedir = ${pkgincludedir}/control EXTRA_DIST += \ lib/control/CMakeLists.txt controlinclude_HEADERS = \ lib/control/control.h \ lib/control/control-commands.h \ lib/control/control-command-thread.h \ lib/control/control-main.h \ lib/control/control-server.h \ lib/control/control-server-unix.h \ lib/control/control-connection.h control_sources = \ lib/control/control-commands.c \ lib/control/control-command-thread.c \ lib/control/control-main.c \ lib/control/control-server.c \ lib/control/control-server-unix.c \ lib/control/control-connection.c EXTRA_DIST += lib/control/control-server-unix.c include lib/control/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/control/control-command-thread.c000066400000000000000000000111731450431004300243110ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-command-thread.h" #include "control-connection.h" #include "control-server.h" #include "messages.h" #include "secret-storage/secret-storage.h" #include "scratch-buffers.h" #include struct _ControlCommandThread { GAtomicCounter ref_cnt; ControlConnection *connection; GString *command; gpointer user_data; GThread *thread; GMutex state_lock; gboolean cancelled; gboolean finished; ControlCommandFunc func; struct iv_event thread_finished; }; static void _on_thread_finished(gpointer user_data) { ControlCommandThread *self = (ControlCommandThread *) user_data; g_thread_join(self->thread); iv_event_unregister(&self->thread_finished); control_server_worker_finished(self->connection->server, self); /* drop ref belonging to the thread_finished event */ control_command_thread_unref(self); } static void _thread(gpointer user_data) { ControlCommandThread *self = (ControlCommandThread *) user_data; scratch_buffers_allocator_init(); msg_debug("Control command thread has started", evt_tag_str("control_command", self->command->str)); self->func(self->connection, self->command, self->user_data, &self->cancelled); g_mutex_lock(&self->state_lock); { self->finished = TRUE; if (!self->cancelled) iv_event_post(&self->thread_finished); } g_mutex_unlock(&self->state_lock); /* drop ref belonging to the thread function */ msg_debug("Control command thread is exiting now", evt_tag_str("control_command", self->command->str)); scratch_buffers_explicit_gc(); scratch_buffers_allocator_deinit(); control_command_thread_unref(self); } const gchar * control_command_thread_get_command(ControlCommandThread *self) { return self->command->str; } void control_command_thread_run(ControlCommandThread *self) { self->thread_finished.cookie = control_command_thread_ref(self); iv_event_register(&self->thread_finished); control_server_worker_started(self->connection->server, self); self->thread = g_thread_new(self->command->str, (GThreadFunc) _thread, control_command_thread_ref(self)); } void control_command_thread_cancel(ControlCommandThread *self) { gboolean has_to_join = FALSE; g_mutex_lock(&self->state_lock); { self->cancelled = TRUE; if (!self->finished) { has_to_join = TRUE; } } g_mutex_unlock(&self->state_lock); if (has_to_join) g_thread_join(self->thread); } ControlCommandThread * control_command_thread_new(ControlConnection *cc, GString *cmd, ControlCommandFunc func, gpointer user_data) { ControlCommandThread *self = g_new0(ControlCommandThread, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->connection = control_connection_ref(cc); self->command = g_string_new(cmd->str); self->func = func; self->user_data = user_data; g_mutex_init(&self->state_lock); IV_EVENT_INIT(&self->thread_finished); self->thread_finished.handler = _on_thread_finished; return self; } static void _control_command_thread_free(ControlCommandThread *self) { g_mutex_clear(&self->state_lock); secret_storage_wipe(self->command->str, self->command->len); g_string_free(self->command, TRUE); control_connection_unref(self->connection); g_free(self); } ControlCommandThread * control_command_thread_ref(ControlCommandThread *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) g_atomic_counter_inc(&self->ref_cnt); return self; } void control_command_thread_unref(ControlCommandThread *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) _control_command_thread_free(self); } syslog-ng-syslog-ng-4.4.0/lib/control/control-command-thread.h000066400000000000000000000031731450431004300243170ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_COMMAND_THREAD_H_INCLUDED #define CONTROL_COMMAND_THREAD_H_INCLUDED #include "control.h" void control_command_thread_run(ControlCommandThread *self); void control_command_thread_cancel(ControlCommandThread *self); const gchar *control_command_thread_get_command(ControlCommandThread *self); ControlCommandThread *control_command_thread_new(ControlConnection *cc, GString *cmd, ControlCommandFunc func, gpointer user_data); ControlCommandThread *control_command_thread_ref(ControlCommandThread *self); void control_command_thread_unref(ControlCommandThread *self); #endif syslog-ng-syslog-ng-4.4.0/lib/control/control-commands.c000066400000000000000000000057511450431004300232340ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control/control.h" #include "control/control-main.h" #include "messages.h" #include static GList *command_list = NULL; void reset_control_command_list(void) { g_list_free_full(command_list, (GDestroyNotify)g_free); command_list = NULL; } gboolean control_command_start_with_command(const ControlCommand *cmd, const gchar *line) { return strncmp(cmd->command_name, line, strlen(cmd->command_name)); } ControlCommand * control_find_command(const char *cmd) { GList *command = g_list_find_custom(command_list, cmd, (GCompareFunc) control_command_start_with_command); if (NULL == command) return NULL; return (ControlCommand *) command->data; } void control_register_command(const gchar *command_name, ControlCommandFunc function, gpointer user_data, gboolean threaded) { ControlCommand *command = control_find_command(command_name); if (command && command->func != function) { msg_debug("Trying to register an already registered ControlCommand with different CommandFunction.", evt_tag_str("command", command_name)); return; } ControlCommand *new_command = g_new0(ControlCommand, 1); new_command->command_name = command_name; new_command->func = function; new_command->user_data = user_data; new_command->threaded = threaded; command_list = g_list_append(command_list, new_command); } void control_replace_command(const gchar *command_name, ControlCommandFunc function, gpointer user_data, gboolean threaded) { ControlCommand *command = control_find_command(command_name); if (!command) { msg_debug("Trying to replace a non-existent command. Command will be registered as a new command.", evt_tag_str("command", command_name)); control_register_command(command_name, function, user_data, threaded); return; } command->func = function; command->user_data = user_data; command->threaded = threaded; } syslog-ng-syslog-ng-4.4.0/lib/control/control-commands.h000066400000000000000000000030751450431004300232360ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_COMMANDS_H_INCLUDED #define CONTROL_COMMANDS_H_INCLUDED #include "control/control.h" #include "mainloop.h" ControlCommand *control_find_command(const char *cmd); void control_register_command(const gchar *command_name, ControlCommandFunc function, gpointer user_data, gboolean threaded); void control_replace_command(const gchar *command_name, ControlCommandFunc function, gpointer user_data, gboolean threaded); void reset_control_command_list(void); #endif syslog-ng-syslog-ng-4.4.0/lib/control/control-connection.c000066400000000000000000000231341450431004300235650ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-connection.h" #include "control-server.h" #include "control-commands.h" #include "control-command-thread.h" #include "str-utils.h" #include "secret-storage/secret-storage.h" #include "messages.h" static void _g_string_destroy(gpointer user_data) { GString *str = (GString *) user_data; g_string_free(str, TRUE); } static void _control_connection_free(ControlConnection *self) { if (self->free_fn) { self->free_fn(self); } /* * when write() fails, control_connection_closed() is called, * which then calls this free func and in this case output_buffer is not NULL * */ if (self->output_buffer) g_string_free(self->output_buffer, TRUE); g_string_free(self->input_buffer, TRUE); g_queue_free_full(self->response_batches, _g_string_destroy); g_mutex_clear(&self->response_batches_lock); iv_event_unregister(&self->evt_response_added); g_free(self); } void control_connection_send_batched_reply(ControlConnection *self, GString *reply) { g_mutex_lock(&self->response_batches_lock); g_queue_push_tail(self->response_batches, reply); g_mutex_unlock(&self->response_batches_lock); self->waiting_for_output = FALSE; iv_event_post(&self->evt_response_added); } void control_connection_send_close_batch(ControlConnection *self) { g_mutex_lock(&self->response_batches_lock); GString *last = (GString *) g_queue_peek_tail(self->response_batches); if (last) { if (last->str[last->len - 1] != '\n') g_string_append_c(last, '\n'); g_string_append(last, ".\n"); g_mutex_unlock(&self->response_batches_lock); } else { g_mutex_unlock(&self->response_batches_lock); control_connection_send_batched_reply(self, g_string_new("\n.\n")); } } void control_connection_send_reply(ControlConnection *self, GString *reply) { control_connection_send_batched_reply(self, reply); control_connection_send_close_batch(self); } static void control_connection_io_output(gpointer s) { ControlConnection *self = (ControlConnection *) s; gint rc; if (!self->output_buffer) { g_mutex_lock(&self->response_batches_lock); self->output_buffer = g_queue_pop_head(self->response_batches); g_mutex_unlock(&self->response_batches_lock); self->pos = 0; } g_assert(self->output_buffer); rc = self->write(self, self->output_buffer->str + self->pos, self->output_buffer->len - self->pos); if (rc < 0) { if (errno != EAGAIN) { msg_error("Error writing control channel", evt_tag_error("error")); control_server_connection_closed(self->server, self); return; } } else { self->pos += rc; if (self->pos == self->output_buffer->len) { g_string_free(self->output_buffer, TRUE); g_mutex_lock(&self->response_batches_lock); self->output_buffer = g_queue_pop_head(self->response_batches); g_mutex_unlock(&self->response_batches_lock); self->pos = 0; } } control_connection_update_watches(self); } void control_connection_wait_for_output(ControlConnection *self) { g_mutex_lock(&self->response_batches_lock); if (g_queue_is_empty(self->response_batches) && !self->output_buffer) self->waiting_for_output = TRUE; g_mutex_unlock(&self->response_batches_lock); control_connection_update_watches(self); } static void control_connection_start_as_thread(ControlConnection *self, ControlCommandFunc cmd_cb, GString *command, gpointer user_data) { ControlCommandThread *runner = control_command_thread_new(self, command, cmd_cb, user_data); control_command_thread_run(runner); control_command_thread_unref(runner); } static gboolean control_connection_run_command_method(ControlConnection *self, ControlCommand *command_desc, GString *command_string) { if (!command_desc->threaded) command_desc->func(self, command_string, command_desc->user_data, NULL); else control_connection_start_as_thread(self, command_desc->func, command_string, command_desc->user_data); return TRUE; } gboolean control_connection_run_command(ControlConnection *self, GString *command_string) { ControlCommand *command_desc = control_find_command(command_string->str); if (command_desc == NULL) { msg_error("Unknown command read on control channel, closing control channel", evt_tag_str("command", command_string->str)); return FALSE; } return self->run_command(self, command_desc, command_string); } static void control_connection_io_input(void *s) { ControlConnection *self = (ControlConnection *) s; GString *command = NULL; gchar *nl; gint rc; gint orig_len; if (self->input_buffer->len > MAX_CONTROL_LINE_LENGTH) { /* too much data in input, drop the connection */ msg_error("Too much data in the control socket input buffer"); control_server_connection_closed(self->server, self); return; } orig_len = self->input_buffer->len; /* NOTE: plus one for the terminating NUL */ g_string_set_size(self->input_buffer, self->input_buffer->len + 128 + 1); rc = self->read(self, self->input_buffer->str + orig_len, 128); if (rc < 0) { if (errno != EAGAIN) { msg_error("Error reading command on control channel, closing control channel", evt_tag_error("error")); goto destroy_connection; } /* EAGAIN, should try again when data comes */ control_connection_update_watches(self); return; } else if (rc == 0) { msg_debug("EOF on control channel, closing connection"); goto destroy_connection; } else { self->input_buffer->len = orig_len + rc; self->input_buffer->str[self->input_buffer->len] = 0; } /* here we have finished reading the input, check if there's a newline somewhere */ nl = strchr(self->input_buffer->str, '\n'); if (nl) { command = g_string_sized_new(128); /* command doesn't contain NL */ g_string_assign_len(command, self->input_buffer->str, nl - self->input_buffer->str); secret_storage_wipe(self->input_buffer->str, nl - self->input_buffer->str); /* strip NL */ /*g_string_erase(self->input_buffer, 0, command->len + 1);*/ g_string_truncate(self->input_buffer, 0); } else { /* no EOL in the input buffer, wait for more data */ control_connection_update_watches(self); return; } if (!control_connection_run_command(self, command)) goto destroy_connection; control_connection_wait_for_output(self); secret_storage_wipe(command->str, command->len); g_string_free(command, TRUE); return; destroy_connection: if (command) { secret_storage_wipe(command->str, command->len); g_string_free(command, TRUE); } control_server_connection_closed(self->server, self); } static void _on_evt_response_added(gpointer user_data) { ControlConnection *self = (ControlConnection *) user_data; control_connection_update_watches(self); } void control_connection_init_instance(ControlConnection *self, ControlServer *server) { g_atomic_counter_set(&self->ref_cnt, 1); self->server = server; self->input_buffer = g_string_sized_new(128); self->handle_input = control_connection_io_input; self->handle_output = control_connection_io_output; self->response_batches = g_queue_new(); self->run_command = control_connection_run_command_method; g_mutex_init(&self->response_batches_lock); IV_EVENT_INIT(&self->evt_response_added); self->evt_response_added.cookie = self; self->evt_response_added.handler = _on_evt_response_added; iv_event_register(&self->evt_response_added); return; } ControlConnection * control_connection_ref(ControlConnection *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) g_atomic_counter_inc(&self->ref_cnt); return self; } void control_connection_unref(ControlConnection *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) _control_connection_free(self); } void control_connection_start_watches(ControlConnection *self) { if (self->events.start_watches) { self->watches_are_running = TRUE; self->events.start_watches(self); } } void control_connection_update_watches(ControlConnection *self) { if (!self->watches_are_running) return; if (self->events.update_watches) self->events.update_watches(self); } void control_connection_stop_watches(ControlConnection *self) { if (self->events.stop_watches) { self->events.stop_watches(self); self->watches_are_running = FALSE; } } syslog-ng-syslog-ng-4.4.0/lib/control/control-connection.h000066400000000000000000000052501450431004300235710ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_CONNECTION_H #define CONTROL_CONNECTION_H #include "control.h" #include "atomic.h" #include struct _ControlConnection { GAtomicCounter ref_cnt; GQueue *response_batches; GMutex response_batches_lock; struct iv_event evt_response_added; gboolean waiting_for_output; gboolean watches_are_running; GString *input_buffer; GString *output_buffer; gsize pos; ControlServer *server; gboolean (*run_command)(ControlConnection *self, ControlCommand *command_desc, GString *command_string); int (*read)(ControlConnection *self, gpointer buffer, gsize size); int (*write)(ControlConnection *self, gpointer buffer, gsize size); void (*handle_input)(gpointer s); void (*handle_output)(gpointer s); void (*free_fn)(ControlConnection *self); struct { void (*start_watches)(ControlConnection *self); void (*update_watches)(ControlConnection *self); void (*stop_watches)(ControlConnection *self); } events; }; gboolean control_connection_run_command(ControlConnection *self, GString *command_string); void control_connection_send_reply(ControlConnection *self, GString *reply); void control_connection_send_batched_reply(ControlConnection *self, GString *reply); void control_connection_send_close_batch(ControlConnection *self); void control_connection_start_watches(ControlConnection *self); void control_connection_update_watches(ControlConnection *self); void control_connection_stop_watches(ControlConnection *self); void control_connection_init_instance(ControlConnection *self, ControlServer *server); ControlConnection *control_connection_ref(ControlConnection *self); void control_connection_unref(ControlConnection *self); #endif syslog-ng-syslog-ng-4.4.0/lib/control/control-main.c000066400000000000000000000027351450431004300223560ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-main.h" #include "control-server-unix.h" #include "control-commands.h" ControlServer * control_init(const gchar *control_name) { ControlServer *control_server = control_server_unix_new(control_name); control_server_start(control_server); return control_server; } void control_deinit(ControlServer *control_server) { reset_control_command_list(); if (control_server) { control_server_stop(control_server); control_server_free(control_server); } } syslog-ng-syslog-ng-4.4.0/lib/control/control-main.h000066400000000000000000000023351450431004300223570ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_MAIN_H_INCLUDED #define CONTROL_MAIN_H_INCLUDED #include "mainloop.h" #include "control/control-server.h" ControlServer *control_init(const gchar *control_name); void control_deinit(ControlServer *control_server); #endif syslog-ng-syslog-ng-4.4.0/lib/control/control-server-unix.c000066400000000000000000000161741450431004300237230ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-server.h" #include "control-connection.h" #include "messages.h" #include "gsocket.h" #include typedef struct _ControlServerUnix { ControlServer super; gchar *control_socket_name; gint control_socket; struct iv_fd control_listen; } ControlServerUnix; typedef struct _ControlConnectionUnix { ControlConnection super; struct iv_fd control_io; gint fd; } ControlConnectionUnix; gint control_connection_unix_write(ControlConnection *s, gpointer buffer, gsize size) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; return write(self->control_io.fd, buffer, size); } gint control_connection_unix_read(ControlConnection *s, gpointer buffer, gsize size) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; return read(self->control_io.fd, buffer, size); } static void control_connection_unix_start_watches(ControlConnection *s) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; IV_FD_INIT(&self->control_io); self->control_io.cookie = self; self->control_io.fd = self->fd; iv_fd_register(&self->control_io); control_connection_update_watches(s); } static void control_connection_unix_stop_watches(ControlConnection *s) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; iv_fd_unregister(&self->control_io); } static gboolean _pending_output(ControlConnection *s) { g_mutex_lock(&s->response_batches_lock); gboolean result = (s->output_buffer && s->output_buffer->len > s->pos) || !g_queue_is_empty(s->response_batches); g_mutex_unlock(&s->response_batches_lock); return result; } static void control_connection_unix_update_watches(ControlConnection *s) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; if (s->waiting_for_output) { iv_fd_set_handler_out(&self->control_io, NULL); iv_fd_set_handler_in(&self->control_io, NULL); } else if (_pending_output(s)) { iv_fd_set_handler_out(&self->control_io, s->handle_output); iv_fd_set_handler_in(&self->control_io, NULL); } else { iv_fd_set_handler_out(&self->control_io, NULL); iv_fd_set_handler_in(&self->control_io, s->handle_input); } } void control_connection_unix_free(ControlConnection *s) { ControlConnectionUnix *self = (ControlConnectionUnix *)s; close(self->control_io.fd); } ControlConnection * control_connection_unix_new(ControlServer *server, gint sock) { ControlConnectionUnix *self = g_new0(ControlConnectionUnix, 1); control_connection_init_instance(&self->super, server); self->fd = sock; self->super.free_fn = control_connection_unix_free; self->super.read = control_connection_unix_read; self->super.write = control_connection_unix_write; self->super.events.start_watches = control_connection_unix_start_watches; self->super.events.update_watches = control_connection_unix_update_watches; self->super.events.stop_watches = control_connection_unix_stop_watches; return &self->super; } static void _control_socket_accept(void *cookie) { ControlServerUnix *self = (ControlServerUnix *)cookie; gint conn_socket; GSockAddr *peer_addr; GIOStatus status; ControlConnection *cc; if (self->control_socket == -1) return; status = g_accept(self->control_socket, &conn_socket, &peer_addr); if (status != G_IO_STATUS_NORMAL) { msg_error("Error accepting control socket connection", evt_tag_error("error")); goto error; } cc = control_connection_unix_new(&self->super, conn_socket); /* NOTE: with the call below, the reference to the control connection (cc) * will be taken over by the various I/O callbacks, Those will return to * us (ControlServer) via the control_server_connection_closed() function, * which in turn will properly dispose the ControlConnection instance. */ control_connection_start_watches(cc); g_sockaddr_unref(peer_addr); error: ; } static gboolean control_server_unix_start(ControlServer *s) { ControlServerUnix *self = (ControlServerUnix *)s; GSockAddr *saddr; saddr = g_sockaddr_unix_new(self->control_socket_name); self->control_socket = socket(PF_UNIX, SOCK_STREAM, 0); if (self->control_socket == -1) { msg_error("Error opening control socket, external controls will not be available", evt_tag_str("socket", self->control_socket_name)); goto error; } if (g_bind(self->control_socket, saddr) != G_IO_STATUS_NORMAL) { msg_error("Error opening control socket, bind() failed", evt_tag_str("socket", self->control_socket_name), evt_tag_error("error")); goto error; } if (listen(self->control_socket, 255) < 0) { msg_error("Error opening control socket, listen() failed", evt_tag_str("socket", self->control_socket_name), evt_tag_error("error")); goto error; } self->control_listen.fd = self->control_socket; self->control_listen.cookie = self; iv_fd_register(&self->control_listen); iv_fd_set_handler_in(&self->control_listen, _control_socket_accept); g_sockaddr_unref(saddr); return control_server_start_method(s); error: if (self->control_socket != -1) { close(self->control_socket); self->control_socket = -1; } g_sockaddr_unref(saddr); return FALSE; } static void control_server_unix_stop(ControlServer *s) { ControlServerUnix *self = (ControlServerUnix *)s; if (iv_fd_registered(&self->control_listen)) { iv_fd_unregister(&self->control_listen); } if (self->control_socket != -1) { close(self->control_socket); } control_server_stop_method(s); } void control_server_unix_free(ControlServer *s) { ControlServerUnix *self = (ControlServerUnix *)s; g_assert(!iv_fd_registered(&self->control_listen)); g_free(self->control_socket_name); control_server_free_method(s); } ControlServer * control_server_unix_new(const gchar *path) { ControlServerUnix *self = g_new(ControlServerUnix, 1); control_server_init_instance(&self->super); self->super.start = control_server_unix_start; self->super.stop = control_server_unix_stop; self->super.free_fn = control_server_unix_free; self->control_socket_name = g_strdup(path); IV_FD_INIT(&self->control_listen); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/control/control-server-unix.h000066400000000000000000000021721450431004300237210ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_SERVER_UNIX_H #define CONTROL_SERVER_UNIX_H ControlServer *control_server_unix_new(const gchar *path); #endif syslog-ng-syslog-ng-4.4.0/lib/control/control-server.c000066400000000000000000000111241450431004300227300ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-server.h" #include "control-connection.h" #include "control-command-thread.h" #include "messages.h" void _cancel_worker(gpointer data, gpointer user_data) { ControlCommandThread *thread = (ControlCommandThread *) data; msg_warning("Requesting the cancellation of control command thread", evt_tag_str("control_command", control_command_thread_get_command(thread))); control_command_thread_cancel(thread); /* NOTE: threads would call control_server_worker_finished() when done (at * least if the main loop is still executing once to process our * thread_finished event). * * If finished() is called, our ref stored on the worker_threads list is * dropped at that point. * * If finished() is not called (e.g. the workers are stuck and have not * exited until our mainloop exit strategy is executed), their reference * remains lingering on the worker_threads list. * * We try to take care of such lingering refs in control_server_stop(), * which is executed already after iv_main() returns. */ } void control_server_cancel_workers(ControlServer *self) { if (self->worker_threads) { msg_debug("Cancelling control server worker threads"); g_list_foreach(self->worker_threads, _cancel_worker, NULL); msg_debug("Control server worker threads have been cancelled"); } } void control_server_worker_started(ControlServer *self, ControlCommandThread *worker) { control_command_thread_ref(worker); self->worker_threads = g_list_append(self->worker_threads, worker); } void control_server_worker_finished(ControlServer *self, ControlCommandThread *worker) { self->worker_threads = g_list_remove(self->worker_threads, worker); control_command_thread_unref(worker); } void control_server_connection_closed(ControlServer *self, ControlConnection *cc) { control_connection_stop_watches(cc); control_connection_unref(cc); } gboolean control_server_start_method(ControlServer *self) { /* NOTE: this is a placeholder and is empty for now. Derived * ControlServer implementations must call this at startup */ return TRUE; } void _unref_worker(gpointer data) { ControlCommandThread *thread = (ControlCommandThread *) data; msg_warning("Control command thread has not exited by the time we need to exit, forcing", evt_tag_str("control_command", control_command_thread_get_command(thread))); control_command_thread_unref(thread); } /* NOTE: this is called once the mainloop has exited, thus we would not get * our worker_thread_finished() callbacks anymore. If our worker_threads is * not empty at this point, then they have not yet responded to our cancel * signal earlier and they won't as no further main loop iterations will be * performed. * * At this point we can unref the elements of the worker list, the thread * itself will keep a reference until it is done executing, but we won't get * notifications anymore. If the thread is still running at the point * _exit() is called, we would leak some ControlCommandThread instances. */ void control_server_stop_method(ControlServer *self) { if (self->worker_threads) { g_list_free_full(self->worker_threads, _unref_worker); self->worker_threads = NULL; } } void control_server_free_method(ControlServer *self) { } void control_server_init_instance(ControlServer *self) { self->worker_threads = NULL; self->start = control_server_start_method; self->stop = control_server_stop_method; self->free_fn = control_server_free_method; } void control_server_free(ControlServer *self) { g_assert(self->worker_threads == NULL); if (self->free_fn) { self->free_fn(self); } g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/control/control-server.h000066400000000000000000000041231450431004300227360ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_SERVER_H #define CONTROL_SERVER_H #include "syslog-ng.h" #include "control.h" #include "atomic.h" #include #define MAX_CONTROL_LINE_LENGTH 4096 struct _ControlServer { GList *worker_threads; gboolean (*start)(ControlServer *s); void (*stop)(ControlServer *s); void (*free_fn)(ControlServer *self); }; void control_server_cancel_workers(ControlServer *self); void control_server_connection_closed(ControlServer *self, ControlConnection *cc); void control_server_worker_started(ControlServer *self, ControlCommandThread *worker); void control_server_worker_finished(ControlServer *self, ControlCommandThread *worker); gboolean control_server_start_method(ControlServer *self); void control_server_stop_method(ControlServer *self); void control_server_free_method(ControlServer *self); void control_server_free(ControlServer *self); void control_server_init_instance(ControlServer *self); static inline gboolean control_server_start(ControlServer *self) { if (self->start) return self->start(self); return TRUE; } static inline void control_server_stop(ControlServer *self) { if (self->stop) self->stop(self); } #endif syslog-ng-syslog-ng-4.4.0/lib/control/control.h000066400000000000000000000027471450431004300214440ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_H_INCLUDED #define CONTROL_H_INCLUDED #include "syslog-ng.h" typedef struct _ControlServer ControlServer; typedef struct _ControlConnection ControlConnection; typedef struct _ControlCommandThread ControlCommandThread; typedef void (*ControlCommandFunc)(ControlConnection *cc, GString *, gpointer user_data, gboolean *cancelled); typedef struct _ControlCommand { const gchar *command_name; ControlCommandFunc func; gpointer user_data; gboolean threaded; } ControlCommand; #endif syslog-ng-syslog-ng-4.4.0/lib/control/tests/000077500000000000000000000000001450431004300207435ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/control/tests/CMakeLists.txt000066400000000000000000000001451450431004300235030ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_control_cmds SOURCES test_control_cmds.c control-server-dummy.c) syslog-ng-syslog-ng-4.4.0/lib/control/tests/Makefile.am000066400000000000000000000010741450431004300230010ustar00rootroot00000000000000lib_control_tests_TESTS = \ lib/control/tests/test_control_cmds EXTRA_DIST += \ lib/control/tests/CMakeLists.txt check_PROGRAMS += ${lib_control_tests_TESTS} lib_control_tests_test_control_cmds_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/control/tests lib_control_tests_test_control_cmds_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/lib/secret-storage/libsecret-storage.la lib_control_tests_test_control_cmds_SOURCES = \ lib/control/tests/test_control_cmds.c \ lib/control/tests/control-server-dummy.c \ lib/control/tests/control-server-dummy.h syslog-ng-syslog-ng-4.4.0/lib/control/tests/control-server-dummy.c000066400000000000000000000101261450431004300252240ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "control-server-dummy.h" #include "control/control-connection.h" #include typedef struct _ControlConnectionDummy { ControlConnection super; GString *output; GString *input; } ControlConnectionDummy; gboolean control_connection_dummy_run_command(ControlConnection *s, ControlCommand *command_desc, GString *command_string) { /* ignore threaded execution */ command_desc->func(s, command_string, command_desc->user_data, NULL); return TRUE; } gint control_connection_dummy_write(ControlConnection *s, gpointer buffer, gsize size) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; g_string_append_len(self->output, buffer, size); return size; } /* NOTE: only supports one read */ static gint control_connection_dummy_read(ControlConnection *s, gpointer buffer, gsize size) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; strncpy(buffer, self->input->str, size); return MIN(self->input->len, size); } static void control_connection_dummy_start_watches(ControlConnection *s) { control_connection_update_watches(s); } static void control_connection_dummy_stop_watches(ControlConnection *s) { } static void control_connection_dummy_update_watches(ControlConnection *s) { if (s->waiting_for_output) g_assert_not_reached(); else if (!g_queue_is_empty(s->response_batches) || s->output_buffer) s->handle_output(s); } static void control_connection_dummy_free(ControlConnection *s) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; g_string_free(self->input, TRUE); g_string_free(self->output, TRUE); } void control_connection_dummy_set_input(ControlConnection *s, const gchar *request) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; g_string_assign(self->input, request); g_string_append_c(self->input, '\n'); } const gchar * control_connection_dummy_get_output(ControlConnection *s) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; return self->output->str; } void control_connection_dummy_reset_output(ControlConnection *s) { ControlConnectionDummy *self = (ControlConnectionDummy *)s; g_string_assign(self->output, ""); s->waiting_for_output = FALSE; } ControlConnection * control_connection_dummy_new(ControlServer *server) { ControlConnectionDummy *self = g_new0(ControlConnectionDummy, 1); control_connection_init_instance(&self->super, server); self->super.run_command = control_connection_dummy_run_command; self->super.read = control_connection_dummy_read; self->super.write = control_connection_dummy_write; self->super.events.start_watches = control_connection_dummy_start_watches; self->super.events.update_watches = control_connection_dummy_update_watches; self->super.events.stop_watches = control_connection_dummy_stop_watches; self->super.free_fn = control_connection_dummy_free; self->input = g_string_new(""); self->output = g_string_new(""); return &self->super; } typedef struct _ControlServerDummy { ControlServer super; } ControlServerDummy; ControlServer * control_server_dummy_new(void) { ControlServerDummy *self = g_new0(ControlServerDummy, 1); control_server_init_instance(&self->super); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/control/tests/control-server-dummy.h000066400000000000000000000026211450431004300252320ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTROL_SERVER_DUMMY_H_INLCUDED #define CONTROL_SERVER_DUMMY_H_INLCUDED 1 #include "control/control-server.h" void control_connection_dummy_set_input(ControlConnection *s, const gchar *request); const gchar *control_connection_dummy_get_output(ControlConnection *s); void control_connection_dummy_reset_output(ControlConnection *s); ControlConnection *control_connection_dummy_new(ControlServer *server); ControlServer *control_server_dummy_new(void); #endif syslog-ng-syslog-ng-4.4.0/lib/control/tests/test_control_cmds.c000066400000000000000000000215131450431004300246360ustar00rootroot00000000000000/* * Copyright (c) 2013-2015 Balabit * Copyright (c) 2013 Juhász Viktor * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "messages.h" #include "control/control.h" #include "control/control-commands.h" #include "control/control-connection.h" #include "control-server-dummy.h" #include "mainloop-control.h" #include "stats/stats-control.h" #include "control/control-server.h" #include "stats/stats-cluster.h" #include "stats/stats-registry.h" #include "apphook.h" #include "cfg-path.h" ControlServer *control_server; ControlConnection *control_connection; MainLoop *main_loop; void setup(void) { MainLoopOptions main_loop_options = {0}; app_startup(); main_loop = main_loop_get_instance(); main_loop_init(main_loop, &main_loop_options); main_loop_register_control_commands(main_loop); stats_register_control_commands(); control_server = control_server_dummy_new(); control_connection = control_connection_dummy_new(control_server); control_connection_start_watches(control_connection); } void teardown(void) { control_server_connection_closed(control_server, control_connection); control_server_free(control_server); main_loop_deinit(main_loop); app_shutdown(); reset_control_command_list(); } TestSuite(control_cmds, .init = setup, .fini = teardown); static void _send_request(const gchar *request) { control_connection_dummy_set_input(control_connection, request); control_connection_dummy_reset_output(control_connection); } static void _fetch_response(const gchar **response) { *response = control_connection_dummy_get_output(control_connection); } static void _run_command(const gchar *request, const gchar **response) { _send_request(request); control_connection->handle_input(control_connection); _fetch_response(response); } static gboolean first_line_eq(const gchar *buf, const gchar *expected) { const gchar *nl = strchr(buf, '\n'); return strncmp(buf, expected, nl - buf) == 0; } Test(control_cmds, test_listfiles) { const gchar *response; const gchar *db_file = "/opt/syslog-ng/var/db/patterndb.xml"; GString *expected = g_string_new(""); cfg_path_track_file(main_loop_get_current_config(main_loop), db_file, "path_check"); _run_command("LISTFILES", &response); g_string_printf(expected, "path_check: %s", db_file); cr_assert(first_line_eq(response, expected->str), "Bad reply: [%s]", response); g_string_free(expected, TRUE); } Test(control_cmds, test_log) { const gchar *response; _run_command("LOG", &response); cr_assert(first_line_eq(response, "FAIL Invalid arguments received"), "Bad reply: [%s]", response); _run_command("LOG fakelog", &response); cr_assert(first_line_eq(response, "FAIL Invalid arguments received"), "Bad reply: [%s]", response); msg_set_log_level(0); _run_command("LOG VERBOSE", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 0"), "Bad reply: [%s]", response); _run_command("LOG VERBOSE ON", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 1"), "Bad reply: [%s]", response); cr_assert_eq(verbose_flag, 1, "Flag isn't changed"); _run_command("LOG VERBOSE OFF", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 0"), "Bad reply: [%s]", response); cr_assert_eq(verbose_flag, 0, "Flag isn't changed"); msg_set_log_level(1); _run_command("LOG DEBUG", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 1"), "Bad reply: [%s]", response); _run_command("LOG DEBUG ON", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 2"), "Bad reply: [%s]", response); cr_assert_eq(debug_flag, 1, "Flag isn't changed"); _run_command("LOG DEBUG OFF", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 1"), "Bad reply: [%s]", response); cr_assert_eq(debug_flag, 0, "Flag isn't changed"); msg_set_log_level(2); _run_command("LOG TRACE", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 2"), "Bad reply: [%s]", response); _run_command("LOG TRACE ON", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 3"), "Bad reply: [%s]", response); cr_assert_eq(trace_flag, 1, "Flag isn't changed"); _run_command("LOG TRACE OFF", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 2"), "Bad reply: [%s]", response); cr_assert_eq(trace_flag, 0, "Flag isn't changed"); } Test(control_cmds, test_log_level) { const gchar *response; msg_set_log_level(0); _run_command("LOG LEVEL foo", &response); cr_assert(first_line_eq(response, "FAIL Invalid arguments received"), "Bad reply: [%s]", response); msg_set_log_level(0); _run_command("LOG LEVEL debug", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 2"), "Bad reply: [%s]", response); msg_set_log_level(1); _run_command("LOG LEVEL", &response); cr_assert(first_line_eq(response, "OK syslog-ng log level set to 1"), "Bad reply: [%s]", response); } Test(control_cmds, test_stats) { StatsCounterItem *counter = NULL; gchar **stats_result; const gchar *response; stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, "id", "received" ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); stats_unlock(); _run_command("STATS", &response); stats_result = g_strsplit(response, "\n", 2); cr_assert_str_eq(stats_result[0], "SourceName;SourceId;SourceInstance;State;Type;Number", "Bad reply"); g_strfreev(stats_result); } Test(control_cmds, test_reset_stats) { StatsCounterItem *counter = NULL; const gchar *response; stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, "id", "received" ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); stats_counter_set(counter, 666); stats_unlock(); _run_command("RESET_STATS", &response); cr_assert(first_line_eq(response, "OK The statistics of syslog-ng have been reset to 0."), "Bad reply"); _run_command("STATS", &response); cr_assert_str_eq(response, "SourceName;SourceId;SourceInstance;State;Type;Number\ncenter;id;received;a;processed;0\n.\n", "Bad reply"); } static void _original_replace(ControlConnection *cc, GString *result, gpointer user_data, gboolean *cancelled) { } static void _new_replace(ControlConnection *cc, GString *result, gpointer user_data, gboolean *cancelled) { } static void _assert_control_command_eq(ControlCommand *cmd, ControlCommand *cmd_other) { cr_assert_eq(cmd->func, cmd_other->func); cr_assert_str_eq(cmd->command_name, cmd_other->command_name); cr_assert_eq(cmd->user_data, cmd_other->user_data); } Test(control_cmds, test_replace_existing_command) { control_register_command("REPLACE", _original_replace, (gpointer)0xbaadf00d, FALSE); ControlCommand *cmd = control_find_command("REPLACE"); ControlCommand expected_original = { .func = _original_replace, .command_name = "REPLACE", .user_data = (gpointer)0xbaadf00d }; _assert_control_command_eq(cmd, &expected_original); control_replace_command("REPLACE", _new_replace, (gpointer)0xd006f00d, FALSE); ControlCommand *new_cmd = control_find_command("REPLACE"); ControlCommand expected_new = { .func = _new_replace, .command_name = "REPLACE", .user_data = (gpointer) 0xd006f00d }; _assert_control_command_eq(new_cmd, &expected_new); } Test(control_cmds, test_replace_non_existing_command) { control_replace_command("REPLACE", _new_replace, (gpointer)0xd006f00d, FALSE); ControlCommand *new_cmd = control_find_command("REPLACE"); ControlCommand expected_new = { .func = _new_replace, .command_name = "REPLACE", .user_data = (gpointer) 0xd006f00d }; _assert_control_command_eq(new_cmd, &expected_new); } syslog-ng-syslog-ng-4.4.0/lib/crypto.c000066400000000000000000000046551450431004300176170ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ /* This file becomes part of libsyslog-ng-crypto.so, the shared object * that contains all crypto related stuff to be used by plugins. This * includes the TLS wrappers, random number initialization, and so on. */ #include "crypto.h" #include "apphook.h" #include "thread-utils.h" #include "compat/openssl_support.h" #include #include #include #include #include static gboolean randfile_loaded; void crypto_deinit(void) { char rnd_file[256]; if (randfile_loaded) { RAND_file_name(rnd_file, sizeof(rnd_file)); if (rnd_file[0]) RAND_write_file(rnd_file); } #if OPENSSL_VERSION_NUMBER < 0x10100000L ERR_free_strings(); EVP_cleanup(); #endif openssl_crypto_deinit_threading(); } void crypto_init(void) { openssl_init(); openssl_crypto_init_threading(); if (getenv("RANDFILE")) { char rnd_file[256]; RAND_file_name(rnd_file, sizeof(rnd_file)); if (rnd_file[0]) { RAND_load_file(rnd_file, -1); randfile_loaded = TRUE; if (RAND_status() < 0) { fprintf(stderr, "ERROR: a trusted random number source is not available, crypto operations will probably fail. This could be due to the lack of entropy in the RANDFILE or due to insufficient entropy provided by system sources."); g_assert_not_reached(); } } } } syslog-ng-syslog-ng-4.4.0/lib/crypto.h000066400000000000000000000021611450431004300176120ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef CRYPTO_H_INCLUDED #define CRYPTO_H_INCLUDED #include "syslog-ng.h" void crypto_init(void); void crypto_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/debugger/000077500000000000000000000000001450431004300177055ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/debugger/CMakeLists.txt000066400000000000000000000004031450431004300224420ustar00rootroot00000000000000set(DEBUGGER_HEADERS debugger/debugger.h debugger/tracer.h debugger/debugger-main.h PARENT_SCOPE) set(DEBUGGER_SOURCES debugger/debugger.c debugger/tracer.c debugger/debugger-main.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/debugger/Makefile.am000066400000000000000000000005371450431004300217460ustar00rootroot00000000000000debuggerincludedir = ${pkgincludedir}/debugger EXTRA_DIST += lib/debugger/CMakeLists.txt debuggerinclude_HEADERS = \ lib/debugger/debugger.h \ lib/debugger/tracer.h \ lib/debugger/debugger-main.h debugger_sources = \ lib/debugger/debugger.c \ lib/debugger/tracer.c \ lib/debugger/debugger-main.c include lib/debugger/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/debugger/debugger-main.c000066400000000000000000000032551450431004300225640ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "debugger/debugger.h" #include "logpipe.h" static Debugger *current_debugger; static gboolean _pipe_hook(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { if ((s->flags & PIF_CONFIG_RELATED) == 0) return TRUE; if (msg->flags & LF_STATE_TRACING) return debugger_perform_tracing(current_debugger, s, msg); else return debugger_stop_at_breakpoint(current_debugger, s, msg); } void debugger_start(MainLoop *main_loop, GlobalConfig *cfg) { /* we don't support threaded mode (yet), force it to non-threaded */ cfg->threaded = FALSE; current_debugger = debugger_new(main_loop, cfg); pipe_single_step_hook = _pipe_hook; debugger_start_console(current_debugger); } syslog-ng-syslog-ng-4.4.0/lib/debugger/debugger-main.h000066400000000000000000000022601450431004300225640ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DEBUGGER_DEBUGGER_MAIN_H_INCLUDED #define DEBUGGER_DEBUGGER_MAIN_H_INCLUDED 1 #include "debugger/debugger.h" #include "cfg.h" void debugger_start(MainLoop *main_loop, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/debugger/debugger.c000066400000000000000000000252501450431004300216410ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "debugger/debugger.h" #include "debugger/tracer.h" #include "logmsg/logmsg.h" #include "logpipe.h" #include "apphook.h" #include "mainloop.h" #include "timeutils/misc.h" #include "compat/time.h" #include #include struct _Debugger { Tracer *tracer; MainLoop *main_loop; GlobalConfig *cfg; gchar *command_buffer; LogTemplate *display_template; LogMessage *current_msg; LogPipe *current_pipe; gboolean drop_current_message; struct timespec last_trace_event; }; static gboolean _format_nvpair(NVHandle handle, const gchar *name, const gchar *value, gssize length, LogMessageValueType type, gpointer user_data) { if (type == LM_VT_BYTES || type == LM_VT_PROTOBUF) { printf("%s=", name); for (gssize i = 0; i < length; i++) { const guchar b = (const guchar) value[i]; printf("%02hhx", b); } printf("\n"); return FALSE; } printf("%s=%.*s\n", name, (gint) length, value); return FALSE; } static void _display_msg_details(Debugger *self, LogMessage *msg) { GString *output = g_string_sized_new(128); log_msg_values_foreach(msg, _format_nvpair, NULL); g_string_truncate(output, 0); log_msg_format_tags(msg, output); printf("TAGS=%s\n", output->str); printf("\n"); g_string_free(output, TRUE); } static void _display_msg_with_template(Debugger *self, LogMessage *msg, LogTemplate *template) { GString *output = g_string_sized_new(128); log_template_format(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, output); printf("%s\n", output->str); g_string_free(output, TRUE); } static gboolean _display_msg_with_template_string(Debugger *self, LogMessage *msg, const gchar *template_string, GError **error) { LogTemplate *template; template = log_template_new(self->cfg, NULL); if (!log_template_compile(template, template_string, error)) { return FALSE; } _display_msg_with_template(self, msg, template); log_template_unref(template); return TRUE; } static void _display_source_line(LogExprNode *expr_node) { FILE *f; gint lineno = 1; gchar buf[1024]; if (!expr_node || !expr_node->filename) return; f = fopen(expr_node->filename, "r"); if (f) { while (fgets(buf, sizeof(buf), f) && lineno < expr_node->line) lineno++; if (lineno != expr_node->line) buf[0] = 0; fclose(f); } else { buf[0] = 0; } printf("%-8d %s", expr_node->line, buf); if (buf[0] == 0 || buf[strlen(buf) - 1] != '\n') putc('\n', stdout); fflush(stdout); } static gboolean _cmd_help(Debugger *self, gint argc, gchar *argv[]) { printf("syslog-ng interactive console, the following commands are available\n\n" " help, h, or ? Display this help\n" " info Display information about the current execution state\n" " continue or c Continue until the next breakpoint\n" " trace Display timing information as the message traverses the config\n" " print, p Print the current log message\n" " drop, d Drop the current message\n" " quit, q Tell syslog-ng to exit\n" ); return TRUE; } static gboolean _cmd_continue(Debugger *self, gint argc, gchar *argv[]) { return FALSE; } static gboolean _cmd_print(Debugger *self, gint argc, gchar *argv[]) { if (argc == 1) _display_msg_details(self, self->current_msg); else if (argc == 2) { GError *error = NULL; if (!_display_msg_with_template_string(self, self->current_msg, argv[1], &error)) { printf("print: %s\n", error->message); g_clear_error(&error); } } else printf("print: expected no arguments or exactly one\n"); return TRUE; } static gboolean _cmd_display(Debugger *self, gint argc, gchar *argv[]) { if (argc == 2) { GError *error = NULL; if (!log_template_compile(self->display_template, argv[1], &error)) { printf("display: Error compiling template: %s\n", error->message); g_clear_error(&error); return TRUE; } } printf("display: The template is set to: \"%s\"\n", self->display_template->template_str); return TRUE; } static gboolean _cmd_drop(Debugger *self, gint argc, gchar *argv[]) { self->drop_current_message = TRUE; return FALSE; } static gboolean _cmd_trace(Debugger *self, gint argc, gchar *argv[]) { self->current_msg->flags |= LF_STATE_TRACING; return FALSE; } static gboolean _cmd_quit(Debugger *self, gint argc, gchar *argv[]) { main_loop_exit(self->main_loop); self->drop_current_message = TRUE; return FALSE; } static gboolean _cmd_info_pipe(Debugger *self, LogPipe *pipe) { gchar buf[1024]; printf("LogPipe %p at %s\n", pipe, log_expr_node_format_location(pipe->expr_node, buf, sizeof(buf))); _display_source_line(pipe->expr_node); return TRUE; } static gboolean _cmd_info(Debugger *self, gint argc, gchar *argv[]) { if (argc >= 2) { if (strcmp(argv[1], "pipe") == 0) return _cmd_info_pipe(self, self->current_pipe); } printf("info: List of info subcommands\n" "info pipe -- display information about the current pipe\n"); return TRUE; } typedef gboolean (*DebuggerCommandFunc)(Debugger *self, gint argc, gchar *argv[]); struct { const gchar *name; DebuggerCommandFunc command; } command_table[] = { { "help", _cmd_help }, { "h", _cmd_help }, { "?", _cmd_help }, { "continue", _cmd_continue }, { "c", _cmd_continue }, { "print", _cmd_print }, { "p", _cmd_print }, { "display", _cmd_display }, { "drop", _cmd_drop }, { "quit", _cmd_quit }, { "q", _cmd_quit }, { "trace", _cmd_trace }, { "info", _cmd_info }, { "i", _cmd_info }, { NULL, NULL } }; gchar * debugger_builtin_fetch_command(void) { gchar buf[1024]; gsize len; printf("(syslog-ng) "); fflush(stdout); if (!fgets(buf, sizeof(buf), stdin)) return NULL; /* strip NL */ len = strlen(buf); if (buf[len - 1] == '\n') { buf[len - 1] = 0; } return g_strdup(buf); } FetchCommandFunc fetch_command_func = debugger_builtin_fetch_command; void debugger_register_command_fetcher(FetchCommandFunc fetcher) { fetch_command_func = fetcher; } static void _fetch_command(Debugger *self) { gchar *command; command = fetch_command_func(); if (command && strlen(command) > 0) { if (self->command_buffer) g_free(self->command_buffer); self->command_buffer = command; } else { if (command) g_free(command); } } static gboolean _handle_command(Debugger *self) { gint argc; gchar **argv; GError *error = NULL; DebuggerCommandFunc command = NULL; if (!g_shell_parse_argv(self->command_buffer ? : "", &argc, &argv, &error)) { printf("%s\n", error->message); g_clear_error(&error); return TRUE; } for (gint i = 0; command_table[i].name; i++) { if (strcmp(command_table[i].name, argv[0]) == 0) { command = command_table[i].command; break; } } if (!command) { printf("Undefined command %s, try \"help\"\n", argv[0]); return TRUE; } gboolean result = command(self, argc, argv); g_strfreev(argv); return result; } static void _handle_interactive_prompt(Debugger *self) { gchar buf[1024]; LogPipe *current_pipe = self->current_pipe; printf("Breakpoint hit %s\n", log_expr_node_format_location(current_pipe->expr_node, buf, sizeof(buf))); _display_source_line(current_pipe->expr_node); _display_msg_with_template(self, self->current_msg, self->display_template); while (1) { _fetch_command(self); if (!_handle_command(self)) break; } printf("(continuing)\n"); } static gpointer _interactive_console_thread_func(Debugger *self) { app_thread_start(); printf("Waiting for breakpoint...\n"); while (1) { tracer_wait_for_breakpoint(self->tracer); _handle_interactive_prompt(self); tracer_resume_after_breakpoint(self->tracer); } app_thread_stop(); return NULL; } void debugger_start_console(Debugger *self) { g_thread_new(NULL, (GThreadFunc) _interactive_console_thread_func, self); } gboolean debugger_stop_at_breakpoint(Debugger *self, LogPipe *pipe_, LogMessage *msg) { self->drop_current_message = FALSE; self->current_msg = log_msg_ref(msg); self->current_pipe = log_pipe_ref(pipe_); tracer_stop_on_breakpoint(self->tracer); log_msg_unref(self->current_msg); log_pipe_unref(self->current_pipe); self->current_msg = NULL; self->current_pipe = NULL; return !self->drop_current_message; } gboolean debugger_perform_tracing(Debugger *self, LogPipe *pipe_, LogMessage *msg) { struct timespec ts, *prev_ts = &self->last_trace_event; gchar buf[1024]; clock_gettime(CLOCK_MONOTONIC, &ts); long diff = prev_ts->tv_sec == 0 ? 0 : timespec_diff_nsec(&ts, prev_ts); printf("[%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT" +%ld] Tracing %s\n", ts.tv_sec, ts.tv_nsec, diff, log_expr_node_format_location(pipe_->expr_node, buf, sizeof(buf))); *prev_ts = ts; return TRUE; } Debugger * debugger_new(MainLoop *main_loop, GlobalConfig *cfg) { Debugger *self = g_new0(Debugger, 1); self->main_loop = main_loop; self->tracer = tracer_new(cfg); self->cfg = cfg; self->display_template = log_template_new(cfg, NULL); self->command_buffer = g_strdup("help"); log_template_compile(self->display_template, "$DATE $HOST $MSGHDR$MSG", NULL); return self; } void debugger_free(Debugger *self) { log_template_unref(self->display_template); tracer_free(self->tracer); g_free(self->command_buffer); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/debugger/debugger.h000066400000000000000000000031571450431004300216500ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DEBUGGER_DEBUGGER_H_INCLUDED #define DEBUGGER_DEBUGGER_H_INCLUDED 1 #include "syslog-ng.h" #include "cfg.h" #include "mainloop.h" typedef struct _Debugger Debugger; typedef gchar *(*FetchCommandFunc)(void); Debugger *debugger_new(MainLoop *main_loop, GlobalConfig *cfg); void debugger_free(Debugger *self); gchar *debugger_builtin_fetch_command(void); void debugger_register_command_fetcher(FetchCommandFunc fetcher); void debugger_start_console(Debugger *self); gboolean debugger_perform_tracing(Debugger *self, LogPipe *pipe, LogMessage *msg); gboolean debugger_stop_at_breakpoint(Debugger *self, LogPipe *pipe, LogMessage *msg); #endif syslog-ng-syslog-ng-4.4.0/lib/debugger/tests/000077500000000000000000000000001450431004300210475ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/debugger/tests/CMakeLists.txt000066400000000000000000000000561450431004300236100ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test-debugger) syslog-ng-syslog-ng-4.4.0/lib/debugger/tests/Makefile.am000066400000000000000000000006211450431004300231020ustar00rootroot00000000000000lib_debugger_tests_TESTS = \ lib/debugger/tests/test_debugger EXTRA_DIST += lib/debugger/tests/CMakeLists.txt check_PROGRAMS += ${lib_debugger_tests_TESTS} lib_debugger_tests_test_debugger_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/debugger/tests lib_debugger_tests_test_debugger_LDADD = $(TEST_LDADD) lib_debugger_tests_test_debugger_SOURCES = \ lib/debugger/tests/test-debugger.c syslog-ng-syslog-ng-4.4.0/lib/debugger/tests/test-debugger.c000066400000000000000000000026631450431004300237630ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "debugger/debugger.h" #include "apphook.h" void setup(void) { app_startup(); configuration = cfg_new_snippet(); } void teardown(void) { cfg_free(configuration); } TestSuite(debugger, .init = setup, .fini = teardown); Test(debugger, test_debugger) { MainLoop *main_loop = main_loop_get_instance(); Debugger *debugger = debugger_new(main_loop, configuration); debugger_free(debugger); } syslog-ng-syslog-ng-4.4.0/lib/debugger/tracer.c000066400000000000000000000043321450431004300213330ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "debugger/tracer.h" void tracer_stop_on_breakpoint(Tracer *self) { g_mutex_lock(&self->breakpoint_mutex); /* send break point */ self->breakpoint_hit = TRUE; g_cond_signal(&self->breakpoint_cond); /* wait for resume */ while (!self->resume_requested) g_cond_wait(&self->resume_cond, &self->breakpoint_mutex); self->resume_requested = FALSE; g_mutex_unlock(&self->breakpoint_mutex); } void tracer_wait_for_breakpoint(Tracer *self) { g_mutex_lock(&self->breakpoint_mutex); while (!self->breakpoint_hit) g_cond_wait(&self->breakpoint_cond, &self->breakpoint_mutex); self->breakpoint_hit = FALSE; g_mutex_unlock(&self->breakpoint_mutex); } void tracer_resume_after_breakpoint(Tracer *self) { g_mutex_lock(&self->breakpoint_mutex); self->resume_requested = TRUE; g_cond_signal(&self->resume_cond); g_mutex_unlock(&self->breakpoint_mutex); } Tracer * tracer_new(GlobalConfig *cfg) { Tracer *self = g_new0(Tracer, 1); g_mutex_init(&self->breakpoint_mutex); g_cond_init(&self->breakpoint_cond); g_cond_init(&self->resume_cond); return self; } void tracer_free(Tracer *self) { g_mutex_clear(&self->breakpoint_mutex); g_cond_clear(&self->breakpoint_cond); g_cond_clear(&self->resume_cond); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/debugger/tracer.h000066400000000000000000000027101450431004300213360ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DEBUGGER_TRACER_H_INCLUDED #define DEBUGGER_TRACER_H_INCLUDED 1 #include "syslog-ng.h" typedef struct _Tracer { GMutex breakpoint_mutex; GCond breakpoint_cond; GCond resume_cond; gboolean breakpoint_hit; gboolean resume_requested; } Tracer; void tracer_stop_on_breakpoint(Tracer *self); void tracer_wait_for_breakpoint(Tracer *self); void tracer_resume_after_breakpoint(Tracer *self); Tracer *tracer_new(GlobalConfig *cfg); void tracer_free(Tracer *self); #endif syslog-ng-syslog-ng-4.4.0/lib/dnscache.c000066400000000000000000000315251450431004300200430ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "dnscache.h" #include "messages.h" #include "timeutils/cache.h" #include "tls-support.h" #include #include #include #include #include #include #include #include #include #include typedef struct _DNSCacheEntry DNSCacheEntry; typedef struct _DNSCacheKey DNSCacheKey; struct _DNSCacheKey { gint family; union { struct in_addr ip; #if SYSLOG_NG_ENABLE_IPV6 struct in6_addr ip6; #endif } addr; }; struct _DNSCacheEntry { struct iv_list_head list; DNSCacheKey key; time_t resolved; gchar *hostname; gsize hostname_len; /* whether this entry is a positive (successful DNS lookup) or negative (failed DNS lookup, contains an IP address) match */ gboolean positive; }; struct _DNSCache { GHashTable *cache; const DNSCacheOptions *options; struct iv_list_head cache_list; struct iv_list_head persist_list; gint persistent_count; time_t hosts_mtime; time_t hosts_checktime; }; static gboolean dns_cache_key_equal(DNSCacheKey *e1, DNSCacheKey *e2) { if (e1->family == e2->family) { if ((e1->family == AF_INET && memcmp(&e1->addr.ip, &e2->addr.ip, sizeof(e1->addr.ip)) == 0)) return TRUE; #if SYSLOG_NG_ENABLE_IPV6 if ((e1->family == AF_INET6 && memcmp(&e1->addr.ip6, &e2->addr.ip6, sizeof(e1->addr.ip6)) == 0)) return TRUE; #endif } return FALSE; } static guint dns_cache_key_hash(DNSCacheKey *e) { if (e->family == AF_INET) { return ntohl(e->addr.ip.s_addr); } #if SYSLOG_NG_ENABLE_IPV6 else if (e->family == AF_INET6) { guint32 *a32 = (guint32 *) &e->addr.ip6.s6_addr; return (0x80000000 | (a32[0] ^ a32[1] ^ a32[2] ^ a32[3])); } #endif else { g_assert_not_reached(); return 0; } } static void dns_cache_entry_free(DNSCacheEntry *e) { iv_list_del(&e->list); g_free(e->hostname); g_free(e); } static inline void dns_cache_fill_key(DNSCacheKey *key, gint family, void *addr) { key->family = family; switch (family) { case AF_INET: key->addr.ip = *(struct in_addr *) addr; break; #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: key->addr.ip6 = *(struct in6_addr *) addr; break; #endif default: g_assert_not_reached(); break; } } static void dns_cache_store(DNSCache *self, gboolean persistent, gint family, void *addr, const gchar *hostname, gboolean positive) { DNSCacheEntry *entry; guint hash_size; entry = g_new(DNSCacheEntry, 1); dns_cache_fill_key(&entry->key, family, addr); entry->hostname = g_strdup(hostname); entry->hostname_len = strlen(hostname); entry->positive = positive; INIT_IV_LIST_HEAD(&entry->list); if (!persistent) { entry->resolved = cached_g_current_time_sec(); iv_list_add(&entry->list, &self->cache_list); } else { entry->resolved = 0; iv_list_add(&entry->list, &self->persist_list); } hash_size = g_hash_table_size(self->cache); g_hash_table_replace(self->cache, &entry->key, entry); if (persistent && hash_size != g_hash_table_size(self->cache)) self->persistent_count++; /* persistent elements are not counted */ if ((gint) (g_hash_table_size(self->cache) - self->persistent_count) > self->options->cache_size) { DNSCacheEntry *entry_to_remove = iv_list_entry(self->cache_list.next, DNSCacheEntry, list); /* remove oldest element */ g_hash_table_remove(self->cache, &entry_to_remove->key); } } void dns_cache_store_persistent(DNSCache *self, gint family, void *addr, const gchar *hostname) { dns_cache_store(self, TRUE, family, addr, hostname, TRUE); } void dns_cache_store_dynamic(DNSCache *self, gint family, void *addr, const gchar *hostname, gboolean positive) { dns_cache_store(self, FALSE, family, addr, hostname, positive); } static void dns_cache_cleanup_persistent_hosts(DNSCache *self) { struct iv_list_head *ilh, *ilh2; iv_list_for_each_safe(ilh, ilh2, &self->persist_list) { DNSCacheEntry *entry = iv_list_entry(ilh, DNSCacheEntry, list); g_hash_table_remove(self->cache, &entry->key); self->persistent_count--; } } static void dns_cache_check_hosts(DNSCache *self, glong t) { struct stat st; if (G_LIKELY(self->hosts_checktime == t)) return; self->hosts_checktime = t; if (!self->options->hosts || stat(self->options->hosts, &st) < 0) { dns_cache_cleanup_persistent_hosts(self); return; } if (self->hosts_mtime == -1 || st.st_mtime > self->hosts_mtime) { FILE *hosts; self->hosts_mtime = st.st_mtime; dns_cache_cleanup_persistent_hosts(self); hosts = fopen(self->options->hosts, "r"); if (hosts) { gchar buf[4096]; char *strtok_saveptr; while (fgets(buf, sizeof(buf), hosts)) { gchar *p, *ip; gint len; gint family; union { struct in_addr ip4; #if SYSLOG_NG_ENABLE_IPV6 struct in6_addr ip6; #endif } ia; if (buf[0] == 0 || buf[0] == '\n' || buf[0] == '#') continue; len = strlen(buf); if (buf[len - 1] == '\n') buf[len-1] = 0; p = strtok_r(buf, " \t", &strtok_saveptr); if (!p) continue; ip = p; #if SYSLOG_NG_ENABLE_IPV6 if (strchr(ip, ':') != NULL) family = AF_INET6; else #endif family = AF_INET; p = strtok_r(NULL, " \t", &strtok_saveptr); if (!p) continue; inet_pton(family, ip, &ia); dns_cache_store_persistent(self, family, &ia, p); } fclose(hosts); } else { msg_error("Error loading dns cache hosts file", evt_tag_str("filename", self->options->hosts), evt_tag_error("error")); } } } /* * @hostname is set to the stored hostname, * @positive is set whether the match was a DNS match or failure * * Returns TRUE if the cache was able to serve the request (e.g. had a * matching entry at all). */ gboolean dns_cache_lookup(DNSCache *self, gint family, void *addr, const gchar **hostname, gsize *hostname_len, gboolean *positive) { DNSCacheKey key; DNSCacheEntry *entry; time_t now; now = cached_g_current_time_sec(); dns_cache_check_hosts(self, now); dns_cache_fill_key(&key, family, addr); entry = g_hash_table_lookup(self->cache, &key); if (entry) { if (entry->resolved && ((entry->positive && entry->resolved < now - self->options->expire) || (!entry->positive && entry->resolved < now - self->options->expire_failed))) { /* the entry is not persistent and is too old */ } else { *hostname = entry->hostname; *hostname_len = entry->hostname_len; *positive = entry->positive; return TRUE; } } *hostname = NULL; *positive = FALSE; return FALSE; } DNSCache * dns_cache_new(const DNSCacheOptions *options) { DNSCache *self = g_new0(DNSCache, 1); self->cache = g_hash_table_new_full((GHashFunc) dns_cache_key_hash, (GEqualFunc) dns_cache_key_equal, NULL, (GDestroyNotify) dns_cache_entry_free); INIT_IV_LIST_HEAD(&self->cache_list); INIT_IV_LIST_HEAD(&self->persist_list); self->hosts_mtime = -1; self->hosts_checktime = 0; self->persistent_count = 0; self->options = options; return self; } void dns_cache_free(DNSCache *self) { g_hash_table_destroy(self->cache); g_free(self); } void dns_cache_options_defaults(DNSCacheOptions *options) { options->cache_size = 1007; options->expire = 3600; options->expire_failed = 60; options->hosts = NULL; } void dns_cache_options_destroy(DNSCacheOptions *options) { g_free(options->hosts); options->hosts = NULL; } /************************************************************************** * The global API that manages DNSCache instances on its own. Callers need * not be aware of underlying data structures and locking, they can simply * call these functions to lookup/query the DNS cache. * * I would prefer these to be moved into a higher level implementation * detail. **************************************************************************/ TLS_BLOCK_START { DNSCache *dns_cache; } TLS_BLOCK_END; #define dns_cache __tls_deref(dns_cache) /* DNS cache related options are global, independent of the configuration * (e.g. GlobalConfig instance), and they are stored in the * "effective_dns_cache_options" variable below. * * The reasons for using the global variable are as explained below. * * Some notes: * 1) DNS cache contents are better retained between configuration reloads * 2) There are multiple DNSCache instances as they are per-thread data structs. * * The usual pattern would be: * DNSCache->options -> DNSCacheOptions * * And options would be a reference and would point inside a DNSCacheOptions * instance contained within the GlobalConfig. * * The problem with this approach is that we don't want to recreate DNSCache * instances when reloading the configuration (as we want to keep their * config), and this would mean that we'd have to update the "options" * pointers in each of the existing instances. And those instances are * per-thread variables, making it a bit more difficult to track them. * * For this reason, it was a lot simpler to use a global variable to hold * configuration options, one that can be updated as the configuration is * reloaded. Then DNSCache instances transparently take the options changes * into account as they continue to resolve names. * * I could come up with even better solutions to this problem (like using a * layer above GlobalConfig, a state that encapsulates per-execution state * of syslog-ng), however, right now that would be an overkill and I want to * get the DNSCache refactors into the master tree. */ static DNSCacheOptions effective_dns_cache_options; G_LOCK_DEFINE_STATIC(unused_dns_caches); static GList *unused_dns_caches; gboolean dns_caching_lookup(gint family, void *addr, const gchar **hostname, gsize *hostname_len, gboolean *positive) { return dns_cache_lookup(dns_cache, family, addr, hostname, hostname_len, positive); } void dns_caching_store(gint family, void *addr, const gchar *hostname, gboolean positive) { dns_cache_store_dynamic(dns_cache, family, addr, hostname, positive); } void dns_caching_update_options(const DNSCacheOptions *new_options) { DNSCacheOptions *options = &effective_dns_cache_options; if (options->hosts) g_free(options->hosts); options->cache_size = new_options->cache_size; options->expire = new_options->expire; options->expire_failed = new_options->expire_failed; options->hosts = g_strdup(new_options->hosts); } void dns_caching_thread_init(void) { g_assert(dns_cache == NULL); G_LOCK(unused_dns_caches); if (unused_dns_caches) { dns_cache = unused_dns_caches->data; unused_dns_caches = g_list_delete_link(unused_dns_caches, unused_dns_caches); } G_UNLOCK(unused_dns_caches); if (!dns_cache) dns_cache = dns_cache_new(&effective_dns_cache_options); } void dns_caching_thread_deinit(void) { g_assert(dns_cache != NULL); G_LOCK(unused_dns_caches); unused_dns_caches = g_list_prepend(unused_dns_caches, dns_cache); G_UNLOCK(unused_dns_caches); dns_cache = NULL; } void dns_caching_global_init(void) { dns_cache_options_defaults(&effective_dns_cache_options); } void dns_caching_global_deinit(void) { G_LOCK(unused_dns_caches); g_list_foreach(unused_dns_caches, (GFunc) dns_cache_free, NULL); g_list_free(unused_dns_caches); unused_dns_caches = NULL; G_UNLOCK(unused_dns_caches); dns_cache_options_destroy(&effective_dns_cache_options); } syslog-ng-syslog-ng-4.4.0/lib/dnscache.h000066400000000000000000000043211450431004300200420ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DNSCACHE_H_INCLUDED #define DNSCACHE_H_INCLUDED #include "syslog-ng.h" typedef struct { gint cache_size; gint expire; gint expire_failed; gchar *hosts; } DNSCacheOptions; typedef struct _DNSCache DNSCache; void dns_cache_store_persistent(DNSCache *self, gint family, void *addr, const gchar *hostname); void dns_cache_store_dynamic(DNSCache *self, gint family, void *addr, const gchar *hostname, gboolean positive); gboolean dns_cache_lookup(DNSCache *self, gint family, void *addr, const gchar **hostname, gsize *hostname_len, gboolean *positive); DNSCache *dns_cache_new(const DNSCacheOptions *options); void dns_cache_free(DNSCache *self); void dns_cache_options_defaults(DNSCacheOptions *options); void dns_cache_options_destroy(DNSCacheOptions *options); gboolean dns_caching_lookup(gint family, void *addr, const gchar **hostname, gsize *hostname_len, gboolean *positive); void dns_caching_store(gint family, void *addr, const gchar *hostname, gboolean positive); void dns_caching_update_options(const DNSCacheOptions *dns_cache_options); void dns_caching_thread_init(void); void dns_caching_thread_deinit(void); void dns_caching_global_init(void); void dns_caching_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/driver.c000066400000000000000000000312561450431004300175670ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "driver.h" #include "logqueue-fifo.h" #include "afinter.h" #include "cfg-tree.h" #include "messages.h" #include /* LogDriverPlugin */ void log_driver_plugin_free_method(LogDriverPlugin *self) { g_free(self); } void log_driver_plugin_init_instance(LogDriverPlugin *self, const gchar *name) { self->name = name; self->free_fn = log_driver_plugin_free_method; } /* LogDriver */ gboolean log_driver_add_plugin(LogDriver *self, LogDriverPlugin *plugin) { g_assert(plugin->name); if (log_driver_lookup_plugin(self, plugin->name)) { msg_error("Another instance of this plugin is registered in this driver, unable to register plugin again", evt_tag_str("driver", self->id), evt_tag_str("plugin", plugin->name)); return FALSE; } self->plugins = g_list_append(self->plugins, plugin); return TRUE; } LogDriverPlugin * log_driver_lookup_plugin(LogDriver *self, const gchar *plugin_name) { for (GList *l = self->plugins; l; l = l->next) { LogDriverPlugin *plugin = (LogDriverPlugin *) l->data; if (strcmp(plugin->name, plugin_name) == 0) return plugin; } return NULL; } static gboolean log_driver_pre_init_method(LogPipe *s) { LogDriver *self = (LogDriver *) s; gboolean success = TRUE; GList *l; for (l = self->plugins; l; l = l->next) { if (!log_driver_plugin_attach((LogDriverPlugin *) l->data, self)) success = FALSE; } return success; } static void log_driver_post_deinit_method(LogPipe *s) { LogDriver *self = (LogDriver *) s; GList *l; for (l = self->plugins; l; l = l->next) { log_driver_plugin_detach((LogDriverPlugin *) l->data, self); } } gboolean log_driver_init_method(LogPipe *s) { return TRUE; } gboolean log_driver_deinit_method(LogPipe *s) { return TRUE; } /* NOTE: intentionally static, as only cDriver or LogDestDriver will derive from LogDriver */ static void log_driver_free(LogPipe *s) { LogDriver *self = (LogDriver *) s; GList *l; for (l = self->plugins; l; l = l->next) { log_driver_plugin_free((LogDriverPlugin *) l->data); } if (self->plugins) { g_list_free(self->plugins); } if (self->group) g_free(self->group); if (self->id) g_free(self->id); log_pipe_free_method(s); } /* NOTE: intentionally static, as only LogSrcDriver or LogDestDriver will derive from LogDriver */ static void log_driver_init_instance(LogDriver *self, GlobalConfig *cfg) { log_pipe_init_instance(&self->super, cfg); self->super.flags |= PIF_CONFIG_RELATED; self->super.free_fn = log_driver_free; self->super.pre_init = log_driver_pre_init_method; self->super.init = log_driver_init_method; self->super.deinit = log_driver_deinit_method; self->super.post_deinit = log_driver_post_deinit_method; } /* LogSrcDriver */ static gboolean log_src_driver_pre_init_method(LogPipe *s) { LogSrcDriver *self = (LogSrcDriver *) s; GlobalConfig *cfg = log_pipe_get_config(&self->super.super); if (!self->super.group) { self->super.group = cfg_tree_get_rule_name(&cfg->tree, ENC_SOURCE, s->expr_node); self->group_len = strlen(self->super.group); self->super.id = cfg_tree_get_child_id(&cfg->tree, ENC_SOURCE, s->expr_node); } return log_driver_pre_init_method(s); } static void _log_src_driver_register_counters(LogSrcDriver *self) { gint level = log_pipe_is_internal(&self->super.super) ? STATS_LEVEL3 : STATS_LEVEL0; stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_GROUP, self->super.group, NULL ); stats_register_counter(level, &sc_key, SC_TYPE_PROCESSED, &self->super.processed_group_messages); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, NULL, "received" ); stats_register_counter(level, &sc_key, SC_TYPE_PROCESSED, &self->received_global_messages); stats_unlock(); } gboolean log_src_driver_init_method(LogPipe *s) { LogSrcDriver *self = (LogSrcDriver *) s; if (!log_driver_init_method(s)) return FALSE; _log_src_driver_register_counters(self); return TRUE; } static void _log_src_driver_unregister_counters(LogSrcDriver *self) { stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_GROUP, self->super.group, NULL ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &self->super.processed_group_messages); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, NULL, "received" ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &self->received_global_messages); stats_unlock(); } gboolean log_src_driver_deinit_method(LogPipe *s) { LogSrcDriver *self = (LogSrcDriver *) s; if (!log_driver_deinit_method(s)) return FALSE; _log_src_driver_unregister_counters(self); return TRUE; } void log_src_driver_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSrcDriver *self = (LogSrcDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); /* $SOURCE */ if (msg->flags & LF_LOCAL) afinter_postpone_mark(cfg->mark_freq); log_msg_set_value(msg, LM_V_SOURCE, self->super.group, self->group_len); stats_counter_inc(self->super.processed_group_messages); stats_counter_inc(self->received_global_messages); log_pipe_forward_msg(s, msg, path_options); } void log_src_driver_init_instance(LogSrcDriver *self, GlobalConfig *cfg) { log_driver_init_instance(&self->super, cfg); self->super.super.pre_init = log_src_driver_pre_init_method; self->super.super.init = log_src_driver_init_method; self->super.super.deinit = log_src_driver_deinit_method; self->super.super.queue = log_src_driver_queue_method; self->super.super.flags |= PIF_SOURCE; } void log_src_driver_free(LogPipe *s) { log_driver_free(s); } /* LogDestDriver */ static LogQueue * _create_memory_queue(LogDestDriver *self, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super); gint log_fifo_size = self->log_fifo_size < 0 ? cfg->log_fifo_size : self->log_fifo_size; if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_22)) { msg_warning_once("WARNING: log-fifo-size() works differently starting with " VERSION_3_22 " to avoid dropping " "flow-controlled messages when log-fifo-size() is misconfigured. From now on, log-fifo-size() " "only affects messages that are not flow-controlled. (Flow-controlled log paths have the " "flags(flow-control) option set.) To enable the new behaviour, update the @version string in " "your configuration and consider lowering the value of log-fifo-size()."); return log_queue_fifo_legacy_new(log_fifo_size, persist_name, stats_level, driver_sck_builder, queue_sck_builder); } return log_queue_fifo_new(log_fifo_size, persist_name, stats_level, driver_sck_builder, queue_sck_builder); } /* returns a reference */ static LogQueue * log_dest_driver_acquire_memory_queue(LogDestDriver *self, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super); LogQueue *queue = NULL; if (persist_name) queue = cfg_persist_config_fetch(cfg, persist_name); if (queue && !log_queue_has_type(queue, log_queue_fifo_get_type())) { log_queue_unref(queue); queue = NULL; } if (!queue) { queue = _create_memory_queue(self, persist_name, stats_level, driver_sck_builder, queue_sck_builder); log_queue_set_throttle(queue, self->throttle); } return queue; } /* consumes the reference in @q */ static void log_dest_driver_release_queue_method(LogDestDriver *self, LogQueue *q) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super); /* we only save the LogQueue instance if it contains data */ if (q->persist_name && log_queue_keep_on_reload(q) > 0) { cfg_persist_config_add(cfg, q->persist_name, q, (GDestroyNotify) log_queue_unref); } else { log_queue_unref(q); } } void log_dest_driver_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogDestDriver *self = (LogDestDriver *) s; stats_counter_inc(self->super.processed_group_messages); stats_counter_inc(self->queued_global_messages); log_pipe_forward_msg(s, msg, path_options); } static gboolean log_dest_driver_pre_init_method(LogPipe *s) { LogDestDriver *self = (LogDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(&self->super.super); if (!self->super.group) { self->super.group = cfg_tree_get_rule_name(&cfg->tree, ENC_DESTINATION, s->expr_node); self->super.id = cfg_tree_get_child_id(&cfg->tree, ENC_DESTINATION, s->expr_node); } return log_driver_pre_init_method(s); } static void _log_dest_driver_register_counters(LogDestDriver *self) { gint level = log_pipe_is_internal(&self->super.super) ? STATS_LEVEL3 : STATS_LEVEL0; stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_DESTINATION | SCS_GROUP, self->super.group, NULL ); stats_register_counter(level, &sc_key, SC_TYPE_PROCESSED, &self->super.processed_group_messages); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, NULL, "queued" ); stats_register_counter(level, &sc_key, SC_TYPE_PROCESSED, &self->queued_global_messages); stats_unlock(); } gboolean log_dest_driver_init_method(LogPipe *s) { LogDestDriver *self = (LogDestDriver *) s; if (!log_driver_init_method(s)) return FALSE; _log_dest_driver_register_counters(self); return TRUE; } static void _log_dest_driver_unregister_counters(LogDestDriver *self) { stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_DESTINATION | SCS_GROUP, self->super.group, NULL ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &self->super.processed_group_messages); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_CENTER, NULL, "queued" ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &self->queued_global_messages); stats_unlock(); } gboolean log_dest_driver_deinit_method(LogPipe *s) { LogDestDriver *self = (LogDestDriver *) s; GList *l, *l_next; for (l = self->queues; l; l = l_next) { LogQueue *q = (LogQueue *) l->data; /* the GList struct will be freed by log_dest_driver_release_queue */ l_next = l->next; /* we have to pass a reference to log_dest_driver_release_queue(), * which automatically frees the ref on the list too */ log_dest_driver_release_queue(self, log_queue_ref(q)); } g_assert(self->queues == NULL); _log_dest_driver_unregister_counters(self); if (!log_driver_deinit_method(s)) return FALSE; return TRUE; } void log_dest_driver_init_instance(LogDestDriver *self, GlobalConfig *cfg) { log_driver_init_instance(&self->super, cfg); self->super.super.pre_init = log_dest_driver_pre_init_method; self->super.super.init = log_dest_driver_init_method; self->super.super.deinit = log_dest_driver_deinit_method; self->super.super.queue = log_dest_driver_queue_method; self->acquire_queue = log_dest_driver_acquire_memory_queue; self->release_queue = log_dest_driver_release_queue_method; self->log_fifo_size = -1; self->throttle = 0; } void log_dest_driver_free(LogPipe *s) { LogDestDriver *self = (LogDestDriver *) s; GList *l; for (l = self->queues; l; l = l->next) { log_queue_unref((LogQueue *) l->data); } g_list_free(self->queues); log_driver_free(s); } syslog-ng-syslog-ng-4.4.0/lib/driver.h000066400000000000000000000150361450431004300175720ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DRIVER_H_INCLUDED #define DRIVER_H_INCLUDED #include "syslog-ng.h" #include "logpipe.h" #include "logqueue.h" #include "cfg.h" /* * Drivers overview * ================ * * In syslog-ng nomenclature a driver is either responsible for handling * incoming messages (also known as source driver), or to send them out to * another party (also known as the destination driver). Source drivers are * created in "source" statements and destination drivers are similarly * created in "destination" statements. * * Drivers are derived from LogPipes, in essence they use the same "queue" * method to forward messages further down the processing pipeline. * * Driver plugins * ============== * * It is possible to change the behaviour of a driver somewhat by adding * "plugins" to drivers. These plugins basically get a chance to override * LogDriver virtual methods, change their semantics and possibly rely on * the original behaviour too. This way, functionalities that are present * in all destination drivers can easily be shared, without having to recode * the same stuff multiple times. * * Driver plugins are activated with the "attach" virtual method, which in * turn may redirect any of the LogDriver virtual methods to themselves. * They can even have a "user_data" pointer, so that they can locate their * associated state. * * Multiple plugins can hook into the same method, by saving the original * address & original user_data value. * */ /* direction agnostic driver class: LogDriver, see specialized source & destination drivers below */ typedef struct _LogDriver LogDriver; typedef struct _LogDriverPlugin LogDriverPlugin; struct _LogDriverPlugin { const gchar *name; /* this function is called when the plugin is attached to a LogDriver * instance. It should do whatever it is necessary to extend the * functionality of the driver specified (e.g. hook into various * methods). */ gboolean (*attach)(LogDriverPlugin *s, LogDriver *d); void (*detach)(LogDriverPlugin *s, LogDriver *d); void (*free_fn)(LogDriverPlugin *s); }; static inline gboolean log_driver_plugin_attach(LogDriverPlugin *self, LogDriver *d) { return self->attach(self, d); } static inline void log_driver_plugin_detach(LogDriverPlugin *self, LogDriver *d) { if (self->detach) self->detach(self, d); } static inline void log_driver_plugin_free(LogDriverPlugin *self) { self->free_fn(self); } void log_driver_plugin_init_instance(LogDriverPlugin *self, const gchar *name); void log_driver_plugin_free_method(LogDriverPlugin *self); struct _LogDriver { LogPipe super; gboolean optional; gchar *group; gchar *id; GList *plugins; StatsCounterItem *processed_group_messages; }; gboolean log_driver_add_plugin(LogDriver *self, LogDriverPlugin *plugin); void log_driver_append(LogDriver *self, LogDriver *next); LogDriverPlugin *log_driver_lookup_plugin(LogDriver *self, const gchar *name); #define log_driver_get_plugin(self, T, name) \ ({ \ T *plugin = (T *) log_driver_lookup_plugin(self, name); \ g_assert(plugin != NULL); \ plugin; \ }) /* methods registered to the init/deinit virtual functions */ gboolean log_driver_init_method(LogPipe *s); gboolean log_driver_deinit_method(LogPipe *s); /* source driver class: LogSourceDriver */ typedef struct _LogSrcDriver LogSrcDriver; struct _LogSrcDriver { LogDriver super; gint group_len; StatsCounterItem *received_global_messages; }; gboolean log_src_driver_init_method(LogPipe *s); gboolean log_src_driver_deinit_method(LogPipe *s); void log_src_driver_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options); void log_src_driver_init_instance(LogSrcDriver *self, GlobalConfig *cfg); void log_src_driver_free(LogPipe *s); /* destination driver class: LogDestDriver */ typedef struct _LogDestDriver LogDestDriver; struct _LogDestDriver { LogDriver super; LogQueue *(*acquire_queue)(LogDestDriver *s, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder); void (*release_queue)(LogDestDriver *s, LogQueue *q); /* queues managed by this LogDestDriver, all constructed queues come * here and are automatically saved into cfg_persist & persist_state. */ GList *queues; gint log_fifo_size; gint throttle; StatsCounterItem *queued_global_messages; }; /* returns a reference */ static inline LogQueue * log_dest_driver_acquire_queue(LogDestDriver *self, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { LogQueue *q; q = self->acquire_queue(self, persist_name, stats_level, driver_sck_builder, queue_sck_builder); if (q) { self->queues = g_list_prepend(self->queues, q); } return q; } /* consumes the reference in @q */ static inline void log_dest_driver_release_queue(LogDestDriver *self, LogQueue *q) { if (q) { self->queues = g_list_remove(self->queues, q); /* this drops the reference passed by the caller */ self->release_queue(self, q); /* this drops the reference stored on the list */ log_queue_unref(q); } } gboolean log_dest_driver_init_method(LogPipe *s); gboolean log_dest_driver_deinit_method(LogPipe *s); void log_dest_driver_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options); void log_dest_driver_init_instance(LogDestDriver *self, GlobalConfig *cfg); void log_dest_driver_free(LogPipe *s); #endif syslog-ng-syslog-ng-4.4.0/lib/dynamic-window-pool.c000066400000000000000000000043011450431004300221630ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * Copyright (c) 2019 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #include "dynamic-window-pool.h" DynamicWindowPool * dynamic_window_pool_new(gsize size) { DynamicWindowPool *self = g_new0(DynamicWindowPool, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->pool_size = size; return self; } void dynamic_window_pool_init(DynamicWindowPool *self) { self->free_window = self->pool_size; } DynamicWindowPool * dynamic_window_pool_ref(DynamicWindowPool *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) g_atomic_counter_inc(&self->ref_cnt); return self; } void dynamic_window_pool_unref(DynamicWindowPool *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && g_atomic_counter_dec_and_test(&self->ref_cnt)) { g_free(self); } } gsize dynamic_window_pool_request(DynamicWindowPool *self, gsize requested_size) { gsize offered = MIN(self->free_window, requested_size); self->free_window -= offered; return offered; } void dynamic_window_pool_release(DynamicWindowPool *self, gsize release_size) { self->free_window += release_size; g_assert(self->free_window <= self->pool_size); } syslog-ng-syslog-ng-4.4.0/lib/dynamic-window-pool.h000066400000000000000000000033131450431004300221720ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DYNAMIC_WINDOW_POOL_H_INCLUDED #define DYNAMIC_WINDOW_POOL_H_INCLUDED #include "syslog-ng.h" #include "atomic.h" typedef struct _DynamicWindowPool DynamicWindowPool; struct _DynamicWindowPool { GAtomicCounter ref_cnt; gsize pool_size; gsize free_window; gsize balanced_window; }; DynamicWindowPool *dynamic_window_pool_new(gsize iw_size); void dynamic_window_pool_init(DynamicWindowPool *self); DynamicWindowPool *dynamic_window_pool_ref(DynamicWindowPool *self); void dynamic_window_pool_unref(DynamicWindowPool *self); gsize dynamic_window_pool_request(DynamicWindowPool *self, gsize requested_size); void dynamic_window_pool_release(DynamicWindowPool *self, gsize release_size); #endif syslog-ng-syslog-ng-4.4.0/lib/dynamic-window.c000066400000000000000000000042161450431004300212210ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * Copyright (c) 2019 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "dynamic-window.h" void dynamic_window_stat_update(DynamicWindowStat *self, gsize value) { self->sum += value; self->n++; } void dynamic_window_stat_reset(DynamicWindowStat *self) { self->sum = 0; self->n = 0; } gsize dynamic_window_stat_get_avg(DynamicWindowStat *self) { if (self->n == 0) return 0; return self->sum / self->n; } gsize dynamic_window_stat_get_number_of_samples(DynamicWindowStat *self) { return self->n; } guint64 dynamic_window_stat_get_sum(DynamicWindowStat *self) { return self->sum; } void dynamic_window_set_pool(DynamicWindow *self, DynamicWindowPool *pool) { self->pool = pool; dynamic_window_stat_reset(&self->stat); } gboolean dynamic_window_is_enabled(DynamicWindow *self) { return !!self->pool; } gsize dynamic_window_request(DynamicWindow *self, gsize size) { if (!self->pool) return 0; return dynamic_window_pool_request(self->pool, size); } void dynamic_window_release(DynamicWindow *self, gsize size) { if (!self->pool) return; dynamic_window_pool_release(self->pool, size); } syslog-ng-syslog-ng-4.4.0/lib/dynamic-window.h000066400000000000000000000036771450431004300212400ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DYNAMIC_WINDOW_H_INCLUDED #define DYNAMIC_WINDOW_H_INCLUDED #include "syslog-ng.h" #include "dynamic-window-pool.h" typedef struct _DynamicWindow DynamicWindow; typedef struct _DynamicWindowStat DynamicWindowStat; struct _DynamicWindowStat { gsize n; guint64 sum; }; void dynamic_window_stat_update(DynamicWindowStat *self, gsize value); void dynamic_window_stat_reset(DynamicWindowStat *self); gsize dynamic_window_stat_get_avg(DynamicWindowStat *self); gsize dynamic_window_stat_get_number_of_samples(DynamicWindowStat *self); guint64 dynamic_window_stat_get_sum(DynamicWindowStat *self); struct _DynamicWindow { DynamicWindowPool *pool; DynamicWindowStat stat; }; void dynamic_window_set_pool(DynamicWindow *self, DynamicWindowPool *pool); gboolean dynamic_window_is_enabled(DynamicWindow *self); gsize dynamic_window_request(DynamicWindow *self, gsize size); void dynamic_window_release(DynamicWindow *self, gsize size); #endif syslog-ng-syslog-ng-4.4.0/lib/eventlog/000077500000000000000000000000001450431004300177445ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/eventlog/AUTHORS000066400000000000000000000001011450431004300210040ustar00rootroot00000000000000EventLog has been written by Balazs Scheidler syslog-ng-syslog-ng-4.4.0/lib/eventlog/CMakeLists.txt000066400000000000000000000005571450431004300225130ustar00rootroot00000000000000add_library(eventlog SHARED src/evtctx.c src/evtfmt.c src/evtout.c src/evtrec.c src/evtstr.c src/evtsyslog.c src/evttags.c ) target_include_directories(eventlog SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_link_libraries(eventlog PRIVATE GLib::GLib ) install(TARGETS eventlog DESTINATION lib) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/eventlog/COPYING000066400000000000000000000026241450431004300210030ustar00rootroot00000000000000 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of BalaBit nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syslog-ng-syslog-ng-4.4.0/lib/eventlog/CREDITS000066400000000000000000000003441450431004300207650ustar00rootroot00000000000000EventLog contains a couple of ideas which are based on the discussion on the log-analysis mailing list. Namely: Tina Bird Marcus J. Ranum Darren Reed marc Rainer Gerhards Thanks for their comments. syslog-ng-syslog-ng-4.4.0/lib/eventlog/ChangeLog000066400000000000000000000115211450431004300215160ustar00rootroot00000000000000# do not edit -- automatically generated by arch changelog # arch-tag: automatic-ChangeLog--bazsi@balabit.hu--bazsi-1/eventlog--mainline--1.0 # 2005-12-03 11:21:29 GMT Balazs Scheidler patch-9 Summary: some more build system specific fixes, eventlog can now be released with ZBS Revision: eventlog--mainline--1.0--patch-9 new files: .arch-ids/VERSION.id .arch-ids/dist.conf.in.id VERSION dist.conf.in modified files: ChangeLog Makefile.am NEWS configure.in debian/changelog.in renamed files: debian/.arch-ids/changelog.id ==> debian/.arch-ids/changelog.in.id debian/changelog ==> debian/changelog.in 2005-12-03 10:11:14 GMT Balazs Scheidler patch-8 Summary: added Debianization files, released 0.2.4 Revision: eventlog--mainline--1.0--patch-8 2005-12-03 Balazs Scheidler * configure.in: bumped to 0.2.4 * debian/*: added Debianization new files: .arch-ids/ChangeLog.id ChangeLog debian/.arch-ids/=id debian/.arch-ids/changelog.id debian/.arch-ids/compat.id debian/.arch-ids/control.id debian/.arch-ids/copyright.id debian/.arch-ids/libevtlog-dev.install.id debian/.arch-ids/libevtlog0.install.id debian/.arch-ids/libevtlog0.shlibs.id debian/.arch-ids/rules.id debian/changelog debian/compat debian/control debian/copyright debian/libevtlog-dev.install debian/libevtlog0.install debian/libevtlog0.shlibs debian/rules modified files: Makefile.am NEWS PORTS configure.in doc/DESIGN.txt renamed files: .arch-ids/ChangeLog.id ==> .arch-ids/ChangeLog.0.id ChangeLog ==> ChangeLog.0 new directories: debian debian/.arch-ids 2005-08-08 07:40:56 GMT Balazs Scheidler patch-7 Summary: added AUTHORS and cleaned up non-tla managed files by adding an .arch-inventory Revision: eventlog--mainline--1.0--patch-7 new files: .arch-ids/.arch-inventory.id .arch-inventory modified files: {arch}/=tagging-method 2005-08-08 07:39:15 GMT Balazs Scheidler patch-6 Summary: added AUTHORS file Revision: eventlog--mainline--1.0--patch-6 new files: .arch-ids/AUTHORS.id AUTHORS 2005-02-12 23:03:30 GMT Balazs Scheidler patch-5 Summary: Committed the version number change, however eventlog has been released earlier. Revision: eventlog--mainline--1.0--patch-5 removed files: .arch-ids/Makefile.in.id Makefile.in src/.arch-ids/Makefile.in.id src/Makefile.in tests/.arch-ids/Makefile.in.id tests/Makefile.in modified files: configure.in eventlog.pc.in 2005-01-16 14:54:22 GMT Balazs Scheidler patch-4 Summary: inherit CFLAGS from the environment Revision: eventlog--mainline--1.0--patch-4 modified files: configure.in 2005-01-16 14:51:11 GMT Balazs Scheidler patch-3 Summary: Added COPYING file Revision: eventlog--mainline--1.0--patch-3 new files: .arch-ids/COPYING.id COPYING modified files: README configure.in eventlog.pc.in 2004-12-27 23:28:34 GMT Balazs Scheidler patch-2 Summary: changed default context flags Revision: eventlog--mainline--1.0--patch-2 2004-12-28 Balazs Scheidler * evtctx.c (evt_ctx_init): set default flags not to add extra tags by default modified files: ChangeLog configure.in src/evtctx.c 2004-12-26 23:13:56 GMT Balazs Scheidler patch-1 Summary: Fixed memory leak and out-of-tree builds Revision: eventlog--mainline--1.0--patch-1 2004-12-27 Balazs Scheidler * evtctx.c (evt_ctx_free): fixed tag-hook leak * tests/Makefile.am: fixed out-of-tree builds modified files: ChangeLog src/evtctx.c tests/Makefile.am tests/Makefile.in 2004-12-26 20:41:48 GMT Balazs Scheidler base-0 Summary: initial import Revision: eventlog--mainline--1.0--base-0 (automatically generated log message) new files: CREDITS ChangeLog Makefile Makefile.am Makefile.in NEWS PORTS README aclocal.m4 autogen.sh configure.in doc/API.txt doc/DESIGN.txt doc/configuration.txt eventlog.pc.in questions src/Makefile src/Makefile.am src/Makefile.in src/evt_internals.h src/evtctx.c src/evtfmt.c src/evtlog.h src/evtmaps.h src/evtout.c src/evtrec.c src/evtstr.c src/evtsyslog.c src/evttags.c tests/Makefile tests/Makefile.am tests/Makefile.in tests/evtfmt.c tests/evtrec.c tests/evtsyslog.c syslog-ng-syslog-ng-4.4.0/lib/eventlog/ChangeLog.0000066400000000000000000000055251450431004300216630ustar00rootroot000000000000002004-12-28 Balazs Scheidler * evtctx.c (evt_ctx_init): set default flags not to add extra tags by default 2004-12-27 Balazs Scheidler * evtctx.c (evt_ctx_free): fixed tag-hook leak * tests/Makefile.am: fixed out-of-tree builds 2004-08-20 Balazs Scheidler * configure.in: bumped version number to 0.2 * configure.in: updated to autoconf 2.59 and automake 1.7.1, * src/evtlog.h: added support to several independent logging contexts, constructors directly return the constructed object instead of returning it through an argument, renamed evtstr_ prefix to evt_str_ to be more consistent, * src/evt_internals.h: renamed EVTCONFIG to EVTCONTEXT, made it reference counted, separated EVTSYSLOG from EVTCONTEXT, made it a separate global variable (as EVTCONFIG is not global anymore), reference counting functions are moved here (e.g. it is not publicly accessible) * src/*.c: followed changes in evtlog.h and evt_internals.h 2003-01-10 Balazs Scheidler * doc/API.txt: added doc on syslog compatibility * COPYING: changed to BSD license * src/evtout.c: instead of calling syslog() functions directly, call them through the function pointer * src/evtlog.h: added syslog compatibility by wrapper macros, only defined if EVENTLOG_SYSLOG_MACROS preprocessor symbol is defined * src/evtlog.c: call evt_syslog_wrapper_init() upon initialization * src/evt_internals.h: added EVTSYSLOG structure which contains function pointers for the libc syslog routines (it is needed to avoid direct calling of openlog, closelog, syslog as they might be defined inside the shared object) * src/evtsyslog.c: new file, contains the syslog-like functions and the dlsym based wrapper provided ENABLE_SYSLOG_WRAPPER is defined * configure.in: new configure option, --enable-syslog-wrapper which enables the dlsym based syslog() wrapper 2003-01-07 Balazs Scheidler * src/evt_internals.h (EVTTAG): et_prio member was dropped, log format is consistent, so it is easy to reorder tags at log analysis time * src/evtlog.h (evt_tag_*): removed prio argument, (evt_rec_ref): moved from internal to public API as it might be needed to avoid the free evt_log() does * src/evttags.c (evt_tag_*): removed prio argument * src/evtout.c (evt_log): the function consumes its argument, so no need for explicit free * src/evtmaps.h: removed priorities completely * src/evtrec.c: all tags are prepended to the list, no specific order is kept * tests/evtfmt.c, tests/evtrec.c: updated test programs * doc/configuration.txt: new file, contains the configuration file format * doc/DESIGN.txt: updated * doc/API.txt: updated 2003-01-06 Balazs Scheidler * configure.in: version 0.1 released * changelog started syslog-ng-syslog-ng-4.4.0/lib/eventlog/NEWS000066400000000000000000000030111450431004300204360ustar00rootroot00000000000000eventlog 0.2.8 Tue, 25 Mar 2008 21:03:00 +0100 Build system fixes. eventlog 0.2.7 Thu, 3 Jan 2008 13:27:28 +0100 Fixed eventlog.conf parsing to avoid crash for invalid syntax. eventlog 0.2.6 Mon, 30 Oct 2006 19:42:35 +0100 Added build scripts for RHEL3/4, Solaris, and AIX 5.2 eventlog 0.2.5 Sat, 15 Jul 2006 17:22:32 +0200 The order of tags is reversed. Previously eventlog generated messages with the tag ordering opposite of what the application requested. This is now fixed. eventlog 0.2.4 Sat, 03 Dec 2005 11:09:40 +0100 A proper release in a long time, syslog-ng itself relied on the latest snapshot until now. Added debianization files. ChangeLog is generated automatically based on tla commits. eventlog 0.1.2 Fri, 10 Jan 2003 10:15:48 +0100 Added two implementations of the syslog wrapper (macro and dlsym based). The dlsym() based can be enabled by configure-ing with the --enable-dlsym-wrapper option. The macro based can be used by defining the symbol EVENTLOG_SYSLOG_MACROS preprocessor symbol prior to including evtlog.h. eventlog 0.1.1 Tue, 7 Jan 2003 20:11:13 +0100 Incorporated first comments, evt_log now consumes its parameter, the tag ordering scheme was completely dropped. Also updated documentation, added a PORTS file and configuration.txt file eventlog 0.1 Mon, 6 Jan 2003 17:09:58 +0100 This is the initial release of eventlog, a structured event logging API. Not all features are implemented, but the basic building blocks are in place. syslog-ng-syslog-ng-4.4.0/lib/eventlog/doc/000077500000000000000000000000001450431004300205115ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/eventlog/doc/API.txt000066400000000000000000000043611450431004300216670ustar00rootroot00000000000000 Application Programming Interface --------------------------------- The EventLog library implements a set of functions to construct, format and output event records. The public symbols are defined in the header file named , for a list and documentation of functions please consult that file as it contains inline function descriptions in gtk-doc format. It is very important to use consistent tag naming and that different applications use identify the same data with the same tag name. Therefore please use the predefined tag name if one is available. Predefined tag names are defined in the header file . This header is included by therefore you will not need to reference it explicitly. A third header file named "evt_internals.h" is defines the internals of the EventLog library. Please do not depend on its contents and don't include it directly. As this header file is not meant to be used in applications, it is not installed when the library is installed. Syslog compatibility -------------------- Most UNIX systems and therefore the programs running under UNIX use the syslog() API found in the libc for logging. Because of the large installed base it is worth supporting legacy applications before they are converted to use EventLog. Two different implementations of syslog compatibility is provided: macro and linker based. * Macro based compatibility This works by defining the syslog() function names as macros to refer to the compatibility functions found in EventLog. To use the macro based wrapper you will need to recompile the program from source: $ cc -DEVENTLOG_SYSLOG_MACROS syslogapp.c -levtlog * Linker based compatibility Some dynamic linker implementations (most notably: Linux and Solaris) support symbol overloading. EventLog can use this feature if the dlsym() function is present which supports RTLD_NEXT to fetch symbols hidden by EventLog itself. To enable this wrapper configure EventLog with the --enable-dlsym-wrapper configure option. To use the wrapper you simply need to preload the event log shared object like: $ LD_PRELOAD=/usr/lib/libeventlog.so.0 syslogapp Where syslogapp is the program to be run. As you can see the application itself did not need to be recompiled.syslog-ng-syslog-ng-4.4.0/lib/eventlog/doc/DESIGN.txt000066400000000000000000000021041450431004300222200ustar00rootroot00000000000000Overview -------- This library was designed to support several event formats and multiple means of delivering messages. Therefore the process of sending a message to a log is separated to three independent parts: * Building the event record This is done by the application program using the library. It is a sequence of calling the following functions: evt_rec_init(...) evt_tag_str(...) / evt_tag_int(...) / evt_tag_printf(...) evt_log(...) /* consumes the log record, no need to free it */ The event record itself consists of the following properties: - a simple, constant human readable description of the event - an unordered set of tag/value pairs - a syslog compatible priority value (debug .. emerg) The record initialized by evt_rec_init() may contain a couple of tags by default (like pid, timestamp etc.) * Logging the event record The way an event record is sent to the log might also be customized by the administrator. Currently a single output method is implemented named 'local' which sends the message off by using syslog(). syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/000077500000000000000000000000001450431004300205335ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/Makefile.am000066400000000000000000000017041450431004300225710ustar00rootroot00000000000000 lib_LTLIBRARIES += lib/eventlog/src/libevtlog.la EXTRA_DIST += \ lib/eventlog/AUTHORS \ lib/eventlog/ChangeLog \ lib/eventlog/ChangeLog.0 \ lib/eventlog/CMakeLists.txt \ lib/eventlog/COPYING \ lib/eventlog/CREDITS \ lib/eventlog/doc \ lib/eventlog/doc/API.txt \ lib/eventlog/doc/DESIGN.txt \ lib/eventlog/NEWS lib_eventlog_src_libevtlog_la_SOURCES = \ lib/eventlog/src/evtrec.c \ lib/eventlog/src/evtfmt.c \ lib/eventlog/src/evtout.c \ lib/eventlog/src/evtstr.c \ lib/eventlog/src/evtctx.c \ lib/eventlog/src/evttags.c \ lib/eventlog/src/evtsyslog.c lib_eventlog_src_libevtlog_la_LDFLAGS = -no-undefined -release ${LSNG_RELEASE} \ -version-info ${LSNG_CURRENT}:${LSNG_REVISION}:${LSNG_AGE} lib_eventlog_src_libevtlog_la_CFLAGS = $(AM_CFLAGS) lib_eventlog_src_libevtlog_la_LIBADD = @GLIB_LIBS@ noinst_HEADERS = lib/eventlog/src/evt_internals.h pkginclude_HEADERS += \ lib/eventlog/src/evtmaps.h \ lib/eventlog/src/evtlog.h syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evt_internals.h000066400000000000000000000077351450431004300235750ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * EventLog library internal functions/typedefs. * * $Id: evt_internals.h,v 1.4 2004/08/20 19:46:28 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef __EVT_INTERNALS_H_INCLUDED #define __EVT_INTERNALS_H_INCLUDED #include "evtlog.h" #include #ifdef _MSC_VER #include #endif #include /* whether to add the given default tag */ #define EF_ADD_PID 0x0001 #define EF_ADD_PROG 0x0002 #define EF_ADD_ISOSTAMP 0x0004 #define EF_ADD_UTCSTAMP 0x0008 #define EF_ADD_TIMEZONE 0x0010 #define EF_ADD_MSGID 0x0020 #define EF_ADD_ALL 0x003F #define EF_INITIALIZED 0x8000 typedef struct __evttaghook EVTTAGHOOK; typedef struct __evtsyslogopts EVTSYSLOGOPTS; typedef struct __evtstr EVTSTR; struct __evtsyslogopts { void (*es_openlog)(const char *ident, int option, int facility); void (*es_closelog)(void); void (*es_syslog)(int priority, const char *format, ...) G_GNUC_PRINTF(2, 3); int es_options; }; struct __evtcontext { int ec_ref; char ec_formatter[32]; char *(*ec_formatter_fn)(EVTREC *e); char ec_outmethod[32]; int (*ec_outmethod_fn)(EVTREC *e); char *ec_prog; int ec_syslog_fac; EVTTAGHOOK *ec_tag_hooks; unsigned long ec_flags; }; struct __evttaghook { struct __evttaghook *et_next; int (*et_callback)(EVTREC *e, void *user_ptr); void *et_userptr; }; struct __evtrec { int ev_ref; int ev_syslog_pri; char *ev_desc; EVTTAG *ev_pairs; EVTTAG *ev_last_pair; EVTCONTEXT *ev_ctx; }; struct __evttag { EVTTAG *et_next; char *et_tag; char *et_value; }; struct __evtstr { size_t es_allocated; /* number of allocated characters in es_buf */ size_t es_length; /* length of string without trailing NUL */ char *es_buf; }; /* internal functions */ /* event context */ EVTCONTEXT *evt_ctx_ref(EVTCONTEXT *ctx); /* event records */ EVTREC *evt_rec_ref(EVTREC *e); /* event tag */ void evt_tag_free(EVTTAG *et); /* event strings */ EVTSTR *evt_str_init(size_t init_alloc); void evt_str_free(EVTSTR *es, int free_buf); int evt_str_append(EVTSTR *es, char *str); int evt_str_append_len(EVTSTR *es, char *str, size_t len); int evt_str_append_escape_bs(EVTSTR *es, char *unescaped, size_t unescaped_len, char escape_char); char *evt_str_get_str(EVTSTR *es); /* syslog linked wrapper */ extern EVTSYSLOGOPTS syslog_opts; void evt_syslog_wrapper_init(void); #endif syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtctx.c000066400000000000000000000103301450431004300222110ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtctx.c,v 1.3 2004/08/20 19:46:28 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * This is the main module which is responsible for managing the * configuration and to perform initialization. */ #include "evt_internals.h" #include #include #include #include #include #include #ifdef _MSC_VER #define getpid GetCurrentProcessId #endif static int evtrec_add_standard_tags(EVTREC *e, void *userptr) { time_t now; struct tm *tm = NULL; char buf[128]; EVTCONTEXT *ctx = e->ev_ctx; time(&now); if (ctx->ec_flags & EF_ADD_PID) evt_rec_add_tag(e, evt_tag_int(EVT_TAG_PID, (int) getpid())); if (ctx->ec_flags & EF_ADD_PROG) evt_rec_add_tag(e, evt_tag_str(EVT_TAG_PROG, ctx->ec_prog)); if (ctx->ec_flags & EF_ADD_ISOSTAMP) { tm = localtime(&now); strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", tm); evt_rec_add_tag(e, evt_tag_str(EVT_TAG_ISOSTAMP, buf)); } if (ctx->ec_flags & EF_ADD_UTCSTAMP) evt_rec_add_tag(e, evt_tag_int(EVT_TAG_UTCSTAMP, (int) now)); if (ctx->ec_flags & EF_ADD_TIMEZONE) { if (!tm) tm = localtime(&now); strftime(buf, sizeof(buf), "%z", tm); evt_rec_add_tag(e, evt_tag_str(EVT_TAG_TIMEZONE, buf)); } if (ctx->ec_flags & EF_ADD_MSGID) { evt_rec_add_tag(e, evt_tag_int(EVT_TAG_MSGID, 123456)); } return 1; } int evt_ctx_tag_hook_add(EVTCONTEXT *ctx, int (*func)(EVTREC *e, void *user_ptr), void *user_ptr) { EVTTAGHOOK *cb = malloc(sizeof(EVTTAGHOOK)); if (!cb) return 0; cb->et_callback = func; cb->et_userptr = user_ptr; cb->et_next = ctx->ec_tag_hooks; ctx->ec_tag_hooks = cb; return 1; } EVTCONTEXT * evt_ctx_init(const char *prog, int syslog_fac) { EVTCONTEXT *ctx; ctx = (EVTCONTEXT *) calloc(sizeof(*ctx), 1); if (ctx) { strcpy(ctx->ec_formatter, "plain"); strcpy(ctx->ec_outmethod, "local"); ctx->ec_ref = 1; ctx->ec_flags = EF_INITIALIZED; ctx->ec_prog = (char *) prog; ctx->ec_syslog_fac = syslog_fac; evt_ctx_tag_hook_add(ctx, evtrec_add_standard_tags, NULL); #ifndef _MSC_VER evt_syslog_wrapper_init(); #endif } return ctx; } EVTCONTEXT * evt_ctx_ref(EVTCONTEXT *ctx) { assert(ctx->ec_ref > 0); ctx->ec_ref++; return ctx; } void evt_ctx_free(EVTCONTEXT *ctx) { assert(ctx->ec_ref > 0); if (--ctx->ec_ref == 0) { EVTTAGHOOK *p, *p_next; p = ctx->ec_tag_hooks; while (p) { p_next = p->et_next; free(p); p = p_next; } free(ctx); } } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtfmt.c000066400000000000000000000064521450431004300222130ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtfmt.c,v 1.3 2004/08/20 19:46:28 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Formatting implementations. This module is responsible for formatting * EVENT records. Each formatter has a unique ID and the administrator is * free to select which output format to use. */ #include "evt_internals.h" #include #include static char * evtrec_format_plain(EVTREC *e) { EVTSTR *es; EVTTAG *et; char *res; if (!(es = evt_str_init(128))) return NULL; evt_str_append_escape_bs(es, e->ev_desc, strlen(e->ev_desc), ';'); evt_str_append(es, ";"); if (e->ev_pairs) evt_str_append(es, " "); for (et = e->ev_pairs; et; et = et->et_next) { evt_str_append(es, et->et_tag); evt_str_append(es, "='"); evt_str_append_escape_bs(es, et->et_value, strlen(et->et_value), '\''); if (et->et_next) evt_str_append(es, "', "); else evt_str_append(es, "'"); } res = evt_str_get_str(es); evt_str_free(es, 0); return res; } static struct { char *ef_name; char *(*ef_formatter)(EVTREC *e); } evt_formatters[] = { { "plain", evtrec_format_plain }, { NULL, NULL } }; char * evt_format(EVTREC *e) { EVTCONTEXT *ctx = e->ev_ctx; if (!ctx->ec_formatter_fn) { int i; for (i = 0; evt_formatters[i].ef_name; i++) { if (strcmp(evt_formatters[i].ef_name, ctx->ec_formatter) == 0) { ctx->ec_formatter_fn = evt_formatters[i].ef_formatter; break; } } if (evt_formatters[i].ef_name == NULL) ctx->ec_formatter_fn = evtrec_format_plain; } return (*ctx->ec_formatter_fn)(e); } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtlog.h000066400000000000000000000156141450431004300222130ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * EventLog library public functions. * * $Id: evtlog.h,v 1.5 2004/08/20 19:53:52 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS `AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef __EVTLOG_H_INCLUDED #define __EVTLOG_H_INCLUDED #ifndef _MSC_VER # include #endif #include #include #include #include #include #include #include "evtmaps.h" #define EVT_PRI_EMERG 0 /* system is unusable */ #define EVT_PRI_ALERT 1 /* action must be taken immediately */ #define EVT_PRI_CRIT 2 /* critical conditions */ #define EVT_PRI_ERR 3 /* error conditions */ #define EVT_PRI_WARNING 4 /* warning conditions */ #define EVT_PRI_NOTICE 5 /* normal but significant condition */ #define EVT_PRI_INFO 6 /* informational */ #define EVT_PRI_DEBUG 7 /* debug-level messages */ #define EVT_FAC_KERN (0<<3) /* kernel messages */ #define EVT_FAC_USER (1<<3) /* random user-level messages */ #define EVT_FAC_MAIL (2<<3) /* mail system */ #define EVT_FAC_DAEMON (3<<3) /* system daemons */ #define EVT_FAC_AUTH (4<<3) /* security/authorization messages */ #define EVT_FAC_SYSLOG (5<<3) /* messages generated internally by syslogd */ #define EVT_FAC_LPR (6<<3) /* line printer subsystem */ #define EVT_FAC_NEWS (7<<3) /* network news subsystem */ #define EVT_FAC_UUCP (8<<3) /* UUCP subsystem */ #define EVT_FAC_CRON (9<<3) /* clock daemon */ #define EVT_FAC_AUTHPRIV (10<<3) /* security/authorization messages (private) */ #define EVT_FAC_FTP (11<<3) /* ftp daemon */ /* other codes through 15 reserved for system use */ #define EVT_FAC_LOCAL0 (16<<3) /* reserved for local use */ #define EVT_FAC_LOCAL1 (17<<3) /* reserved for local use */ #define EVT_FAC_LOCAL2 (18<<3) /* reserved for local use */ #define EVT_FAC_LOCAL3 (19<<3) /* reserved for local use */ #define EVT_FAC_LOCAL4 (20<<3) /* reserved for local use */ #define EVT_FAC_LOCAL5 (21<<3) /* reserved for local use */ #define EVT_FAC_LOCAL6 (22<<3) /* reserved for local use */ #define EVT_FAC_LOCAL7 (23<<3) /* reserved for local use */ /* EVTCONTEXT encapsulates logging specific parameters like the * program name and facility to use */ typedef struct __evtcontext EVTCONTEXT; /* EVTREC is an event log record, contains a description and one or more * name/value pairs */ typedef struct __evtrec EVTREC; /* EVTTAG is a name value pair, comprising an event record */ typedef struct __evttag EVTTAG; /* eventlog contexts */ /** * evt_ctx_init: * @prog: program name to use to identify this process as * @syslog_fac: syslog facility code, like EVT_FAC_AUTH * * This function creates a new eventlog context. * * Returns: the new context, or NULL on failure **/ EVTCONTEXT *evt_ctx_init(const char *prog, int syslog_fac); /** * evt_ctx_free: * @ctx: context to free * * This function frees an eventlog context. **/ void evt_ctx_free(EVTCONTEXT *ctx); /** * evt_ctx_tag_hook_add: **/ int evt_ctx_tag_hook_add(EVTCONTEXT *ctx, int (*func)(EVTREC *e, void *user_ptr), void *user_ptr); /* event record manipulation */ EVTREC *evt_rec_init(EVTCONTEXT *ctx, int syslog_pri, const char *desc); void evt_rec_add_tag(EVTREC *e, EVTTAG *tag); void evt_rec_add_tagsv(EVTREC *e, va_list tags); void evt_rec_add_tags(EVTREC *e, EVTTAG *first, ...); int evt_rec_get_syslog_pri(EVTREC *e); void evt_rec_free(EVTREC *e); /** * evt_rec_tag_*: * @tag: specifies tag name as string * @value: specifies a value in the given type * * Adds the specified tag/value pair to EVTREC. * * Return value: 0 to indicate failure and 1 for success **/ EVTTAG *evt_tag_str(const char *tag, const char *value); EVTTAG *evt_tag_mem(const char *tag, const void *value, size_t len); EVTTAG *evt_tag_int(const char *tag, int value); EVTTAG *evt_tag_long(const char *tag, long long value); EVTTAG *evt_tag_errno(const char *tag, int err); EVTTAG *evt_tag_printf(const char *tag, const char *format, ...) G_GNUC_PRINTF(2, 3); EVTTAG *evt_tag_inaddr(const char *tag, const struct in_addr *addr); EVTTAG *evt_tag_inaddr6(const char *tag, const struct in6_addr *addr); /** * evt_format: * @e: event record * * Formats the given event as specified by the current configuration. * * Return value: returns a newly allocated string. The caller is responsible * for freeing the returned value. **/ char *evt_format(EVTREC *e); /** * evt_log: * @e: event record * * Formats and sends the given event as specified by the current * configuration. This function blocks and will not return until the message * is sent. The function consumes its argument, that is the caller does not * need to free the event record after passing it to evt_log(). * * Return value: 0 to indicate failure and 1 for success * **/ int evt_log(EVTREC *e); /* syslog wrapper */ void evt_openlog(const char *ident, int option, int facility); void evt_closelog(void); void evt_vsyslog(int pri, const char *format, va_list ap) G_GNUC_PRINTF(2, 0); void evt_syslog(int pri, const char *format, ...) G_GNUC_PRINTF(2, 3); #ifdef EVENTLOG_SYSLOG_MACROS #define openlog evt_openlog #define syslog evt_syslog #define vsyslog evt_vsyslog #define closelog evt_closelog #endif #endif syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtmaps.h000066400000000000000000000042031450431004300223620ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtmaps.h,v 1.3 2003/01/10 09:24:51 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef __EVTMAPS_H_INCLUDED #define __EVTMAPS_H_INCLUDED /* base event map, with no namespace */ #define EVT_TAG_PID "pid" #define EVT_TAG_PROG "prog" #define EVT_TAG_ISOSTAMP "isostamp" #define EVT_TAG_UTCSTAMP "utcstamp" #define EVT_TAG_TIMEZONE "tz" #define EVT_TAG_MSGID "msgid" #define EVT_TAG_FD "fd" #define EVT_TAG_OSERROR "error" #define EVT_TAG_FILENAME "filename" #endif syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtout.c000066400000000000000000000064321450431004300222320ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtout.c,v 1.4 2004/08/20 19:46:29 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Output implementations. An output method is responsible for delivering a * message. Each output method has a unique ID and the administrator is * free to select which method to use. */ #include "evt_internals.h" #include #include #include /* local method implementation */ static int evt_output_local(EVTREC *e) { static int initialized = 0; char *msg; EVTCONTEXT *ctx = e->ev_ctx; if (!initialized) { /* * there's a small window of race here, if this is used in a * multithreaded program, but it's a small race, and can only occur * when the first message is sent */ initialized = 1; syslog_opts.es_openlog(ctx->ec_prog, syslog_opts.es_options, ctx->ec_syslog_fac); } msg = evt_format(e); syslog_opts.es_syslog(e->ev_syslog_pri, "%s", msg); free(msg); return 1; } static struct { char *eo_name; int (*eo_outmethod_fn)(EVTREC *e); } evt_outmethods[] = { { "local", evt_output_local }, { NULL, NULL } }; int evt_log(EVTREC *e) { int res; EVTCONTEXT *ctx = e->ev_ctx; if (!ctx->ec_outmethod_fn) { int i; for (i = 0; evt_outmethods[i].eo_name; i++) { if (strcmp(evt_outmethods[i].eo_name, ctx->ec_outmethod) == 0) { ctx->ec_outmethod_fn = evt_outmethods[i].eo_outmethod_fn; break; } } if (evt_outmethods[i].eo_name == NULL) ctx->ec_outmethod_fn = evt_output_local; } res = (*ctx->ec_outmethod_fn)(e); evt_rec_free(e); return res; } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtrec.c000066400000000000000000000067311450431004300221760ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtrec.c,v 1.4 2004/08/20 19:46:29 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "evt_internals.h" #include #include #include /* for snprintf */ void evt_rec_add_tag(EVTREC *e, EVTTAG *tag) { /* make it the last in list */ tag->et_next = NULL; if (e->ev_last_pair) e->ev_last_pair->et_next = tag; else e->ev_pairs = tag; e->ev_last_pair = tag; } void evt_rec_add_tagsv(EVTREC *e, va_list tags) { EVTTAG *t; t = va_arg(tags, EVTTAG *); while (t) { evt_rec_add_tag(e, t); t = va_arg(tags, EVTTAG *); } } void evt_rec_add_tags(EVTREC *e, EVTTAG *first, ...) { va_list ap; va_start(ap, first); evt_rec_add_tag(e, first); evt_rec_add_tagsv(e, ap); va_end(ap); } int evt_rec_get_syslog_pri(EVTREC *e) { return e->ev_syslog_pri; } static int evt_rec_call_hooks(EVTREC *e) { EVTTAGHOOK *et; int res = 1; for (et = e->ev_ctx->ec_tag_hooks; et; et = et->et_next) { if (!et->et_callback(e, et->et_userptr)) res = 0; } return res; } EVTREC * evt_rec_init(EVTCONTEXT *ctx, int syslog_pri, const char *desc) { EVTREC *e; e = (EVTREC *) malloc(sizeof(EVTREC)); if (e) { e->ev_ctx = evt_ctx_ref(ctx); e->ev_desc = strdup(desc); e->ev_pairs = NULL; e->ev_last_pair = NULL; e->ev_ref = 1; e->ev_syslog_pri = syslog_pri; if (!evt_rec_call_hooks(e)) { free(e); e = NULL; } } return e; } EVTREC * evt_rec_ref(EVTREC *e) { e->ev_ref++; return e; } void evt_rec_free(EVTREC *e) { EVTTAG *p, *p_next; if (--e->ev_ref == 0) { free(e->ev_desc); for (p = e->ev_pairs; p; p = p_next) { p_next = p->et_next; evt_tag_free(p); } evt_ctx_free(e->ev_ctx); free(e); } } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtstr.c000066400000000000000000000111201450431004300222210ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtstr.c,v 1.3 2004/08/20 19:46:29 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * A couple of string support functions which make it easy to output * escaped strings. It is used by event formatting functions. */ #include "evt_internals.h" #include #include #include #include #ifdef HAVE_MALLOC_H #include #endif /* event string handling */ static inline int evt_str_grow(EVTSTR *es, size_t new_alloc) { char *buf = realloc(es->es_buf, new_alloc); if (!buf) return 0; es->es_buf = buf; es->es_allocated = new_alloc; return 1; } int evt_str_append_len(EVTSTR *es, char *str, size_t len) { /* make sure we have room new string + trailing zero */ if (es->es_allocated < es->es_length + len + 1) { if (!evt_str_grow(es, es->es_length + len + 1)) return 0; } memcpy(es->es_buf + es->es_length, str, len); es->es_length += len; es->es_buf[es->es_length] = 0; /* trailing zero */ return 1; } int evt_str_append(EVTSTR *es, char *str) { return evt_str_append_len(es, str, strlen(str)); } int evt_str_append_escape_bs(EVTSTR *es, char *unescaped, size_t unescaped_len, char escape_char) { /* a single character is escaped to at most 4 characters: \xXX */ size_t escaped_char_max_len = 4; char escaped_buffer[128]; size_t escaped_buffer_capacity = sizeof(escaped_buffer) / sizeof(escaped_buffer[0]); size_t escaped_buffer_length = 0; int i; for (i = 0; i < unescaped_len; i++) { unsigned c = (unsigned) unescaped[i]; if (c < 32 && c != '\t') { sprintf(escaped_buffer + escaped_buffer_length, "\\x%02x", (unsigned char) unescaped[i]); escaped_buffer_length += 4; } else if (unescaped[i] == escape_char) { escaped_buffer[escaped_buffer_length++] = '\\'; escaped_buffer[escaped_buffer_length++] = escape_char; } else { escaped_buffer[escaped_buffer_length++] = unescaped[i]; } if (escaped_buffer_capacity <= escaped_buffer_length + escaped_char_max_len) { if (!evt_str_append_len(es, escaped_buffer, escaped_buffer_length)) return 0; escaped_buffer_length = 0; } } return evt_str_append_len(es, escaped_buffer, escaped_buffer_length); } char * evt_str_get_str(EVTSTR *es) { return es->es_buf; } EVTSTR * evt_str_init(size_t init_alloc) { EVTSTR *es; es = (EVTSTR *) malloc(sizeof(EVTSTR)); if (es) { /* make room for init_alloc characters + trailing zero */ init_alloc++; es->es_allocated = init_alloc; es->es_length = 0; es->es_buf = malloc(init_alloc); if (!es->es_buf) { free(es); return NULL; } es->es_buf[0] = 0; } return es; } void evt_str_free(EVTSTR *es, int free_buf) { if (free_buf) free(es->es_buf); free(es); } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evtsyslog.c000066400000000000000000000054421450431004300227430ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evtsyslog.c,v 1.3 2004/08/20 20:27:54 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "evt_internals.h" #include #include #include EVTCONTEXT *syslog_context; EVTSYSLOGOPTS syslog_opts; void evt_openlog(const char *ident, int options, int facility) { syslog_context = evt_ctx_init(ident, facility); /* NOTE: we save the legacy syslog option value, so that our local target * can use it */ syslog_opts.es_options = options; } void evt_closelog(void) { } void evt_vsyslog(int pri, const char *format, va_list ap) { EVTREC *e; char msgbuf[1024]; vsnprintf(msgbuf, sizeof(msgbuf), format, ap); e = evt_rec_init(syslog_context, pri, msgbuf); evt_log(e); } void evt_syslog(int pri, const char *format, ...) { va_list ap; va_start(ap, format); evt_vsyslog(pri, format, ap); va_end(ap); } void evt_syslog_wrapper_init(void) { static int initialized = 0; if (!initialized) { syslog_opts.es_openlog = openlog; syslog_opts.es_closelog = closelog; syslog_opts.es_syslog = syslog; syslog_opts.es_options = LOG_PID | LOG_NOWAIT; initialized = 1; } } syslog-ng-syslog-ng-4.4.0/lib/eventlog/src/evttags.c000066400000000000000000000076021450431004300223610ustar00rootroot00000000000000/* * Event Logging API * Copyright (c) 2003 BalaBit IT Ltd. * All rights reserved. * Author: Balazs Scheidler * * $Id: evttags.c,v 1.4 2004/08/20 19:46:29 bazsi Exp $ * * Some of the ideas are based on the discussions on the log-analysis * mailing list (http://www.loganalysis.org/). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of BalaBit nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY BALABIT AND CONTRIBUTORS S IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * This module implements tag support functions. */ #include "evt_internals.h" #include #include #include #include #include #ifdef _MSC_VER #ifndef snprintf #define snprintf _snprintf #endif #endif void evt_tag_free(EVTTAG *et) { free(et->et_tag); free(et->et_value); free(et); } EVTTAG * evt_tag_str(const char *tag, const char *value) { EVTTAG *p; /* neither tag nor value can be NULL */ assert(tag); if (!value) value = "(null)"; p = (EVTTAG *) malloc(sizeof(EVTTAG)); if (p) { p->et_tag = strdup(tag); p->et_value = strdup(value); } return p; } EVTTAG * evt_tag_mem(const char *tag, const void *value, size_t len) { char *buf = malloc(len + 1); memcpy(buf, value, len); for (size_t i = 0; i < len; i++) { if (buf[i] == 0) buf[i] = '.'; } buf[len] = 0; EVTTAG *p = evt_tag_str(tag, buf); free(buf); return p; } EVTTAG * evt_tag_int(const char *tag, int value) { char buf[32]; /* a 64 bit int fits into 20 characters */ snprintf(buf, sizeof(buf), "%d", value); return evt_tag_str(tag, buf); } EVTTAG * evt_tag_long(const char *tag, long long value) { char buf[32]; /* a 64 bit int fits into 20 characters */ snprintf(buf, sizeof(buf), "%lld", value); return evt_tag_str(tag, buf); } EVTTAG * evt_tag_errno(const char *tag, int err) { char buf[128]; snprintf(buf, sizeof(buf), "%s (%d)", strerror(err), err); return evt_tag_str(tag, buf); } EVTTAG * evt_tag_printf(const char *tag, const char *format, ...) { va_list ap; char buf[1024]; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); return evt_tag_str(tag, buf); } EVTTAG * evt_tag_inaddr(const char *tag, const struct in_addr *addr) { char buf[64]; if (addr) inet_ntop(AF_INET, addr, buf, sizeof(buf)); else strncpy(buf, "none", sizeof(buf)); return evt_tag_str(tag, buf); } EVTTAG * evt_tag_inaddr6(const char *tag, const struct in6_addr *addr) { char buf[128]; if (addr) inet_ntop(AF_INET6, addr, buf, sizeof(buf)); else strncpy(buf, "none", sizeof(buf)); return evt_tag_str(tag, buf); } syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/000077500000000000000000000000001450431004300211065ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/CMakeLists.txt000066400000000000000000000011001450431004300236360ustar00rootroot00000000000000add_unit_test(TARGET test_evtrec INCLUDES "${Eventlog_INCLUDE_DIR}" SOURCES evtrec.c) add_unit_test(TARGET test_evtfmt INCLUDES "${Eventlog_INCLUDE_DIR}" SOURCES evtfmt.c) add_unit_test(CRITERION TARGET test_evt_tag_mem INCLUDES "${Eventlog_INCLUDE_DIR}" SOURCES evt_tag_mem.c) add_unit_test(TARGET test_evtsyslog INCLUDES "${Eventlog_INCLUDE_DIR}" SOURCES evtsyslog.c) add_unit_test(TARGET test_evtsyslog_macros INCLUDES "${Eventlog_INCLUDE_DIR}" SOURCES evtsyslog.c) target_compile_definitions(test_evtsyslog_macros PRIVATE EVENTLOG_SYSLOG_MACROS=1) syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/Makefile.am000066400000000000000000000022251450431004300231430ustar00rootroot00000000000000lib_eventlog_tests_TESTS = \ lib/eventlog/tests/evtrec \ lib/eventlog/tests/evtfmt \ lib/eventlog/tests/evtsyslog \ lib/eventlog/tests/evtsyslog-macros \ lib/eventlog/tests/evt_tag_mem EXTRA_DIST += lib/eventlog/tests/CMakeLists.txt check_PROGRAMS += ${lib_eventlog_tests_TESTS} lib_eventlog_tests_evtrec_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/eventlog/src lib_eventlog_tests_evtrec_LDADD = $(top_builddir)/lib/eventlog/src/libevtlog.la lib_eventlog_tests_evtfmt_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/eventlog/src lib_eventlog_tests_evtfmt_LDADD = $(top_builddir)/lib/eventlog/src/libevtlog.la lib_eventlog_tests_evtsyslog_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/eventlog/src lib_eventlog_tests_evtsyslog_LDADD = $(top_builddir)/lib/eventlog/src/libevtlog.la lib_eventlog_tests_evt_tag_mem_CFLAGS = $(TEST_CFLAGS) lib_eventlog_tests_evt_tag_mem_LDADD = $(TEST_LDADD) lib_eventlog_tests_evtsyslog_macros_SOURCES = lib/eventlog/tests/evtsyslog.c lib_eventlog_tests_evtsyslog_macros_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/lib/eventlog/src -DEVENTLOG_SYSLOG_MACROS=1 lib_eventlog_tests_evtsyslog_macros_LDADD = $(top_builddir)/lib/eventlog/src/libevtlog.la syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/evt_tag_mem.c000066400000000000000000000041701450431004300235430ustar00rootroot00000000000000/* * Copyright (c) 2022 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include struct evt_tag_mem_params { gchar *original_value; gsize original_value_len; gchar *new_value; }; ParameterizedTestParameters(evt_tag_mem, test) { static struct evt_tag_mem_params params[] = { {"", 1, "."}, {"\0", 2, ".."}, {"foo", 4, "foo."}, {"\0\0foo", 6, "..foo."}, {"\0a\0b\0c", 7, ".a.b.c."}, }; return cr_make_param_array(struct evt_tag_mem_params, params, sizeof (params) / sizeof(struct evt_tag_mem_params)); } ParameterizedTest(struct evt_tag_mem_params *params, evt_tag_mem, test) { gchar *key = "test:evt_tag_mem"; EVTCONTEXT *ctx = evt_ctx_init("evt_tag_mem", LOG_AUTH); EVTREC *event_rec = evt_rec_init(ctx, LOG_INFO, ""); evt_rec_add_tag(event_rec, evt_tag_mem(key, params->original_value, params->original_value_len)); gchar *formatted_result = evt_format(event_rec); GString *expected_result = g_string_sized_new(8); g_string_append_printf(expected_result, "; %s='%s'", key, params->new_value); cr_assert_str_eq(formatted_result, expected_result->str); free(formatted_result); g_string_free(expected_result, TRUE); evt_ctx_free(ctx); } syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/evtfmt.c000066400000000000000000000013511450431004300225570ustar00rootroot00000000000000#include "evtlog.h" #include #include #include int main(void) { EVTCONTEXT *ctx; EVTREC *e; char *es; ctx = evt_ctx_init("evtfmt", LOG_AUTH); e = evt_rec_init(ctx, LOG_INFO, "Test message with an embedded ';' in it. It also contains an like tag."); evt_rec_add_tags(e, evt_tag_str("test:tag", "'value'"), evt_tag_str("test:tag2", "\n\n\n\n"), evt_tag_int("test:fd", fileno(stderr)), evt_tag_errno("test:error", EAGAIN), evt_tag_printf("test:printf", "%d %d", 5, 6), NULL); es = evt_format(e); printf("%s\n", es); free(es); evt_log(e); evt_ctx_free(ctx); return 0; } syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/evtrec.c000066400000000000000000000007231450431004300225440ustar00rootroot00000000000000#include "evtlog.h" #include #include int main(void) { EVTREC *e; EVTCONTEXT *ctx; ctx = evt_ctx_init("evtrec", LOG_AUTH); e = evt_rec_init(ctx, LOG_INFO, "Test message"); evt_rec_add_tags(e, evt_tag_str("test:tag", "value"), evt_tag_int("test:fd", fileno(stderr)), evt_tag_errno("test:error", EAGAIN), NULL); evt_log(e); evt_ctx_free(ctx); return 0; } syslog-ng-syslog-ng-4.4.0/lib/eventlog/tests/evtsyslog.c000066400000000000000000000003211450431004300233050ustar00rootroot00000000000000#include #ifdef EVENTLOG_SYSLOG_MACROS #include #endif int main(void) { openlog("evtsyslog", LOG_PID, 0); syslog(LOG_AUTH | LOG_NOTICE, "test message"); closelog(); return 0; } syslog-ng-syslog-ng-4.4.0/lib/fdhelpers.c000066400000000000000000000031521450431004300202420ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "fdhelpers.h" #include #include gboolean g_fd_set_nonblock(int fd, gboolean enable) { int flags; if ((flags = fcntl(fd, F_GETFL)) == -1) return FALSE; if (enable) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { return FALSE; } return TRUE; } gboolean g_fd_set_cloexec(int fd, gboolean enable) { int flags; if ((flags = fcntl(fd, F_GETFD)) == -1) return FALSE; if (enable) flags |= FD_CLOEXEC; else flags &= ~FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) < 0) { return FALSE; } return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/fdhelpers.h000066400000000000000000000022631450431004300202510ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FDHELPERS_H_INCLUDED #define FDHELPERS_H_INCLUDED 1 #include "syslog-ng.h" gboolean g_fd_set_nonblock(int fd, gboolean enable); gboolean g_fd_set_cloexec(int fd, gboolean enable); #endif syslog-ng-syslog-ng-4.4.0/lib/file-perms.c000066400000000000000000000170171450431004300203360ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-perms.h" #include "userdb.h" #include "messages.h" #include "cfg.h" #include "gprocess.h" #include #include #include #include #define DONTCHANGE -2 void file_perm_options_set_file_uid(FilePermOptions *self, const gchar *file_uid) { self->file_uid = 0; if (!resolve_user(file_uid, &self->file_uid)) { msg_error("Error resolving user", evt_tag_str("user", file_uid)); } } void file_perm_options_dont_change_file_uid(FilePermOptions *self) { self->file_uid = DONTCHANGE; } void file_perm_options_set_file_gid(FilePermOptions *self, const gchar *file_gid) { self->file_gid = 0; if (!resolve_group(file_gid, &self->file_gid)) { msg_error("Error resolving group", evt_tag_str("group", file_gid)); } } void file_perm_options_dont_change_file_gid(FilePermOptions *self) { self->file_gid = DONTCHANGE; } void file_perm_options_set_file_perm(FilePermOptions *self, gint file_perm) { self->file_perm = file_perm; } void file_perm_options_dont_change_file_perm(FilePermOptions *self) { self->file_perm = DONTCHANGE; } void file_perm_options_set_dir_uid(FilePermOptions *self, const gchar *dir_uid) { self->dir_uid = 0; if (!resolve_user(dir_uid, &self->dir_uid)) { msg_error("Error resolving user", evt_tag_str("user", dir_uid)); } } void file_perm_options_dont_change_dir_uid(FilePermOptions *self) { self->dir_uid = DONTCHANGE; } void file_perm_options_set_dir_gid(FilePermOptions *self, const gchar *dir_gid) { self->dir_gid = 0; if (!resolve_group(dir_gid, &self->dir_gid)) { msg_error("Error resolving group", evt_tag_str("group", dir_gid)); } } void file_perm_options_dont_change_dir_gid(FilePermOptions *self) { self->dir_gid = DONTCHANGE; } void file_perm_options_set_dir_perm(FilePermOptions *self, gint dir_perm) { self->dir_perm = dir_perm; } void file_perm_options_dont_change_dir_perm(FilePermOptions *self) { self->dir_perm = DONTCHANGE; } void file_perm_options_defaults(FilePermOptions *self) { self->file_uid = self->file_gid = -1; self->file_perm = -1; self->dir_uid = self->dir_gid = -1; self->dir_perm = -1; } void file_perm_options_global_defaults(FilePermOptions *self) { self->file_uid = self->file_gid = -1; self->file_perm = 0600; self->dir_uid = self->dir_gid = -1; self->dir_perm = 0700; } void file_perm_options_inherit_from(FilePermOptions *self, const FilePermOptions *from) { if (self->file_uid == -1) self->file_uid = from->file_uid; if (self->file_gid == -1) self->file_gid = from->file_gid; if (self->file_perm == -1) self->file_perm = from->file_perm; if (self->dir_uid == -1) self->dir_uid = from->dir_uid; if (self->dir_gid == -1) self->dir_gid = from->dir_gid; if (self->dir_perm == -1) self->dir_perm = from->dir_perm; } void file_perm_options_inherit_dont_change(FilePermOptions *self) { FilePermOptions dont_change = { .file_uid = DONTCHANGE, .file_gid = DONTCHANGE, .file_perm = DONTCHANGE, .dir_uid = DONTCHANGE, .dir_gid = DONTCHANGE, .dir_perm = DONTCHANGE, }; file_perm_options_inherit_from(self, &dont_change); } gboolean file_perm_options_apply_file(const FilePermOptions *self, const gchar *path) { #ifndef _MSC_VER gboolean result = TRUE; if (self->file_uid >= 0 && chown(path, (uid_t) self->file_uid, -1) < 0) result = FALSE; if (self->file_gid >= 0 && chown(path, -1, (gid_t) self->file_gid) < 0) result = FALSE; if (self->file_perm >= 0 && chmod(path, (mode_t) self->file_perm) < 0) result = FALSE; return result; #endif } gboolean file_perm_options_apply_symlink(const FilePermOptions *self, const gchar *path) { #ifndef _MSC_VER gboolean result = TRUE; if (self->file_uid >= 0 && lchown(path, (uid_t) self->file_uid, -1) < 0) result = FALSE; if (self->file_gid >= 0 && lchown(path, -1, (gid_t) self->file_gid) < 0) result = FALSE; return result; #endif } gboolean file_perm_options_apply_dir(const FilePermOptions *self, const gchar *path) { #ifndef _MSC_VER gboolean result = TRUE; if (self->dir_uid >= 0 && chown(path, (uid_t) self->dir_uid, -1) < 0) result = FALSE; if (self->dir_gid >= 0 && chown(path, -1, (gid_t) self->dir_gid) < 0) result = FALSE; if (self->dir_perm >= 0 && chmod(path, (mode_t) self->dir_perm) < 0) result = FALSE; return result; #endif } gboolean file_perm_options_apply_fd(const FilePermOptions *self, gint fd) { #ifndef _MSC_VER gboolean result = TRUE; if (self->file_uid >= 0 && fchown(fd, (uid_t) self->file_uid, -1) < 0) result = FALSE; if (self->file_gid >= 0 && fchown(fd, -1, (gid_t) self->file_gid) < 0) result = FALSE; if (self->file_perm >= 0 && fchmod(fd, (mode_t) self->file_perm) < 0) result = FALSE; return result; #endif } /** * * This function receives a complete path (directory + filename) and creates * the directory portion if it does not exist. The point is that the caller * wants to ensure that the given filename can be opened after this function * returns. (at least it won't fail because of missing directories). **/ gboolean file_perm_options_create_containing_directory(const FilePermOptions *self, const gchar *path) { gboolean result = FALSE; gchar *_path; gchar *dirname; struct stat st; gint rc; gchar *p; cap_t saved_caps; _path = g_strdup(path); /* check that the directory exists */ dirname = g_path_get_dirname(_path); rc = stat(dirname, &st); g_free(dirname); if (rc == 0) { /* directory already exists */ result = TRUE; goto finish; } else if (rc < 0 && errno != ENOENT) { /* some real error occurred */ result = FALSE; goto finish; } /* directory does not exist */ p = strchr(_path + 1, '/'); while (p) { *p = 0; if (stat(_path, &st) == 0) { if (!S_ISDIR(st.st_mode)) { result = FALSE; goto finish; } } else if (errno == ENOENT) { if (mkdir(_path, self->dir_perm < 0 ? 0700 : (mode_t) self->dir_perm) == -1) { result = FALSE; goto finish; } saved_caps = g_process_cap_save(); g_process_enable_cap("cap_chown"); g_process_enable_cap("cap_fowner"); file_perm_options_apply_dir(self, _path); g_process_cap_restore(saved_caps); } *p = '/'; p = strchr(p + 1, '/'); } result = TRUE; finish: g_free(_path); return result; } syslog-ng-syslog-ng-4.4.0/lib/file-perms.h000066400000000000000000000054171450431004300203440ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILE_PERMS_H_INCLUDED #define FILE_PERMS_H_INCLUDED #include "syslog-ng.h" typedef struct _FilePermOptions { gint file_uid; gint file_gid; gint file_perm; gint dir_uid; gint dir_gid; gint dir_perm; } FilePermOptions; void file_perm_options_set_file_uid(FilePermOptions *s, const gchar *file_uid); void file_perm_options_dont_change_file_uid(FilePermOptions *s); void file_perm_options_set_file_gid(FilePermOptions *s, const gchar *file_gid); void file_perm_options_dont_change_file_gid(FilePermOptions *s); void file_perm_options_set_file_perm(FilePermOptions *s, gint file_perm); void file_perm_options_dont_change_file_perm(FilePermOptions *s); void file_perm_options_set_dir_uid(FilePermOptions *s, const gchar *dir_uid); void file_perm_options_dont_change_dir_uid(FilePermOptions *s); void file_perm_options_set_dir_gid(FilePermOptions *s, const gchar *dir_gid); void file_perm_options_dont_change_dir_gid(FilePermOptions *s); void file_perm_options_set_dir_perm(FilePermOptions *s, gint dir_perm); void file_perm_options_dont_change_dir_perm(FilePermOptions *s); void file_perm_options_defaults(FilePermOptions *self); void file_perm_options_global_defaults(FilePermOptions *self); void file_perm_options_inherit_from(FilePermOptions *self, const FilePermOptions *from); void file_perm_options_inherit_dont_change(FilePermOptions *self); gboolean file_perm_options_apply_file(const FilePermOptions *self, const gchar *name); gboolean file_perm_options_apply_symlink(const FilePermOptions *self, const gchar *name); gboolean file_perm_options_apply_dir(const FilePermOptions *self, const gchar *name); gboolean file_perm_options_apply_fd(const FilePermOptions *self, gint fd); gboolean file_perm_options_create_containing_directory(const FilePermOptions *self, const gchar *name); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/000077500000000000000000000000001450431004300174065ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/filter/CMakeLists.txt000066400000000000000000000013411450431004300221450ustar00rootroot00000000000000set(FILTER_HEADERS filter/filter-expr.h filter/filter-op.h filter/filter-cmp.h filter/filter-in-list.h filter/filter-tags.h filter/filter-netmask.h filter/filter-netmask6.h filter/filter-call.h filter/filter-re.h filter/filter-pri.h filter/filter-pipe.h filter/filter-expr-parser.h PARENT_SCOPE ) set(FILTER_SOURCES filter/filter-expr.c filter/filter-op.c filter/filter-cmp.c filter/filter-in-list.c filter/filter-tags.c filter/filter-netmask.c filter/filter-netmask6.c filter/filter-call.c filter/filter-re.c filter/filter-pri.c filter/filter-pipe.c filter/filter-expr-parser.c PARENT_SCOPE ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/filter/Makefile.am000066400000000000000000000021131450431004300214370ustar00rootroot00000000000000filterincludedir = ${pkgincludedir}/filter filterinclude_HEADERS = \ lib/filter/filter-expr.h \ lib/filter/filter-op.h \ lib/filter/filter-cmp.h \ lib/filter/filter-in-list.h \ lib/filter/filter-tags.h \ lib/filter/filter-netmask.h \ lib/filter/filter-netmask6.h \ lib/filter/filter-call.h \ lib/filter/filter-re.h \ lib/filter/filter-pri.h \ lib/filter/filter-pipe.h \ lib/filter/filter-expr-parser.h filter_sources = \ lib/filter/filter-expr.c \ lib/filter/filter-op.c \ lib/filter/filter-cmp.c \ lib/filter/filter-in-list.c \ lib/filter/filter-tags.c \ lib/filter/filter-netmask.c \ lib/filter/filter-netmask6.c \ lib/filter/filter-call.c \ lib/filter/filter-re.c \ lib/filter/filter-pri.c \ lib/filter/filter-pipe.c \ lib/filter/filter-expr-parser.c \ lib/filter/filter-expr-grammar.y BUILT_SOURCES += \ lib/filter/filter-expr-grammar.y \ lib/filter/filter-expr-grammar.c \ lib/filter/filter-expr-grammar.h EXTRA_DIST += lib/filter/filter-expr-grammar.ym \ lib/filter/CMakeLists.txt include lib/filter/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/filter/filter-call.c000066400000000000000000000115331450431004300217530ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-call.h" #include "cfg.h" #include "filter-pipe.h" typedef struct _FilterCall { FilterExprNode super; FilterExprNode *filter_expr; gchar *rule; gboolean visited; /* Used for filter call loop detection */ } FilterCall; static gboolean filter_call_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { gboolean res = FALSE; FilterCall *self = (FilterCall *) s; if (self->filter_expr) { /* rule is assumed to contain a single filter pipe */ res = filter_expr_eval_with_context(self->filter_expr, msgs, num_msg, options); } if (res) stats_counter_inc(self->super.matched); else stats_counter_inc(self->super.not_matched); msg_trace("filter() evaluation started", evt_tag_str("called-rule", self->rule), evt_tag_msg_reference(msgs[num_msg - 1])); return res ^ s->comp; } static gboolean filter_call_init(FilterExprNode *s, GlobalConfig *cfg) { FilterCall *self = (FilterCall *) s; LogExprNode *rule; if (self->visited) { msg_error("Loop detected in filter rule", evt_tag_str("rule", self->rule)); return FALSE; } /* skip initialize if filter_call_init already called. */ if (self->filter_expr) return TRUE; self->visited = TRUE; rule = cfg_tree_get_object(&cfg->tree, ENC_FILTER, self->rule); if (rule) { /* this is quite fragile and would break whenever the parsing code in * cfg-grammar.y changes to parse a filter rule. We assume that a * filter rule has a single child, which contains a LogFilterPipe * instance as its object. */ LogFilterPipe *filter_pipe = (LogFilterPipe *) rule->children->object; self->filter_expr = filter_expr_clone(filter_pipe->expr); if (!filter_expr_init(self->filter_expr, cfg)) return FALSE; self->super.modify = self->filter_expr->modify; stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->rule) }; stats_cluster_logpipe_key_set(&sc_key, "filtered_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_FILTER, self->rule, NULL ); stats_register_counter(1, &sc_key, SC_TYPE_MATCHED, &self->super.matched); stats_register_counter(1, &sc_key, SC_TYPE_NOT_MATCHED, &self->super.not_matched); stats_unlock(); } else { msg_error("Referenced filter rule not found in filter() expression", evt_tag_str("rule", self->rule)); return FALSE; } self->visited = FALSE; return TRUE; } static void filter_call_free(FilterExprNode *s) { FilterCall *self = (FilterCall *) s; filter_expr_unref(self->filter_expr); stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->rule) }; stats_cluster_logpipe_key_set(&sc_key, "filtered_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_FILTER, self->rule, NULL ); stats_unregister_counter(&sc_key, SC_TYPE_MATCHED, &self->super.matched); stats_unregister_counter(&sc_key, SC_TYPE_NOT_MATCHED, &self->super.not_matched); stats_unlock(); g_free((gchar *) self->super.type); g_free(self->rule); } FilterExprNode * filter_call_new(gchar *rule, GlobalConfig *cfg) { FilterCall *self = g_new0(FilterCall, 1); filter_expr_node_init_instance(&self->super); self->super.init = filter_call_init; self->super.eval = filter_call_eval; self->super.free_fn = filter_call_free; self->super.type = g_strdup_printf("filter(%s)", rule); self->rule = g_strdup(rule); return &self->super; } FilterExprNode * filter_call_clone(FilterExprNode *s) { FilterCall *self = (FilterCall *) s; FilterExprNode *cloned_self = filter_call_new(self->rule, configuration); filter_call_init(cloned_self, configuration); return cloned_self; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-call.h000066400000000000000000000022271450431004300217600ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_CALL_H_INCLUDED #define FILTER_CALL_H_INCLUDED #include "filter-expr.h" FilterExprNode *filter_call_new(gchar *rule, struct _GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-cmp.c000066400000000000000000000305751450431004300216260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter/filter-cmp.h" #include "filter/filter-expr-grammar.h" #include "scratch-buffers.h" #include "generic-number.h" #include "parse-number.h" #include #include #include typedef struct _FilterCmp { FilterExprNode super; LogTemplate *left, *right; gint compare_mode; } FilterCmp; static gint fop_compare_numeric(const GString *left, const GString *right) { gint l = atoi(left->str); gint r = atoi(right->str); if (l == r) return 0; else if (l < r) return -1; return 1; } static gint fop_compare_bytes(const GString *left, const GString *right) { gint cmp = memcmp(left->str, right->str, MIN(left->len, right->len)); if (cmp != 0) return cmp; if (left->len == right->len) return 0; return left->len < right->len ? -1 : 1; } static inline gboolean _is_object(LogMessageValueType type) { return type == LM_VT_JSON || type == LM_VT_LIST; } static inline gboolean _is_string(LogMessageValueType type) { return type == LM_VT_STRING; } static inline gboolean _is_bytes(LogMessageValueType type) { return type == LM_VT_BYTES || type == LM_VT_PROTOBUF; } static gboolean _evaluate_comparison(FilterCmp *self, gint cmp) { gboolean result = FALSE; if (cmp == 0) { result = self->compare_mode & FCMP_EQ; } else if (cmp < 0) { result = !!(self->compare_mode & FCMP_LT); } else { result = !!(self->compare_mode & FCMP_GT); } return result; } /* NOTE: this function mimics JavaScript when converting a value to a * number. As described here: * * Primitive types: https://javascript.info/type-conversions * * Objects are always converted to NaNs as we can't evaluate the * toPrimitive() method, even if the Object had one. Here's is how it is * dealt with in JavaScript: https://javascript.info/object-toprimitive * */ static void _convert_to_number(const GString *value, LogMessageValueType type, GenericNumber *number) { switch (type) { case LM_VT_STRING: case LM_VT_INTEGER: case LM_VT_DOUBLE: if (!parse_generic_number(value->str, number)) gn_set_nan(number); break; case LM_VT_JSON: case LM_VT_LIST: case LM_VT_BYTES: case LM_VT_PROTOBUF: gn_set_nan(number); break; case LM_VT_NULL: gn_set_int64(number, 0); break; case LM_VT_BOOLEAN: { gboolean b; if (type_cast_to_boolean(value->str, &b, NULL)) gn_set_int64(number, b); else gn_set_int64(number, 0); break; } case LM_VT_DATETIME: { gint64 msec; if (type_cast_to_datetime_msec(value->str, &msec, NULL)) gn_set_int64(number, msec); else gn_set_int64(number, 0); break; } default: g_assert_not_reached(); } } /* * The "new" 4.0 comparison operators have become type aware, e.g. when * doing comparisons they consult with the types associated with the arguments. * * The algorithm took an inspiration from JavaScript, but it deviates * somewhat, here is how it works. * * 1) if both arguments are the same type, then strings and objects/lists are * compared as their string representation (in JavaScript objects would * not be equal as they each are separate instances and JS compares * references in this case) * * 2) if both arguments are of the NULL type, they would evaluate to TRUE if * both sides are NULL (e.g. we can compare NULLs to NULLs) * * 3) otherwise the arguments are converted to numbers (as per JavaScript * behavior) and compared numerically. * * 3.a) If any or both sides becomes a NaN (ie: not-a-number) the * evaluation is always FALSE to match JavaScript behavior * * 3.b) If one side is a NaN and we check for not-equal, then the * evaluation is always TRUE, again to match JavaScript behaviour. * ( != NaN is always TRUE even if is NaN too) * */ static gboolean _evaluate_typed(FilterCmp *self, const GString *left, LogMessageValueType left_type, const GString *right, LogMessageValueType right_type) { GenericNumber l, r; /* Type aware comparison: * - strings are compared as strings. * - objects (ie. non-numbers) are compared as strings. * - numbers or mismatching types are compared as numbers */ if (left_type == right_type && (_is_string(left_type) || _is_object(left_type) || _is_bytes(left_type))) return _evaluate_comparison(self, fop_compare_bytes(left, right)); if (left_type == LM_VT_NULL || right_type == LM_VT_NULL) { /* != */ if ((self->compare_mode & FCMP_OP_MASK) == (FCMP_LT + FCMP_GT)) return left_type != right_type; /* == */ if ((self->compare_mode & FCMP_OP_MASK) == FCMP_EQ) return left_type == right_type; /* fallback to numeric comparisons */ } /* ok, we need to convert to numbers and compare that way */ _convert_to_number(left, left_type, &l); _convert_to_number(right, right_type, &r); if (gn_is_nan(&l) || gn_is_nan(&r)) { /* NaN == NaN is false */ /* NaN > NaN is false */ /* NaN < NaN is false */ /* NaN != NaN is true */ /* != is handled specially */ if ((self->compare_mode & (FCMP_LT + FCMP_GT)) == (FCMP_LT + FCMP_GT)) return TRUE; /* if we have NaN on either side, we return FALSE in any comparisons */ return FALSE; } return _evaluate_comparison(self, gn_compare(&l, &r)); } static gboolean _evaluate_type_and_value_comparison(FilterCmp *self, const GString *left, LogMessageValueType left_type, const GString *right, LogMessageValueType right_type) { if ((self->compare_mode & FCMP_OP_MASK) == FCMP_EQ) { /* === */ if (left_type != right_type) return FALSE; } else if ((self->compare_mode & FCMP_OP_MASK) == (FCMP_LT + FCMP_GT)) { /* !== */ if (left_type != right_type) return TRUE; } else g_assert_not_reached(); return _evaluate_typed(self, left, left_type, right, right_type); } static const gchar * _compare_mode_to_string(gint compare_mode) { if (compare_mode & FCMP_TYPE_AWARE) return "type-aware"; else if (compare_mode & FCMP_STRING_BASED) return "string"; else if (compare_mode & FCMP_NUM_BASED) return "numeric"; g_assert_not_reached(); } static gboolean fop_cmp_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterCmp *self = (FilterCmp *) s; LogMessageValueType left_type, right_type; ScratchBuffersMarker marker; GString *left_buf = scratch_buffers_alloc_and_mark(&marker); GString *right_buf = scratch_buffers_alloc(); log_template_append_format_value_and_type_with_context(self->left, msgs, num_msg, options, left_buf, &left_type); log_template_append_format_value_and_type_with_context(self->right, msgs, num_msg, options, right_buf, &right_type); gboolean result; if (self->compare_mode & FCMP_TYPE_AWARE) result = _evaluate_typed(self, left_buf, left_type, right_buf, right_type); else if (self->compare_mode & FCMP_STRING_BASED) result = _evaluate_comparison(self, fop_compare_bytes(left_buf, right_buf)); else if (self->compare_mode & FCMP_NUM_BASED) result = _evaluate_comparison(self, fop_compare_numeric(left_buf, right_buf)); else if (self->compare_mode & FCMP_TYPE_AND_VALUE_BASED) result = _evaluate_type_and_value_comparison(self, left_buf, left_type, right_buf, right_type); else g_assert_not_reached(); msg_trace("cmp() evaluation result", evt_tag_str("left", left_buf->str), evt_tag_str("operator", self->super.type), evt_tag_str("right", right_buf->str), evt_tag_str("compare_mode", _compare_mode_to_string(self->compare_mode)), evt_tag_str("left_type", log_msg_value_type_to_str(left_type)), evt_tag_str("right_type", log_msg_value_type_to_str(right_type)), evt_tag_int("result", result), evt_tag_msg_reference(msgs[num_msg - 1])); scratch_buffers_reclaim_marked(marker); return result ^ s->comp; } static void fop_cmp_free(FilterExprNode *s) { FilterCmp *self = (FilterCmp *) s; log_template_unref(self->left); log_template_unref(self->right); g_free((gchar *) self->super.type); } FilterExprNode * fop_cmp_clone(FilterExprNode *s) { FilterCmp *self = (FilterCmp *) s; FilterCmp *cloned_self = g_new0(FilterCmp, 1); filter_expr_node_init_instance(&cloned_self->super); cloned_self->super.eval = fop_cmp_eval; cloned_self->super.free_fn = fop_cmp_free; cloned_self->super.clone = fop_cmp_clone; cloned_self->left = log_template_ref(self->left); cloned_self->right = log_template_ref(self->right); cloned_self->compare_mode = self->compare_mode; cloned_self->super.type = g_strdup(self->super.type); return &cloned_self->super; } FilterExprNode * fop_cmp_new(LogTemplate *left, LogTemplate *right, const gchar *type, gint compare_mode, EVTTAG *location) { FilterCmp *self = g_new0(FilterCmp, 1); filter_expr_node_init_instance(&self->super); self->super.type = g_strdup(type); self->super.eval = fop_cmp_eval; self->super.free_fn = fop_cmp_free; self->super.clone = fop_cmp_clone; self->compare_mode = compare_mode; self->left = left; self->right = right; if ((self->compare_mode & FCMP_TYPE_AWARE) && cfg_is_config_version_older(left->cfg, VERSION_VALUE_4_0)) { if (self->left->explicit_type_hint != LM_VT_NONE || self->right->explicit_type_hint != LM_VT_NONE) { /* the user has used explicit types in this expression, so let's * keep it type aware and suppress any warnings. */ } else { if (cfg_is_typing_feature_enabled(configuration)) { msg_warning("WARNING: syslog-ng comparisons became type-aware starting with " VERSION_4_0 " " "which means that syslog-ng attempts to infer the intended type of an " "expression automatically and performs comparisons according to the types detected, " "similarly how JavaScript evaluates the comparison of potentially mismatching types. " "You seem to be using numeric operators in this filter expression, so " "please make sure that once the type-aware behavior is turned on it remains correct, " "see this blog post for more information: https://syslog-ng-future.blog/syslog-ng-4-theme-typing/", location); } self->compare_mode = (self->compare_mode & ~FCMP_TYPE_AWARE) | FCMP_NUM_BASED; } } if ((self->compare_mode & FCMP_NUM_BASED) && cfg_is_config_version_older(left->cfg, VERSION_VALUE_3_8)) { msg_warning("WARNING: due to a bug in versions before " VERSION_3_8 ", " "numeric comparison operators like '!=' in filter " "expressions were evaluated as string operators. This is fixed in " VERSION_3_8 ". " "As we are operating in compatibility mode, syslog-ng will exhibit the buggy " "behaviour as previous versions until you bump the @version value in your " "configuration file", location); self->compare_mode &= ~FCMP_TYPE_AWARE; self->compare_mode |= FCMP_STRING_BASED; } g_assert((self->compare_mode & FCMP_MODE_MASK) != 0); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-cmp.h000066400000000000000000000032031450431004300216170ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_CMP_H_INCLUDED #define FILTER_CMP_H_INCLUDED #include "filter-expr.h" #include "template/templates.h" #define FCMP_EQ 0x0001 #define FCMP_LT 0x0002 #define FCMP_GT 0x0004 #define FCMP_TYPE_AWARE 0x0010 #define FCMP_STRING_BASED 0x0020 #define FCMP_NUM_BASED 0x0040 #define FCMP_TYPE_AND_VALUE_BASED 0x0080 #define FCMP_OP_MASK 0x0007 #define FCMP_MODE_MASK 0x00F0 FilterExprNode *fop_cmp_new(LogTemplate *left, LogTemplate *right, const gchar *type, gint compare_mode, EVTTAG *location); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-expr-grammar.ym000066400000000000000000000312601450431004300236440ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "filter/filter-expr-parser.h" } %code { #include "filter/filter-netmask.h" #include "filter/filter-netmask6.h" #include "filter/filter-op.h" #include "filter/filter-cmp.h" #include "filter/filter-in-list.h" #include "filter/filter-tags.h" #include "filter/filter-call.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "messages.h" #include "template/templates.h" #include "syslog-ng.h" #include "syslog-names.h" #include "plugin.h" #include "cfg-grammar-internal.h" #include "parse-number.h" /* NOTE: this function translates a literal value enclosed in quotes to * numeric, if they represent a number. This is needed as older versions of * syslog-ng only allowed "strings" as arguments to comparison operators and * used the operator to denote numeric/string comparisons. * * In the post-4.0 world, we want to use type-aware operators by default, * which means that type information should not be lost due to having to * quote number literals earlier. * * So if we are using type-aware operators (<, > and ==) and our argument is * a quoted number, we turn it into a numeric value and warn the user to * remove the quotes. * */ static LogTemplate * _translate_number_literals(CfgLexer *lexer, gint compare_mode, LogTemplate *expr, YYLTYPE *location) { /* with string based operators we do nothing */ if ((compare_mode & FCMP_STRING_BASED)) return expr; /* if there's an explicit type-hint we use that */ if (expr->type_hint != LM_VT_NONE) return expr; /* if the argument is not literal we don't do anything */ if (!log_template_is_literal_string(expr)) return expr; /* let's check if the argument is a numeric value represented as a string, * turn it into a numberic value and warn the user. */ gint64 v; if (!parse_int64_with_suffix(log_template_get_literal_value(expr, NULL), &v)) return expr; if (cfg_is_config_version_older(configuration, VERSION_VALUE_4_0)) { if (cfg_is_typing_feature_enabled(configuration)) { msg_warning("WARNING: syslog-ng versions before " VERSION_4_0 " interpreted quoted numeric " "literals as numbers when using the '<', '>' or '==' operators. Please remove " "the quotes around the numeric literal when upgrading to " VERSION_4_0 " format, " "otherwise your comparison will become string based " "instead. Alternatively if your intention is string based " "comparison add a string() type cast around the expression", cfg_lexer_format_location_tag(lexer, location)); } log_template_set_type_hint(expr, "int64", NULL); } return expr; } } %define api.prefix {filter_expr_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {FilterExprNode **result} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_PROGRAM %token KW_IN_LIST %left ';' %left KW_OR %left KW_AND %left KW_NOT %left KW_STR_LT KW_STR_LE KW_STR_EQ KW_STR_NE KW_STR_GE KW_STR_GT %left KW_TA_LT KW_TA_LE KW_TA_EQ KW_TA_NE KW_TA_GE KW_TA_GT %left KW_TAV_EQ KW_TAV_NE %type filter_expr %type filter_simple_expr %type filter_plugin %type filter_comparison %type filter_identifier %type filter_fac_list %type filter_fac %type filter_severity_list %type filter_severity %type filter_re %type operator %% start : filter_expr { *result = $1; if (yychar != FILTER_EXPR_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } YYACCEPT; } ; filter_expr : filter_simple_expr { $$ = $1; if (!$1) YYERROR; } | KW_NOT filter_expr { ((FilterExprNode *) $2)->comp = !(((FilterExprNode *) $2)->comp); $$ = $2; } | filter_expr KW_OR filter_expr { $$ = fop_or_new($1, $3); } | filter_expr KW_AND filter_expr { $$ = fop_and_new($1, $3); } | filter_expr ';' filter_expr { $$ = fop_and_new($1, $3); } | filter_expr ';' { $$ = $1; } | '(' filter_expr ')' { $$ = $2; } ; filter_simple_expr : KW_FACILITY '(' filter_fac_list ')' { $$ = filter_facility_new($3); } | KW_FACILITY '(' LL_NUMBER ')' { $$ = filter_facility_new(0x80000000 | $3); } | KW_SEVERITY '(' filter_severity_list ')' { $$ = filter_severity_new($3); } | KW_FILTER '(' string ')' { $$ = filter_call_new($3, configuration); free($3); } | KW_NETMASK '(' string ')' { $$ = filter_netmask_new($3); free($3); } | KW_NETMASK6 '(' string ')' { #if SYSLOG_NG_ENABLE_IPV6 $$ = filter_netmask6_new($3); #else YYERROR; #endif free($3); } | KW_TAGS '(' string_list ')' { $$ = filter_tags_new($3); } | KW_IN_LIST '(' string string ')' { const gchar *p = $4; if (p[0] == '$') { msg_warning("Value references in filters should not use the '$' prefix, those are only needed in templates", evt_tag_str("value", $4), cfg_lexer_format_location_tag(lexer, &@4)); p++; } $$ = filter_in_list_new($3, p); free($3); free($4); } | KW_IN_LIST '(' string KW_VALUE '(' string ')' ')' { const gchar *p = $6; if (p[0] == '$') { msg_warning("Value references in filters should not use the '$' prefix, those are only needed in templates", evt_tag_str("value", $6), cfg_lexer_format_location_tag(lexer, &@6)); p++; } $$ = filter_in_list_new($3, p); free($3); free($6); } | filter_re | filter_comparison | filter_plugin ; filter_plugin : filter_identifier { Plugin *p; gint context = LL_CONTEXT_FILTER; FilterExprNode *node; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found OR you may not used double quotes in your filter expression", cfg_lexer_lookup_context_name_by_type(context), $1); node = (FilterExprNode *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!node) { YYERROR; } $$ = node; } ; filter_identifier : LL_PLUGIN | KW_THROTTLE { msg_warning_once("WARNING: the throttle() filter has been renamed to rate-limit() in " VERSION_3_36 ", please update your configuration to use the name rate-limit() instead of throttle()", cfg_lexer_format_location_tag(lexer, &@0)); $$ = g_strdup("rate-limit"); } ; filter_comparison : template_content operator { $$ = strdup(lexer->token_text->str); } template_content { $1 = _translate_number_literals(lexer, $2, $1, &@1); $4 = _translate_number_literals(lexer, $2, $4, &@4); $$ = fop_cmp_new($1, $4, $3, $2, cfg_lexer_format_location_tag(lexer, &@0)); free($3); } ; operator : KW_TA_LT { $$ = FCMP_TYPE_AWARE | FCMP_LT; } | KW_TA_LE { $$ = FCMP_TYPE_AWARE | FCMP_LT | FCMP_EQ; } | KW_TA_EQ { $$ = FCMP_TYPE_AWARE | FCMP_EQ; } | KW_TA_NE { $$ = FCMP_TYPE_AWARE | FCMP_LT | FCMP_GT; } | KW_TA_GE { $$ = FCMP_TYPE_AWARE | FCMP_EQ | FCMP_GT; } | KW_TA_GT { $$ = FCMP_TYPE_AWARE | FCMP_GT; } | KW_STR_LT { $$ = FCMP_STRING_BASED | FCMP_LT; } | KW_STR_LE { $$ = FCMP_STRING_BASED | FCMP_LT | FCMP_EQ; } | KW_STR_EQ { $$ = FCMP_STRING_BASED | FCMP_EQ; } | KW_STR_NE { $$ = FCMP_STRING_BASED | FCMP_LT | FCMP_GT; } | KW_STR_GE { $$ = FCMP_STRING_BASED | FCMP_EQ | FCMP_GT; } | KW_STR_GT { $$ = FCMP_STRING_BASED | FCMP_GT; } | KW_TAV_EQ { $$ = FCMP_TYPE_AND_VALUE_BASED | FCMP_EQ; } | KW_TAV_NE { $$ = FCMP_TYPE_AND_VALUE_BASED | FCMP_LT | FCMP_GT; } ; filter_re : KW_PROGRAM { $$ = last_filter_expr = filter_re_new(LM_V_PROGRAM); } filter_re_params { $$ = $2; } | KW_HOST { $$ = last_filter_expr = filter_re_new(LM_V_HOST); } filter_re_params { $$ = $2; } | KW_MESSAGE { $$ = last_filter_expr = filter_re_new(LM_V_MESSAGE); } filter_re_params { $$ = $2; } | KW_SOURCE { $$ = last_filter_expr = filter_source_new(); } filter_re_params { $$ = $2; } | KW_MATCH { $$ = last_filter_expr = filter_match_new(); } filter_match_params { $$ = $2; } ; filter_re_params : '(' string filter_re_opts ')' { GError *error = NULL; CHECK_ERROR_GERROR(filter_re_compile_pattern(last_filter_expr, $2, &error), @2, error, "compiling the regexp failed"); free($2); } ; filter_re_opts : filter_re_opt filter_re_opts | ; filter_re_opt : { last_matcher_options = filter_re_get_matcher_options(last_filter_expr); } matcher_option ; filter_match_params : '(' string filter_match_opts ')' { GError *error = NULL; CHECK_ERROR_GERROR(filter_re_compile_pattern(last_filter_expr, $2, &error), @2, error, "compiling the regexp failed"); free($2); if (filter_match_is_usage_obsolete(last_filter_expr)) { msg_warning_once("WARNING: the match() filter without the use of the value() " "option is deprecated and hinders performance, please use a " "more specific filter like message() and/or program() instead", cfg_lexer_format_location_tag(lexer, &@0)); } } filter_match_opts : filter_match_opt filter_match_opts | ; filter_match_opt : filter_re_opt | KW_VALUE '(' string ')' { const gchar *p = $3; if (p[0] == '$') { msg_warning("WARNING: value references in filters should not use the '$' prefix, those are only needed in templates, removing automatically", evt_tag_str("value", $3), cfg_lexer_format_location_tag(lexer, &@3)); p++; } if (p[0] == '(' || strchr(p, '$') != NULL) { msg_error("value() reference for the match() filter cannot contain a full template string, use the template() option or stick to a single value", evt_tag_str("value", $3), cfg_lexer_format_location_tag(lexer, &@3)); free($3); YYERROR; } filter_match_set_value_handle(last_filter_expr, log_msg_get_value_handle(p)); free($3); } | KW_TEMPLATE '(' template_content ')' { filter_match_set_template_ref(last_filter_expr, $3); } ; filter_fac_list : filter_fac filter_fac_list { $$ = $1 | $2; } | filter_fac { $$ = $1; } ; filter_fac : facility_string LL_DOTDOT facility_string { $$ = syslog_make_range($1 >> 3, $3 >> 3); } | facility_string { $$ = 1 << ($1 >> 3); } ; filter_severity_list : filter_severity filter_severity_list { $$ = $1 | $2; } | filter_severity { $$ = $1; } ; filter_severity : severity_string LL_DOTDOT severity_string { $$ = syslog_make_range($1, $3); } | severity_string { $$ = 1 << $1; } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/filter/filter-expr-parser.c000066400000000000000000000057131450431004300233130ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter/filter-expr-parser.h" #include "filter/filter-expr-grammar.h" #include "filter/filter-expr.h" extern int filter_expr_debug; int filter_expr_parse(CfgLexer *lexer, FilterExprNode **node, gpointer arg); static CfgLexerKeyword filter_expr_keywords[] = { { "or", KW_OR }, { "and", KW_AND }, { "not", KW_NOT }, { "lt", KW_STR_LT }, { "le", KW_STR_LE }, { "eq", KW_STR_EQ }, { "ne", KW_STR_NE }, { "ge", KW_STR_GE }, { "gt", KW_STR_GT }, /* type aware comparisons */ { "<", KW_TA_LT }, { "<=", KW_TA_LE }, { "==", KW_TA_EQ }, { "!=", KW_TA_NE }, { ">=", KW_TA_GE }, { ">", KW_TA_GT }, /* equal type and value */ { "===", KW_TAV_EQ }, { "!==", KW_TAV_NE }, /* filter expressions */ { "severity", KW_SEVERITY }, { "level", KW_SEVERITY }, { "priority", KW_SEVERITY }, { "facility", KW_FACILITY }, { "program", KW_PROGRAM }, { "host", KW_HOST }, { "message", KW_MESSAGE }, { "match", KW_MATCH }, { "netmask", KW_NETMASK }, { "throttle", KW_THROTTLE }, { "tags", KW_TAGS }, { "in_list", KW_IN_LIST }, #if SYSLOG_NG_ENABLE_IPV6 { "netmask6", KW_NETMASK6 }, #endif { "value", KW_VALUE }, { "flags", KW_FLAGS }, { NULL } }; CfgParser filter_expr_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &filter_expr_debug, #endif .name = "filter expression", .context = LL_CONTEXT_FILTER, .keywords = filter_expr_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) filter_expr_parse, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(filter_expr_, FILTER_EXPR_, FilterExprNode **) syslog-ng-syslog-ng-4.4.0/lib/filter/filter-expr-parser.h000066400000000000000000000023611450431004300233140ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_EXPR_PARSER_H_INCLUDED #define FILTER_EXPR_PARSER_H_INCLUDED #include "cfg-parser.h" #include "filter/filter-expr.h" extern CfgParser filter_expr_parser; CFG_PARSER_DECLARE_LEXER_BINDING(filter_expr_, FILTER_EXPR_, FilterExprNode **) #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-expr.c000066400000000000000000000060161450431004300220160ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter/filter-expr.h" #include "messages.h" /**************************************************************** * Filter expression nodes ****************************************************************/ void filter_expr_node_init_instance(FilterExprNode *self) { self->ref_cnt = 1; } /* * In case the filter would modify the message the caller has to make sure * that the message is writable. You can always archieve that with * filter_expr_eval_root() below, but you have to be on a processing path to * do that. */ gboolean filter_expr_eval_with_context(FilterExprNode *self, LogMessage **msg, gint num_msg, LogTemplateEvalOptions *options) { gboolean res; g_assert(num_msg > 0); res = self->eval(self, msg, num_msg, options); return res; } gboolean filter_expr_eval(FilterExprNode *self, LogMessage *msg) { return filter_expr_eval_with_context(self, &msg, 1, &DEFAULT_TEMPLATE_EVAL_OPTIONS); } gboolean filter_expr_eval_root_with_context(FilterExprNode *self, LogMessage **msg, gint num_msg, LogTemplateEvalOptions *options, const LogPathOptions *path_options) { g_assert(num_msg > 0); if (self->modify) log_msg_make_writable(&msg[num_msg - 1], path_options); return filter_expr_eval_with_context(self, msg, num_msg, options); } gboolean filter_expr_eval_root(FilterExprNode *self, LogMessage **msg, const LogPathOptions *path_options) { return filter_expr_eval_root_with_context(self, msg, 1, &DEFAULT_TEMPLATE_EVAL_OPTIONS, path_options); } static FilterExprNode * filter_expr_ref(FilterExprNode *self) { self->ref_cnt++; return self; } void filter_expr_unref(FilterExprNode *self) { if (self && (--self->ref_cnt == 0)) { if (self->free_fn) self->free_fn(self); g_free(self); } } FilterExprNode * filter_expr_clone(FilterExprNode *self) { if (!self) return NULL; if (!self->clone) return filter_expr_ref(self); FilterExprNode *cloned = self->clone(self); cloned->comp = self->comp; return cloned; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-expr.h000066400000000000000000000051051450431004300220210ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_H_INCLUDED #define FILTER_H_INCLUDED #include "syslog-ng.h" #include "logpipe.h" #include "stats/stats-registry.h" struct _GlobalConfig; typedef struct _FilterExprNode FilterExprNode; struct _FilterExprNode { guint32 ref_cnt; guint32 comp:1, /* this not is negated */ modify:1; /* this filter changes the log message */ const gchar *type; gboolean (*init)(FilterExprNode *self, GlobalConfig *cfg); gboolean (*eval)(FilterExprNode *self, LogMessage **msg, gint num_msg, LogTemplateEvalOptions *options); FilterExprNode *(*clone)(FilterExprNode *self); void (*free_fn)(FilterExprNode *self); StatsCounterItem *matched; StatsCounterItem *not_matched; }; static inline gboolean filter_expr_init(FilterExprNode *self, GlobalConfig *cfg) { if (self->init) return self->init(self, cfg); return TRUE; } gboolean filter_expr_eval(FilterExprNode *self, LogMessage *msg); gboolean filter_expr_eval_with_context(FilterExprNode *self, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options); gboolean filter_expr_eval_root(FilterExprNode *self, LogMessage **msg, const LogPathOptions *path_options); gboolean filter_expr_eval_root_with_context(FilterExprNode *self, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options, const LogPathOptions *path_options); void filter_expr_node_init_instance(FilterExprNode *self); void filter_expr_unref(FilterExprNode *self); FilterExprNode *filter_expr_clone(FilterExprNode *self); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-in-list.c000066400000000000000000000055231450431004300224210ustar00rootroot00000000000000/* * Copyright (c) 2013, 2014 Balabit * Copyright (c) 2013, 2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-in-list.h" #include "logmsg/logmsg.h" #include "str-utils.h" #include #include #include #include typedef struct _FilterInList { FilterExprNode super; NVHandle value_handle; GTree *tree; } FilterInList; static gboolean filter_in_list_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterInList *self = (FilterInList *)s; LogMessage *msg = msgs[num_msg - 1]; const gchar *value; gssize len = 0; value = log_msg_get_value(msg, self->value_handle, &len); APPEND_ZERO(value, value, len); gboolean result = (g_tree_lookup(self->tree, value) != NULL); msg_trace("in-list() evaluation started", evt_tag_str("value", value), evt_tag_msg_reference(msg)); return result ^ s->comp; } static void filter_in_list_free(FilterExprNode *s) { FilterInList *self = (FilterInList *)s; g_tree_destroy(self->tree); } FilterExprNode * filter_in_list_new(const gchar *list_file, const gchar *property) { FilterInList *self; FILE *stream; gchar line[16384]; stream = fopen(list_file, "r"); if (!stream) { msg_error("Error opening in-list filter list file", evt_tag_str("file", list_file), evt_tag_error("errno")); return NULL; } self = g_new0(FilterInList, 1); filter_expr_node_init_instance(&self->super); self->value_handle = log_msg_get_value_handle(property); self->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL, g_free, NULL); while (fgets(line, sizeof(line), stream) != NULL) { line[strlen(line) - 1] = '\0'; if (line[0]) g_tree_insert(self->tree, g_strdup(line), GINT_TO_POINTER(1)); } fclose(stream); self->super.eval = filter_in_list_eval; self->super.free_fn = filter_in_list_free; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-in-list.h000066400000000000000000000023211450431004300224170ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_IN_LIST_H_INCLUDED #define FILTER_IN_LIST_H_INCLUDED #include "filter-expr.h" FilterExprNode *filter_in_list_new(const gchar *list_file, const gchar *property); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-netmask.c000066400000000000000000000061731450431004300225060ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-netmask.h" #include "gsocket.h" #include "logmsg/logmsg.h" #include #include typedef struct _FilterNetmask { FilterExprNode super; struct in_addr address; struct in_addr netmask; } FilterNetmask; static gboolean filter_netmask_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterNetmask *self = (FilterNetmask *) s; struct in_addr *addr, addr_storage; LogMessage *msg = msgs[num_msg - 1]; gboolean res; if (msg->saddr && g_sockaddr_inet_check(msg->saddr)) { addr = &((struct sockaddr_in *) &msg->saddr->sa)->sin_addr; } else if (!msg->saddr || msg->saddr->sa.sa_family == AF_UNIX) { addr_storage.s_addr = htonl(INADDR_LOOPBACK); addr = &addr_storage; } else { addr = NULL; } if (addr) res = ((addr->s_addr & self->netmask.s_addr) == (self->address.s_addr)); else res = FALSE; msg_trace("netmask() evaluation started", evt_tag_inaddr("msg_address", addr), evt_tag_inaddr("address", &self->address), evt_tag_inaddr("netmask", &self->netmask), evt_tag_msg_reference(msg)); return res ^ s->comp; } FilterExprNode * filter_netmask_new(const gchar *cidr) { FilterNetmask *self = g_new0(FilterNetmask, 1); gchar buf[32]; gchar *slash; filter_expr_node_init_instance(&self->super); slash = strchr(cidr, '/'); if (strlen(cidr) >= sizeof(buf) || !slash) { g_inet_aton(cidr, &self->address); self->netmask.s_addr = htonl(0xFFFFFFFF); } else { strncpy(buf, cidr, slash - cidr); buf[slash - cidr] = 0; g_inet_aton(buf, &self->address); if (strchr(slash + 1, '.')) { g_inet_aton(slash + 1, &self->netmask); } else { gint prefix = strtol(slash + 1, NULL, 10); if (prefix == 32) self->netmask.s_addr = htonl(0xFFFFFFFF); else self->netmask.s_addr = htonl(((1 << prefix) - 1) << (32 - prefix)); } } self->address.s_addr &= self->netmask.s_addr; self->super.eval = filter_netmask_eval; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-netmask.h000066400000000000000000000022131450431004300225020ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_NETMASK_H_INCLUDED #define FILTER_NETMASK_H_INCLUDED #include "filter-expr.h" FilterExprNode *filter_netmask_new(const gchar *cidr); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-netmask6.c000066400000000000000000000106321450431004300225670ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Zoltan Fried * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-netmask6.h" #include "gsocket.h" #include "logmsg/logmsg.h" #include #include #include #include #if SYSLOG_NG_ENABLE_IPV6 typedef struct _FilterNetmask6 { FilterExprNode super; struct in6_addr address; int prefix; gboolean is_valid; } FilterNetmask6; static inline uint64_t _calculate_mask_by_prefix(int prefix) { return (uint64_t) (~0) << (64 - prefix); } static inline uint64_t _mask(uint64_t base, uint64_t mask) { if (G_BYTE_ORDER == G_BIG_ENDIAN) { return base & mask; } else { const uint64_t reversed_base = GUINT64_SWAP_LE_BE(base); return GUINT64_SWAP_LE_BE(reversed_base & mask); } } void get_network_address(const struct in6_addr *address, int prefix, struct in6_addr *network) { struct ipv6_parts { uint64_t lo; uint64_t hi; } ipv6_parts; int length; memset(network, 0, sizeof(*network)); memcpy(&ipv6_parts, address, sizeof(*address)); if (prefix <= 64) { ipv6_parts.lo = _mask(ipv6_parts.lo, _calculate_mask_by_prefix(prefix)); length = sizeof(uint64_t); } else { ipv6_parts.hi = _mask(ipv6_parts.hi, _calculate_mask_by_prefix(prefix - 64)); length = 2 * sizeof(uint64_t); } memcpy(network->s6_addr, &ipv6_parts, length); } static inline gboolean _in6_addr_compare(const struct in6_addr *address1, const struct in6_addr *address2) { return memcmp(address1, address2, sizeof(struct in6_addr)) == 0; } static gboolean _eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterNetmask6 *self = (FilterNetmask6 *) s; LogMessage *msg = msgs[num_msg - 1]; gboolean result = FALSE; struct in6_addr network_address; const struct in6_addr *address; if (!self->is_valid) return s->comp; if (msg->saddr && g_sockaddr_inet6_check(msg->saddr)) { address = &((struct sockaddr_in6 *) &msg->saddr->sa)->sin6_addr; } else if (!msg->saddr || msg->saddr->sa.sa_family == AF_UNIX) { address = &in6addr_loopback; } else { address = NULL; } if (address) { get_network_address(address, self->prefix, &network_address); result = _in6_addr_compare(&network_address, &self->address); } else result = FALSE; msg_trace("netmask6() evaluation started", evt_tag_inaddr6("msg_address", address), evt_tag_inaddr6("address", &self->address), evt_tag_int("prefix", self->prefix), evt_tag_msg_reference(msg)); return result ^ s->comp; } FilterExprNode * filter_netmask6_new(const gchar *cidr) { FilterNetmask6 *self = g_new0(FilterNetmask6, 1); struct in6_addr packet_addr; gchar address[INET6_ADDRSTRLEN]; gchar *slash = strchr(cidr, '/'); filter_expr_node_init_instance(&self->super); if (strlen(cidr) >= sizeof(address) || !slash) { self->is_valid = inet_pton(AF_INET6, cidr, &packet_addr) == 1; self->prefix = 128; } else { self->prefix = strtol(slash + 1, NULL, 10); if (self->prefix > 0 && self->prefix < 129) { strncpy(address, cidr, slash - cidr); address[slash - cidr] = 0; self->is_valid = inet_pton(AF_INET6, address, &packet_addr) == 1; } } if (self->is_valid) get_network_address(&packet_addr, self->prefix, &self->address); else self->address = in6addr_loopback; self->super.eval = _eval; return &self->super; } #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-netmask6.h000066400000000000000000000023371450431004300225770ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Zoltan Fried * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_NETMASK6_H_INCLUDED #define FILTER_NETMASK6_H_INCLUDED #include "filter-expr.h" FilterExprNode *filter_netmask6_new(const gchar *cidr); void get_network_address(const struct in6_addr *address, int prefix, struct in6_addr *network); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-op.c000066400000000000000000000070311450431004300214540ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-op.h" typedef struct _FilterOp { FilterExprNode super; FilterExprNode *left, *right; } FilterOp; static gboolean fop_init(FilterExprNode *s, GlobalConfig *cfg) { FilterOp *self = (FilterOp *) s; g_assert(self->left); g_assert(self->right); if (!filter_expr_init(self->left, cfg)) return FALSE; if (!filter_expr_init(self->right, cfg)) return FALSE; self->super.modify = self->left->modify || self->right->modify; return TRUE; } static void fop_free(FilterExprNode *s) { FilterOp *self = (FilterOp *) s; filter_expr_unref(self->left); filter_expr_unref(self->right); g_free((gchar *) self->super.type); } FilterExprNode * fop_clone(FilterExprNode *s) { FilterOp *self = (FilterOp *) s; FilterOp *cloned_self = g_new0(FilterOp, 1); filter_expr_node_init_instance(&cloned_self->super); cloned_self->super.init = fop_init; cloned_self->super.free_fn = fop_free; cloned_self->super.clone = fop_clone; cloned_self->super.eval = self->super.eval; cloned_self->left = filter_expr_clone(self->left); cloned_self->right = filter_expr_clone(self->right); cloned_self->super.type = g_strdup(self->super.type); return &cloned_self->super; } static void fop_init_instance(FilterOp *self) { filter_expr_node_init_instance(&self->super); self->super.init = fop_init; self->super.free_fn = fop_free; self->super.clone = fop_clone; } static gboolean fop_or_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterOp *self = (FilterOp *) s; return (filter_expr_eval_with_context(self->left, msgs, num_msg, options) || filter_expr_eval_with_context(self->right, msgs, num_msg, options)) ^ s->comp; } FilterExprNode * fop_or_new(FilterExprNode *e1, FilterExprNode *e2) { FilterOp *self = g_new0(FilterOp, 1); fop_init_instance(self); self->super.eval = fop_or_eval; self->left = e1; self->right = e2; self->super.type = g_strdup("OR"); return &self->super; } static gboolean fop_and_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterOp *self = (FilterOp *) s; return (filter_expr_eval_with_context(self->left, msgs, num_msg, options) && filter_expr_eval_with_context(self->right, msgs, num_msg, options)) ^ s->comp; } FilterExprNode * fop_and_new(FilterExprNode *e1, FilterExprNode *e2) { FilterOp *self = g_new0(FilterOp, 1); fop_init_instance(self); self->super.eval = fop_and_eval; self->left = e1; self->right = e2; self->super.type = g_strdup("AND"); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-op.h000066400000000000000000000023231450431004300214600ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_OP_H_INCLUDED #define FILTER_OP_H_INCLUDED #include "filter-expr.h" FilterExprNode *fop_or_new(FilterExprNode *e1, FilterExprNode *e2); FilterExprNode *fop_and_new(FilterExprNode *e1, FilterExprNode *e2); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-pipe.c000066400000000000000000000106061450431004300217750ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter/filter-pipe.h" #include "stats/stats-registry.h" /******************************************************************* * LogFilterPipe *******************************************************************/ static gboolean log_filter_pipe_init(LogPipe *s) { LogFilterPipe *self = (LogFilterPipe *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!filter_expr_init(self->expr, cfg)) return FALSE; if (!self->name) self->name = cfg_tree_get_rule_name(&cfg->tree, ENC_FILTER, s->expr_node); stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->name) }; stats_cluster_logpipe_key_set(&sc_key, "filtered_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_FILTER, self->name, NULL ); stats_register_counter(1, &sc_key, SC_TYPE_MATCHED, &self->matched); stats_register_counter(1, &sc_key, SC_TYPE_NOT_MATCHED, &self->not_matched); stats_unlock(); return TRUE; } static void log_filter_pipe_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogFilterPipe *self = (LogFilterPipe *) s; gboolean res; gchar *filter_result; msg_trace(">>>>>> filter rule evaluation begin", evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); res = filter_expr_eval_root(self->expr, &msg, path_options); if (res) { filter_result = "MATCH - Forwarding message to the next LogPipe"; log_pipe_forward_msg(s, msg, path_options); stats_counter_inc(self->matched); } else { filter_result = "UNMATCHED - Dropping message from LogPipe"; if (path_options->matched) (*path_options->matched) = FALSE; log_msg_drop(msg, path_options, AT_PROCESSED); stats_counter_inc(self->not_matched); } msg_trace("<<<<<< filter rule evaluation result", evt_tag_str("result", filter_result), evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); } static LogPipe * log_filter_pipe_clone(LogPipe *s) { LogFilterPipe *self = (LogFilterPipe *) s; FilterExprNode *expr = filter_expr_clone(self->expr); LogPipe *cloned = log_filter_pipe_new(expr, s->cfg); ((LogFilterPipe *)cloned)->name = g_strdup(self->name); return cloned; } static void log_filter_pipe_free(LogPipe *s) { LogFilterPipe *self = (LogFilterPipe *) s; stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->name) }; stats_cluster_logpipe_key_set(&sc_key, "filtered_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_FILTER, self->name, NULL ); stats_unregister_counter(&sc_key, SC_TYPE_MATCHED, &self->matched); stats_unregister_counter(&sc_key, SC_TYPE_NOT_MATCHED, &self->not_matched); stats_unlock(); g_free(self->name); filter_expr_unref(self->expr); log_pipe_free_method(s); } LogPipe * log_filter_pipe_new(FilterExprNode *expr, GlobalConfig *cfg) { LogFilterPipe *self = g_new0(LogFilterPipe, 1); log_pipe_init_instance(&self->super, cfg); self->super.flags |= PIF_CONFIG_RELATED; self->super.init = log_filter_pipe_init; self->super.queue = log_filter_pipe_queue; self->super.free_fn = log_filter_pipe_free; self->super.clone = log_filter_pipe_clone; self->expr = expr; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-pipe.h000066400000000000000000000027731450431004300220100ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_PIPE_H_INCLUDED #define FILTER_PIPE_H_INCLUDED #include "filter/filter-expr.h" #include "logpipe.h" /* convert a filter expression into a drop/accept LogPipe */ /* * This class encapsulates a LogPipe that either drops/allows a LogMessage * to go through. */ typedef struct _LogFilterPipe { LogPipe super; FilterExprNode *expr; gchar *name; StatsCounterItem *matched; StatsCounterItem *not_matched; } LogFilterPipe; LogPipe *log_filter_pipe_new(FilterExprNode *expr, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-pri.c000066400000000000000000000055661450431004300216430ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter/filter-pri.h" #include "syslog-names.h" #include "logmsg/logmsg.h" typedef struct _FilterPri { FilterExprNode super; guint32 valid; } FilterPri; static gboolean filter_facility_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterPri *self = (FilterPri *) s; LogMessage *msg = msgs[num_msg - 1]; guint32 fac_num = (msg->pri & SYSLOG_FACMASK) >> 3; gboolean res; if (G_UNLIKELY(self->valid & 0x80000000)) { /* exact number specified */ res = ((self->valid & ~0x80000000) == fac_num); } else { res = !!(self->valid & (1 << fac_num)); } msg_trace("facility() evaluation started", evt_tag_int("fac", fac_num), evt_tag_printf("valid_fac", "%08x", self->valid), evt_tag_msg_reference(msg)); return res ^ s->comp; } FilterExprNode * filter_facility_new(guint32 facilities) { FilterPri *self = g_new0(FilterPri, 1); filter_expr_node_init_instance(&self->super); self->super.eval = filter_facility_eval; self->valid = facilities; self->super.type = "facility"; return &self->super; } static gboolean filter_severity_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterPri *self = (FilterPri *) s; LogMessage *msg = msgs[num_msg - 1]; guint32 pri = msg->pri & SYSLOG_PRIMASK; gboolean res; res = !!((1 << pri) & self->valid); msg_trace("severity() evaluation started", evt_tag_int("pri", pri), evt_tag_printf("valid_pri", "%08x", self->valid), evt_tag_msg_reference(msg)); return res ^ s->comp; } FilterExprNode * filter_severity_new(guint32 levels) { FilterPri *self = g_new0(FilterPri, 1); filter_expr_node_init_instance(&self->super); self->super.eval = filter_severity_eval; self->valid = levels; self->super.type = "severity"; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-pri.h000066400000000000000000000022721450431004300216370ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_PRI_H_INCLUDED #define FILTER_PRI_H_INCLUDED #include "filter-expr.h" FilterExprNode *filter_facility_new(guint32 facilities); FilterExprNode *filter_severity_new(guint32 levels); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-re.c000066400000000000000000000155171450431004300214540ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-re.h" #include "str-utils.h" #include "messages.h" #include "scratch-buffers.h" #include typedef struct _FilterRE { FilterExprNode super; NVHandle value_handle; LogMatcherOptions matcher_options; LogMatcher *matcher; } FilterRE; static gboolean filter_re_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterRE *self = (FilterRE *) s; LogMessage *msg = msgs[num_msg - 1]; gboolean result; msg_trace("match() evaluation started against a name-value pair", evt_tag_msg_value_name("name", self->value_handle), evt_tag_msg_value("value", msg, self->value_handle), evt_tag_str("pattern", self->matcher->pattern), evt_tag_msg_reference(msg)); result = log_matcher_match_value(self->matcher, msg, self->value_handle); return result ^ s->comp; } static void filter_re_free(FilterExprNode *s) { FilterRE *self = (FilterRE *) s; log_matcher_unref(self->matcher); log_matcher_options_destroy(&self->matcher_options); } static gboolean filter_re_init(FilterExprNode *s, GlobalConfig *cfg) { FilterRE *self = (FilterRE *) s; if (self->matcher_options.flags & LMF_STORE_MATCHES) self->super.modify = TRUE; return TRUE; } LogMatcherOptions * filter_re_get_matcher_options(FilterExprNode *s) { FilterRE *self = (FilterRE *) s; return &self->matcher_options; } gboolean filter_re_compile_pattern(FilterExprNode *s, const gchar *re, GError **error) { FilterRE *self = (FilterRE *) s; log_matcher_options_init(&self->matcher_options); self->matcher = log_matcher_new(&self->matcher_options); return log_matcher_compile(self->matcher, re, error); } static void filter_re_init_instance(FilterRE *self, NVHandle value_handle) { filter_expr_node_init_instance(&self->super); self->value_handle = value_handle; self->super.init = filter_re_init; self->super.eval = filter_re_eval; self->super.free_fn = filter_re_free; self->super.type = "regexp"; log_matcher_options_defaults(&self->matcher_options); self->matcher_options.flags |= LMF_MATCH_ONLY; } FilterExprNode * filter_re_new(NVHandle value_handle) { FilterRE *self = g_new0(FilterRE, 1); filter_re_init_instance(self, value_handle); return &self->super; } FilterExprNode * filter_source_new(void) { FilterRE *self = (FilterRE *) filter_re_new(LM_V_SOURCE); if (!log_matcher_options_set_type(&self->matcher_options, "string")) { /* this can only happen if the plain text string matcher will cease to exist */ g_assert_not_reached(); } return &self->super; } typedef struct _FilterMatch { FilterRE super; LogTemplate *template; } FilterMatch; gboolean filter_match_is_usage_obsolete(FilterExprNode *s) { FilterMatch *self = (FilterMatch *) s; return self->super.value_handle == 0 && self->template == NULL; } void filter_match_set_value_handle(FilterExprNode *s, NVHandle value_handle) { FilterMatch *self = (FilterMatch *) s; self->super.value_handle = value_handle; } void filter_match_set_template_ref(FilterExprNode *s, LogTemplate *template) { FilterMatch *self = (FilterMatch *) s; log_template_unref(self->template); self->template = template; } static gboolean filter_match_eval_against_program_pid_msg(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterMatch *self = (FilterMatch *) s; const gchar *pid; gssize pid_len; gchar *str; gboolean result; LogMessage *msg = msgs[num_msg - 1]; pid = log_msg_get_value(msg, LM_V_PID, &pid_len); /* compatibility mode */ str = g_strdup_printf("%s%s%s%s: %s", log_msg_get_value(msg, LM_V_PROGRAM, NULL), pid_len > 0 ? "[" : "", pid, pid_len > 0 ? "]" : "", log_msg_get_value(msg, LM_V_MESSAGE, NULL)); msg_trace("match() evaluation started against constructed $PROGRAM[$PID]: $MESSAGE string for compatibility", evt_tag_printf("input", "%s", str), evt_tag_str("pattern", self->super.matcher->pattern), evt_tag_msg_reference(msg)); result = log_matcher_match_buffer(self->super.matcher, msg, str, -1); g_free(str); return result ^ s->comp; } static gboolean filter_match_eval_against_template(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterMatch *self = (FilterMatch *) s; LogMessage *msg = msgs[num_msg - 1]; msg_trace("match() evaluation started against template", evt_tag_template("input", self->template, msg, options), evt_tag_str("pattern", self->super.matcher->pattern), evt_tag_str("template", self->template->template_str), evt_tag_msg_reference(msg)); gboolean result = log_matcher_match_template(self->super.matcher, msg, self->template, options); return result ^ s->comp; } static void filter_match_determine_eval_function(FilterMatch *self) { if (self->super.value_handle) self->super.super.eval = filter_re_eval; else if (self->template) self->super.super.eval = filter_match_eval_against_template; else self->super.super.eval = filter_match_eval_against_program_pid_msg; } static gboolean filter_match_init(FilterExprNode *s, GlobalConfig *cfg) { FilterMatch *self = (FilterMatch *) s; if (!filter_re_init(s, cfg)) return FALSE; filter_match_determine_eval_function(self); return TRUE; } static void filter_match_free(FilterExprNode *s) { FilterMatch *self = (FilterMatch *) s; log_template_unref(self->template); filter_re_free(&self->super.super); } FilterExprNode * filter_match_new(void) { FilterMatch *self = g_new0(FilterMatch, 1); filter_re_init_instance(&self->super, 0); self->super.super.init = filter_match_init; self->super.super.free_fn = filter_match_free; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-re.h000066400000000000000000000031401450431004300214460ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_RE_H_INCLUDED #define FILTER_RE_H_INCLUDED #include "filter-expr.h" #include "logmatcher.h" LogMatcherOptions *filter_re_get_matcher_options(FilterExprNode *s); gboolean filter_re_compile_pattern(FilterExprNode *s, const gchar *re, GError **error); FilterExprNode *filter_re_new(NVHandle value_handle); FilterExprNode *filter_source_new(void); gboolean filter_match_is_usage_obsolete(FilterExprNode *s); void filter_match_set_value_handle(FilterExprNode *s, NVHandle value_handle); void filter_match_set_template_ref(FilterExprNode *s, LogTemplate *template); FilterExprNode *filter_match_new(void); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/filter-tags.c000066400000000000000000000052751450431004300220040ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "filter-tags.h" #include "logmsg/logmsg.h" typedef struct _FilterTags { FilterExprNode super; GArray *tags; } FilterTags; static gboolean filter_tags_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options) { FilterTags *self = (FilterTags *)s; LogMessage *msg = msgs[num_msg - 1]; gboolean res; gint i; for (i = 0; i < self->tags->len; i++) { LogTagId tag_id = g_array_index(self->tags, LogTagId, i); if (log_msg_is_tag_by_id(msg, tag_id)) { res = TRUE; msg_trace("tags() evaluation started", evt_tag_str("tag", log_tags_get_by_id(tag_id)), evt_tag_msg_reference(msg)); return res ^ s->comp; } } res = FALSE; msg_trace("tags() evaluation started", evt_tag_msg_reference(msg)); return res ^ s->comp; } void filter_tags_add(FilterExprNode *s, GList *tags) { FilterTags *self = (FilterTags *)s; LogTagId id; while (tags) { id = log_tags_get_by_name((gchar *) tags->data); g_free(tags->data); tags = g_list_delete_link(tags, tags); g_array_append_val(self->tags, id); } } static void filter_tags_free(FilterExprNode *s) { FilterTags *self = (FilterTags *)s; g_array_free(self->tags, TRUE); } FilterExprNode * filter_tags_new(GList *tags) { FilterTags *self = g_new0(FilterTags, 1); filter_expr_node_init_instance(&self->super); self->tags = g_array_new(FALSE, FALSE, sizeof(LogTagId)); filter_tags_add(&self->super, tags); self->super.eval = filter_tags_eval; self->super.free_fn = filter_tags_free; self->super.type = "tags"; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/filter/filter-tags.h000066400000000000000000000022621450431004300220020ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FILTER_TAGS_H_INCLUDED #define FILTER_TAGS_H_INCLUDED #include "filter-expr.h" void filter_tags_add(FilterExprNode *s, GList *tags); FilterExprNode *filter_tags_new(GList *tags); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/tests/000077500000000000000000000000001450431004300205505ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/filter/tests/CMakeLists.txt000066400000000000000000000033651450431004300233170ustar00rootroot00000000000000set(TEST_FILTERS_FACILITY_SOURCE test_filters_facility.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_LEVEL_NEW_SOURCE test_filters_level_new.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_REGEXP_SOURCE test_filters_regexp.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_FOP_CMP_SOURCE test_filters_fop_cmp.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_FOP_SOURCE test_filters_fop.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_NETMASK_SOURCE test_filters_netmask.c test_filters_common.c test_filters_common.h ) set(TEST_FILTERS_NETMASK6_SOURCE test_filters_netmask6.c test_filters_common.c test_filters_common.h ) add_unit_test(CRITERION TARGET test_filters_facility SOURCES ${TEST_FILTERS_FACILITY_SOURCE} DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_filters_level_new SOURCES ${TEST_FILTERS_LEVEL_NEW_SOURCE} DEPENDS syslogformat) add_unit_test(LIBTEST CRITERION TARGET test_filters_regexp SOURCES ${TEST_FILTERS_REGEXP_SOURCE} DEPENDS syslogformat) add_unit_test(LIBTEST CRITERION TARGET test_filters_fop_cmp SOURCES ${TEST_FILTERS_FOP_CMP_SOURCE}) add_unit_test(CRITERION TARGET test_filters_fop SOURCES ${TEST_FILTERS_FOP_SOURCE} DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_filters_netmask SOURCES ${TEST_FILTERS_NETMASK_SOURCE} DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_filters_in_list DEPENDS syslogformat) if (ENABLE_IPV6) add_unit_test(CRITERION TARGET test_filters_netmask6 SOURCES ${TEST_FILTERS_NETMASK6_SOURCE} DEPENDS syslogformat) endif() add_unit_test(CRITERION TARGET test_filters_statistics DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_filter_call) syslog-ng-syslog-ng-4.4.0/lib/filter/tests/Makefile.am000066400000000000000000000074211450431004300226100ustar00rootroot00000000000000lib_filter_tests_TESTS = \ lib/filter/tests/test_filters_facility \ lib/filter/tests/test_filters_level_new \ lib/filter/tests/test_filter_call \ lib/filter/tests/test_filters_in_list \ lib/filter/tests/test_filters_regexp \ lib/filter/tests/test_filters_fop_cmp \ lib/filter/tests/test_filters_fop \ lib/filter/tests/test_filters_netmask EXTRA_DIST += lib/filter/tests/CMakeLists.txt if ENABLE_IPV6 lib_filter_tests_TESTS += lib/filter/tests/test_filters_netmask6 endif check_PROGRAMS += ${lib_filter_tests_TESTS} lib_filter_tests_test_filters_facility_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_facility_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_facility_SOURCES = \ lib/filter/tests/test_filters_facility.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_level_new_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_level_new_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_level_new_SOURCES = \ lib/filter/tests/test_filters_level_new.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_regexp_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_regexp_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_regexp_SOURCES = \ lib/filter/tests/test_filters_regexp.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_fop_cmp_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_fop_cmp_LDADD = $(TEST_LDADD) lib_filter_tests_test_filters_fop_cmp_SOURCES = \ lib/filter/tests/test_filters_fop_cmp.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_fop_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_fop_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_fop_SOURCES = \ lib/filter/tests/test_filters_fop.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_netmask_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_netmask_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_netmask_SOURCES = \ lib/filter/tests/test_filters_netmask.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h lib_filter_tests_test_filters_in_list_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_in_list_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) if ENABLE_IPV6 lib_filter_tests_test_filters_netmask6_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_netmask6_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filters_netmask6_SOURCES = \ lib/filter/tests/test_filters_netmask6.c \ lib/filter/tests/test_filters_common.c \ lib/filter/tests/test_filters_common.h endif lib_filter_tests_TESTS += lib/filter/tests/test_filters_statistics lib_filter_tests_test_filters_statistics_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filters_statistics_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_filter_tests_test_filter_call_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/filter/tests lib_filter_tests_test_filter_call_LDADD = $(TEST_LDADD) include lib/filter/tests/filters-in-list/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/000077500000000000000000000000001450431004300235755ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/Makefile.am000066400000000000000000000004171450431004300256330ustar00rootroot00000000000000EXTRA_DIST += \ lib/filter/tests/filters-in-list/test.list \ lib/filter/tests/filters-in-list/empty.list \ lib/filter/tests/filters-in-list/lot_of_lines.list \ lib/filter/tests/filters-in-list/ip.list \ lib/filter/tests/filters-in-list/long_line.list syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/empty.list000066400000000000000000000000001450431004300256160ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/ip.list000066400000000000000000000000341450431004300250770ustar00rootroot00000000000000192.168.1.1 192.168.255.254 syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/long_line.list000066400000000000000000000023211450431004300264360ustar00rootroot00000000000000foo-bar1 foo-bar2 foo-bar3 foo-bar4 foo-bar5 foo-bar6 foo-bar7 foo-bar8 foo-bar9 foo-bar10 test-hostAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA foo-bar11 foo-bar12 foo-bar13 foo-bar14 foo-bar15 foo-bar16 foo-bar17 foo-bar18 foo-bar19 foo-bar20 foo-bar21 foo-bar22 foo-bar23 foo-bar24 foo-bar25 foo-bar26 foo-bar27 foo-bar28 foo-bar29 foo-bar30 foo-bar31 foo-bar32 foo-bar33 foo-bar34 foo-bar35 foo-bar36 foo-bar37 foo-bar38 foo-bar39 foo-bar40 foo-bar41 foo-bar42 foo-bar43 foo-bar44 foo-bar45 foo-bar46 foo-bar47 foo-bar48 foo-bar49 foo-bar50 foo-bar51 foo-bar52 foo-bar53 foo-bar54 foo-bar55 foo-bar56 foo-bar57 foo-bar58 foo-bar59 foo-bar60 foo-bar61 foo-bar62 foo-bar63 foo-bar64 foo-bar65 foo-bar66 foo-bar67 foo-bar68 foo-bar69 foo-bar70 foo-bar71 foo-bar72 foo-bar73 foo-bar74 foo-bar75 foo-bar76 foo-bar77 foo-bar78 foo-bar79 foo-bar80 foo-bar81 foo-bar82 foo-bar83 foo-bar84 foo-bar85 foo-bar86 foo-bar87 foo-bar88 foo-bar89 foo-bar90 foo-bar91 foo-bar92 foo-bar93 foo-bar94 foo-bar95 foo-bar96 foo-bar97 foo-bar98 foo-bar99 foo-bar100 syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/lot_of_lines.list000066400000000000000000000017551450431004300271560ustar00rootroot00000000000000test-program foo-bar1 foo-bar2 foo-bar3 foo-bar4 foo-bar5 foo-bar6 foo-bar7 foo-bar8 foo-bar9 foo-bar10 foo-bar11 foo-bar12 foo-bar13 foo-bar14 foo-bar15 foo-bar16 foo-bar17 foo-bar18 foo-bar19 foo-bar20 foo-bar21 foo-bar22 foo-bar23 foo-bar24 foo-bar25 foo-bar26 foo-bar27 foo-bar28 foo-bar29 foo-bar30 foo-bar31 foo-bar32 foo-bar33 foo-bar34 foo-bar35 foo-bar36 foo-bar37 foo-bar38 foo-bar39 foo-bar40 foo-bar41 foo-bar42 foo-bar43 foo-bar44 foo-bar45 foo-bar46 foo-bar47 foo-bar48 foo-bar49 foo-bar50 foo-bar51 foo-bar52 foo-bar53 foo-bar54 foo-bar55 foo-bar56 foo-bar57 foo-bar58 foo-bar59 foo-bar60 foo-bar61 foo-bar62 foo-bar63 foo-bar64 foo-bar65 foo-bar66 foo-bar67 foo-bar68 foo-bar69 foo-bar70 foo-bar71 foo-bar72 foo-bar73 foo-bar74 foo-bar75 foo-bar76 foo-bar77 foo-bar78 foo-bar79 foo-bar80 foo-bar81 foo-bar82 foo-bar83 foo-bar84 foo-bar85 foo-bar86 foo-bar87 foo-bar88 foo-bar89 foo-bar90 foo-bar91 foo-bar92 foo-bar93 foo-bar94 foo-bar95 foo-bar96 foo-bar97 foo-bar98 foo-bar99 foo-bar100 syslog-ng-syslog-ng-4.4.0/lib/filter/tests/filters-in-list/test.list000066400000000000000000000000151450431004300254450ustar00rootroot00000000000000test-program syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filter_call.c000066400000000000000000000030331450431004300242320ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "filter/filter-call.h" #include "filter/filter-expr.h" #include "apphook.h" Test(filter_call, undefined_filter_ref) { FilterExprNode *filter = filter_call_new("undefined_filter", configuration); cr_assert_not_null(filter); cr_assert_not(filter_expr_init(filter, configuration)); filter_expr_unref(filter); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); } static void teardown(void) { app_shutdown(); cfg_free(configuration); } TestSuite(filter_call, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_common.c000066400000000000000000000151171450431004300250000ustar00rootroot00000000000000/* * Copyright (c) 2005-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "filter/filter-expr.h" #include "filter/filter-expr-grammar.h" #include "filter/filter-netmask.h" #include "filter/filter-netmask6.h" #include "filter/filter-op.h" #include "filter/filter-cmp.h" #include "filter/filter-tags.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "cfg.h" #include "messages.h" #include "syslog-names.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "plugin.h" #include "scratch-buffers.h" #include "msg-format.h" #include #include #include #include MsgFormatOptions parse_options; gint facility_bits(const gchar *fac) { return 1 << (syslog_name_lookup_facility_by_name(fac) >> 3); } gint level_bits(const gchar *lev) { return 1 << syslog_name_lookup_severity_by_name(lev); } gint level_range(const gchar *from, const gchar *to) { int r1, r2; r1 = syslog_name_lookup_severity_by_name(from); r2 = syslog_name_lookup_severity_by_name(to); return syslog_make_range(r1, r2); } FilterExprNode * compile_pattern(FilterExprNode *f, const gchar *regexp, const gchar *type, gint flags) { LogMatcherOptions *matcher_options = filter_re_get_matcher_options(f); gboolean result; log_matcher_options_defaults(matcher_options); matcher_options->flags = flags; log_matcher_options_set_type(matcher_options, type); result = filter_re_compile_pattern(f, regexp, NULL); if (result) return f; filter_expr_unref(f); return NULL; } FilterExprNode * create_pcre_regexp_filter(gint field, const gchar *regexp, gint flags) { return compile_pattern(filter_re_new(field), regexp, "pcre", flags); } FilterExprNode * create_pcre_regexp_match(const gchar *regexp, gint flags) { return compile_pattern(filter_match_new(), regexp, "pcre", flags); } LogTemplate * create_template(const gchar *template) { LogTemplate *t; t = log_template_new(configuration, NULL); cr_assert(log_template_compile(t, template, NULL)); return t; } #if SYSLOG_NG_ENABLE_IPV6 static gboolean _is_ipv6(const gchar *sockaddr) { return (NULL != strchr(sockaddr, ':')); } #endif static GSockAddr * _get_sockaddr(const gchar *sockaddr) { if (!sockaddr) return NULL; #if SYSLOG_NG_ENABLE_IPV6 if (_is_ipv6(sockaddr)) { return g_sockaddr_inet6_new(sockaddr, 5000); } #endif return g_sockaddr_inet_new(sockaddr, 5000); } void testcase_with_socket(const gchar *msg, const gchar *sockaddr, FilterExprNode *f, gboolean expected_result) { LogMessage *logmsg; gboolean res; res = filter_expr_init(f, configuration); cr_assert(res, "Filter init failed; msg='%s'\n", msg); logmsg = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); log_msg_set_saddr_ref(logmsg, _get_sockaddr(sockaddr)); res = filter_expr_eval(f, logmsg); cr_assert_eq(res, expected_result, "Filter test failed; msg='%s'\n", msg); f->comp = !f->comp; res = filter_expr_eval(f, logmsg); cr_assert_eq(res, !expected_result, "Filter test failed (negated); msg='%s'\n", msg); log_msg_unref(logmsg); filter_expr_unref(f); } void testcase(const gchar *msg, FilterExprNode *f, gboolean expected_result) { testcase_with_socket(msg, NULL, f, expected_result); } void testcase_with_backref_chk(const gchar *msg, FilterExprNode *f, gboolean expected_result, const gchar *name, const gchar *value ) { LogMessage *logmsg; const gchar *value_msg; NVTable *nv_table; gboolean res; gssize length; NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ"); gssize msglen; gchar buf[1024]; logmsg = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); log_msg_set_saddr_ref(logmsg, g_sockaddr_inet_new("10.10.0.1", 5000)); /* NOTE: we test how our filters cope with non-zero terminated values. We don't change message_len, only the value */ g_snprintf(buf, sizeof(buf), "%sAAAAAAAAAAAA", log_msg_get_value(logmsg, LM_V_MESSAGE, &msglen)); log_msg_set_value_by_name(logmsg, "MESSAGE2", buf, -1); /* add a non-zero terminated indirect value which contains the whole message */ log_msg_set_value_indirect(logmsg, nonasciiz, log_msg_get_value_handle("MESSAGE2"), 0, msglen); nv_table = nv_table_ref(logmsg->payload); res = filter_expr_eval(f, logmsg); cr_assert_eq(res, expected_result, "Filter test failed; msg='%s'\n", msg); nv_table_unref(nv_table); f->comp = 1; nv_table = nv_table_ref(logmsg->payload); res = filter_expr_eval(f, logmsg); cr_assert_eq(res, !expected_result, "Filter test failed (negated); msg='%s'\n", msg); value_msg = log_msg_get_value_by_name(logmsg, name, &length); nv_table_unref(nv_table); if(value == NULL || value[0] == 0) { cr_assert_not(value_msg != NULL && value_msg[0] != 0, "Filter test failed (NULL value chk); msg='%s', expected_value='%s', value_in_msg='%s'", msg, value, value_msg); } else { const gint value_len = strlen(value); cr_assert_eq(length, value_len); cr_assert_eq(strncmp(value_msg, value, value_len), 0, "Filter test failed (value chk); msg='%s', expected_value='%s', value_in_msg='%s'", msg, value, value_msg); } log_msg_unref(logmsg); filter_expr_unref(f); } void setup(void) { app_startup(); configuration = cfg_new_snippet(); cfg_load_module(configuration, "syslogformat"); msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); } void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_common.h000066400000000000000000000040331450431004300250000ustar00rootroot00000000000000/* * Copyright (c) 2005-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef __TEST_FILTER_COMMON_H__ #define __TEST_FILTER_COMMON_H__ #include "filter/filter-expr.h" void testcase_with_socket(const gchar *msg, const gchar *sockaddr, FilterExprNode *f, gboolean expected_result); void testcase(const gchar *msg, FilterExprNode *f, gboolean expected_result); void testcase_with_backref_chk(const gchar *msg, FilterExprNode *f, gboolean expected_result, const gchar *name, const gchar *value ); FilterExprNode *create_pcre_regexp_filter(gint field, const gchar *regexp, gint flags); FilterExprNode *create_pcre_regexp_match(const gchar *regexp, gint flags); LogTemplate *create_template(const gchar *template); FilterExprNode *compile_pattern(FilterExprNode *f, const gchar *regexp, const gchar *type, gint flags); gint facility_bits(const gchar *fac); gint level_bits(const gchar *lev); gint level_range(const gchar *from, const gchar *to); void setup(void); void teardown(void); #endif syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_facility.c000066400000000000000000000105351450431004300253130ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "test_filters_common.h" #include "filter/filter-expr.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "cfg.h" #include #include #include TestSuite(filter, .init = setup, .fini = teardown); typedef struct _FilterParamBits { const gchar *msg; const gchar *fac_str; gboolean expected_result; } FilterParamBits; ParameterizedTestParameters(filter, test_filter_facility_str) { static FilterParamBits test_data_list[] = { {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .fac_str = "user", .expected_result = TRUE}, {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .fac_str = "daemon", .expected_result = FALSE}, {.msg = "<2> openvpn[2499]: PTHREAD support initialized", .fac_str = "kern", .expected_result = TRUE}, {.msg = "<128> openvpn[2499]: PTHREAD support initialized", .fac_str = "local0", .expected_result = TRUE}, {.msg = "<32> openvpn[2499]: PTHREAD support initialized", .fac_str = "local1", .expected_result = FALSE}, {.msg = "<32> openvpn[2499]: PTHREAD support initialized", .fac_str = "auth", .expected_result = TRUE}, #ifdef LOG_AUTHPRIV {.msg = "<80> openvpn[2499]: PTHREAD support initialized", .fac_str = "authpriv", .expected_result = TRUE}, #endif }; return cr_make_param_array(FilterParamBits, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamBits *param, filter, test_filter_facility_str) { FilterExprNode *filter = filter_facility_new(facility_bits(param->fac_str)); testcase(param->msg, filter, param->expected_result); } typedef struct _FilterParamFacilities { const gchar *msg; guint32 facilities; gboolean expected_result; } FilterParamFacilities; ParameterizedTestParameters(filter, test_filter_facility) { static FilterParamFacilities test_data_list[] = { {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_USER >> 3), .expected_result = TRUE}, {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_DAEMON >> 3), .expected_result = FALSE}, {.msg = "<2> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_KERN >> 3), .expected_result = TRUE}, {.msg = "<128> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_LOCAL0 >> 3), .expected_result = TRUE}, {.msg = "<32> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_AUTH >> 3), .expected_result = TRUE}, #ifdef LOG_AUTHPRIV {.msg = "<80> openvpn[2499]: PTHREAD support initialized", .facilities = 0x80000000 | (LOG_AUTHPRIV >> 3), .expected_result = TRUE}, #endif }; return cr_make_param_array(FilterParamFacilities, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamFacilities *param, filter, test_filter_facility) { FilterExprNode *filter = filter_facility_new(param->facilities); testcase(param->msg, filter, param->expected_result); } Test(filter, test_filter_facility_bits) { testcase("<15> openvpn[2499]: PTHREAD support initialized", filter_facility_new(facility_bits("daemon") | facility_bits("user")), TRUE); testcase("<15> openvpn[2499]: PTHREAD support initialized", filter_facility_new(facility_bits("uucp") | facility_bits("local4")), FALSE); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_fop.c000066400000000000000000000104531450431004300242720ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2019 Szemere * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "test_filters_common.h" #include "filter/filter-op.h" #include "filter/filter-expr.h" #include "filter/filter-pri.h" #include "filter/filter-expr-parser.h" #include "cfg-lexer.h" #include "apphook.h" static FilterExprNode * _compile_standalone_filter(gchar *config_snippet) { GlobalConfig *cfg = cfg_new_snippet(); FilterExprNode *tmp; CfgLexer *lexer = cfg_lexer_new_buffer(cfg, config_snippet, strlen(config_snippet)); cr_assert(lexer, "Couldn't initialize a buffer for CfgLexer"); cr_assert(cfg_run_parser(cfg, lexer, &filter_expr_parser, (gpointer *) &tmp, NULL)); cfg_free(cfg); return tmp; } typedef struct _FilterParams { gchar *config_snippet; gboolean expected_result; } FilterParams; ParameterizedTestParameters(filter_op, test_or_evaluation) { static FilterParams test_data_list[] = { // Filters inside evaluates to TRUE {.config_snippet = " facility(2) or facility(2)", .expected_result = TRUE }, {.config_snippet = " facility(2) or not facility(2)", .expected_result = TRUE }, {.config_snippet = "not facility(2) or facility(2)", .expected_result = TRUE }, {.config_snippet = "not facility(2) or not facility(2)", .expected_result = FALSE }, // note: The above expression evaluated in the following way: not (TRUE or (not TRUE)) // The expression below has the same expected result, but for a different reason. {.config_snippet = "(not facility(2)) or (not facility(2))", .expected_result = FALSE }, // Filters inside evaluates to FALSE {.config_snippet = " facility(3) or facility(3)", .expected_result = FALSE }, {.config_snippet = " facility(3) or not facility(3)", .expected_result = TRUE }, {.config_snippet = "not facility(3) or facility(3)", .expected_result = TRUE }, {.config_snippet = "not facility(3) or not facility(3)", .expected_result = TRUE }, // same as before {.config_snippet = "(not facility(3)) or (not facility(3))", .expected_result = TRUE }, // Mixed TRUE and FALSE evaluations {.config_snippet = " facility(2) or facility(3)", .expected_result = TRUE }, {.config_snippet = " facility(2) or not facility(3)", .expected_result = TRUE }, {.config_snippet = "not facility(2) or facility(3)", .expected_result = FALSE }, {.config_snippet = "not facility(2) or not facility(3)", .expected_result = TRUE }, // same as before {.config_snippet = "(not facility(2)) or (not facility(3))", .expected_result = TRUE }, }; return cr_make_param_array(FilterParams, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParams *params, filter_op, test_or_evaluation) { const gchar *msg = "<16> openvpn[2499]: PTHREAD support initialized"; FilterExprNode *filter = _compile_standalone_filter(params->config_snippet); testcase(msg, filter, params->expected_result); } Test(filter_op, cloned_filter_with_negation_should_behave_the_same) { const gchar *msg = "<16> openvpn[2499]: PTHREAD support initialized"; FilterExprNode *filter = _compile_standalone_filter("not (program('noprog') and message('nomsg'))"); FilterExprNode *cloned_filter = filter_expr_clone(filter); testcase(msg, filter, TRUE); testcase(msg, cloned_filter, TRUE); } TestSuite(filter_op, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_fop_cmp.c000066400000000000000000000367401450431004300251400ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "filter/filter-cmp.h" #include "filter/filter-expr-grammar.h" LogMessage * _construct_sample_message(void) { LogMessage *msg = log_msg_new_empty(); msg->pri = 15; log_msg_set_value(msg, LM_V_PROGRAM, "software", -1); log_msg_set_value_by_name_with_type(msg, "strvalue", "string", -1, LM_VT_STRING); log_msg_set_value_by_name_with_type(msg, "jsonvalue", "{\"foo\":\"foovalue\"}", -1, LM_VT_JSON); log_msg_set_value_by_name_with_type(msg, "truevalue", "1", -1, LM_VT_BOOLEAN); log_msg_set_value_by_name_with_type(msg, "falsevalue", "0", -1, LM_VT_BOOLEAN); log_msg_set_value_by_name_with_type(msg, "int32value", "32", -1, LM_VT_INTEGER); log_msg_set_value_by_name_with_type(msg, "int64value", "4294967296", -1, LM_VT_INTEGER); log_msg_set_value_by_name_with_type(msg, "nanvalue", "nan", -1, LM_VT_DOUBLE); log_msg_set_value_by_name_with_type(msg, "dblvalue", "3.1415", -1, LM_VT_DOUBLE); log_msg_set_value_by_name_with_type(msg, "datevalue", "1653246684.123", -1, LM_VT_DATETIME); log_msg_set_value_by_name_with_type(msg, "listvalue", "foo,bar,baz", -1, LM_VT_LIST); log_msg_set_value_by_name_with_type(msg, "nullvalue", "", -1, LM_VT_NULL); log_msg_set_value_by_name_with_type(msg, "bytesvalue", "\0\1\2\3", 4, LM_VT_BYTES); log_msg_set_value_by_name_with_type(msg, "protobufvalue", "\4\5\6\7", 4, LM_VT_PROTOBUF); return msg; } FilterExprNode * _construct_filter(const gchar *config_snippet) { FilterExprNode *tmp; CfgLexer *lexer = cfg_lexer_new_buffer(configuration, config_snippet, strlen(config_snippet)); cr_assert(lexer); cr_assert(cfg_run_parser(configuration, lexer, &filter_expr_parser, (gpointer *) &tmp, NULL)); cr_assert(tmp); return tmp; } gboolean evaluate(const gchar *filter_expr) { LogMessage *msg = _construct_sample_message(); FilterExprNode *filter_node = _construct_filter(filter_expr); gboolean result; cr_assert_not_null(filter_node, "Error compiling filter expression"); result = filter_expr_eval(filter_node, msg); log_msg_unref(msg); filter_expr_unref(filter_node); return result; } Test(filter, test_num_eq) { cr_assert(evaluate("10 == 10")); cr_assert(evaluate("$SEVERITY_NUM == 7")); cr_assert(evaluate("$SEVERITY_NUM == $SEVERITY_NUM")); cr_assert_not(evaluate("10 == 11")); } Test(filter, test_num_ne) { cr_assert(evaluate("10 != 9")); cr_assert(evaluate("$SEVERITY_NUM != 8")); cr_assert(evaluate("$SEVERITY_NUM != $FACILITY_NUM")); cr_assert_not(evaluate("10 != 10")); } Test(filter, test_num_lt) { cr_assert(evaluate("10 < 11")); cr_assert(evaluate("7 < 8")); cr_assert(evaluate("7 < 10")); cr_assert(evaluate("$LEVEL_NUM < 8")); cr_assert(evaluate("$LEVEL_NUM < 10")); cr_assert_not(evaluate("11 < 10")); cr_assert_not(evaluate("11 < 11")); } Test(filter, test_num_le) { cr_assert(evaluate("11 <= 11")); cr_assert(evaluate("10 <= 11")); cr_assert(evaluate("7 <= 8")); cr_assert(evaluate("7 <= 10")); cr_assert(evaluate("$LEVEL_NUM <= 8")); cr_assert(evaluate("$LEVEL_NUM <= 10")); cr_assert_not(evaluate("11 <= 10")); } Test(filter, test_num_gt) { cr_assert(evaluate("11 > 10")); cr_assert(evaluate("8 > 7")); cr_assert(evaluate("10 > 7")); cr_assert(evaluate("8 > $LEVEL_NUM")); cr_assert(evaluate("10 > $LEVEL_NUM")); cr_assert_not(evaluate("10 > 11")); cr_assert_not(evaluate("10 > 10")); } Test(filter, test_num_ge) { cr_assert(evaluate("10 >= 10")); cr_assert(evaluate("11 >= 10")); cr_assert(evaluate("8 >= 7")); cr_assert(evaluate("10 >= 7")); cr_assert(evaluate("8 >= $LEVEL_NUM")); cr_assert(evaluate("10 >= $LEVEL_NUM")); cr_assert_not(evaluate("10 >= 11")); } Test(filter, test_numeric_ordering) { cr_assert_not(evaluate("10 < 10")); cr_assert(evaluate("10 <= 10")); cr_assert(evaluate("10 == 10")); cr_assert(evaluate("10 >= 10")); cr_assert_not(evaluate("10 > 10")); cr_assert(evaluate("10 < 11")); cr_assert(evaluate("10 <= 11")); cr_assert_not(evaluate("10 == 11")); cr_assert_not(evaluate("10 >= 11")); cr_assert_not(evaluate("10 > 11")); cr_assert_not(evaluate("11 < 10")); cr_assert_not(evaluate("11 <= 10")); cr_assert_not(evaluate("11 == 10")); cr_assert(evaluate("11 >= 10")); cr_assert(evaluate("11 > 10")); } /* string comparison */ Test(filter, test_eq) { cr_assert(evaluate("10 eq 10")); cr_assert(evaluate("$SEVERITY_NUM eq 7")); cr_assert(evaluate("$SEVERITY_NUM eq $SEVERITY_NUM")); cr_assert_not(evaluate("10 eq 11")); } Test(filter, test_ne) { cr_assert(evaluate("10 ne 9")); cr_assert(evaluate("$SEVERITY_NUM ne 8")); cr_assert(evaluate("$SEVERITY_NUM ne $FACILITY_NUM")); cr_assert_not(evaluate("10 ne 10")); } Test(filter, test_lt) { cr_assert(evaluate("10 lt 11")); cr_assert(evaluate("7 lt 8")); cr_assert(evaluate("$LEVEL_NUM lt 8")); cr_assert_not(evaluate("7 lt 10")); cr_assert_not(evaluate("11 lt 10")); cr_assert_not(evaluate("11 lt 11")); } Test(filter, test_le) { cr_assert(evaluate("11 le 11")); cr_assert(evaluate("10 le 11")); cr_assert(evaluate("7 le 8")); cr_assert(evaluate("$LEVEL_NUM le 8")); cr_assert_not(evaluate("7 le 10")); cr_assert_not(evaluate("11 le 10")); cr_assert_not(evaluate("$LEVEL_NUM le 10")); } Test(filter, test_gt) { cr_assert(evaluate("11 gt 10")); cr_assert(evaluate("8 gt 7")); cr_assert(evaluate("8 gt $LEVEL_NUM")); cr_assert_not(evaluate("10 gt 7")); cr_assert_not(evaluate("10 gt 11")); cr_assert_not(evaluate("10 gt 10")); cr_assert_not(evaluate("10 gt $LEVEL_NUM")); } Test(filter, test_ge) { cr_assert(evaluate("10 ge 10")); cr_assert(evaluate("11 ge 10")); cr_assert(evaluate("8 ge 7")); cr_assert(evaluate("8 ge $LEVEL_NUM")); cr_assert_not(evaluate("10 ge 7")); cr_assert_not(evaluate("10 ge 11")); cr_assert_not(evaluate("10 ge $LEVEL_NUM")); } Test(filter, test_string_ordering) { cr_assert_not(evaluate("10 lt 10")); cr_assert(evaluate("10 le 10")); cr_assert(evaluate("10 eq 10")); cr_assert(evaluate("10 ge 10")); cr_assert_not(evaluate("10 gt 10")); cr_assert(evaluate("10 lt 11")); cr_assert(evaluate("10 le 11")); cr_assert_not(evaluate("10 eq 11")); cr_assert_not(evaluate("10 ge 11")); cr_assert_not(evaluate("10 gt 11")); cr_assert_not(evaluate("11 lt 10")); cr_assert_not(evaluate("11 le 10")); cr_assert_not(evaluate("11 eq 10")); cr_assert(evaluate("11 ge 10")); cr_assert(evaluate("11 gt 10")); } Test(filter, test_string_ordering_with_non_numbers) { cr_assert(evaluate("alma lt korte")); cr_assert(evaluate("alma le korte")); cr_assert_not(evaluate("alma eq korte")); cr_assert_not(evaluate("alma ge korte")); cr_assert_not(evaluate("alma gt korte")); cr_assert_not(evaluate("korte lt alma")); cr_assert_not(evaluate("korte le alma")); cr_assert_not(evaluate("korte eq alma")); cr_assert(evaluate("korte ge alma")); cr_assert(evaluate("korte gt alma")); } Test(filter, test_type_aware_comparisons_strings_to_strings_are_compared_as_strings) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); /* strings */ cr_assert(evaluate("'alma' != 'korte'")); cr_assert_not(evaluate("'alma' == 'korte'")); cr_assert(evaluate("'alma' < 'korte'")); cr_assert(evaluate("'korte' > 'alma'")); /* strings containing numbers */ cr_assert(evaluate("'10' != '11'")); cr_assert_not(evaluate("'10' == '11'")); cr_assert(evaluate("'10' < '7'")); cr_assert(evaluate("'7' > '10'")); /* string values */ cr_assert(evaluate("'$strvalue' == 'string'")); cr_assert(evaluate("'$strvalue' == '$strvalue'")); cr_assert_not(evaluate("'$strvalue' != '$strvalue'")); /* bytes values */ cr_assert(evaluate("'$bytesvalue' == '$bytesvalue'")); cr_assert_not(evaluate("'$bytesvalue' != '$bytesvalue'")); cr_assert(evaluate("'$protobufvalue' == '$protobufvalue'")); cr_assert_not(evaluate("'$protobufvalue' != '$protobufvalue'")); } Test(filter, test_type_aware_comparison_objects_are_compared_as_strings_if_types_match) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("'$jsonvalue' == json('{\"foo\":\"foovalue\"}')")); cr_assert(evaluate("'$listvalue' == list('foo,bar,baz')")); /* types are not equal, they'd be compared as numbers, both are NaNs */ cr_assert_not(evaluate("list('foo,bar,baz') == string('foo,bar,baz')")); cr_assert_not(evaluate("list('') == string('')")); } Test(filter, test_type_aware_comparison_strings_are_compared_as_strings_if_types_match) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("'$strvalue' == 'string')")); cr_assert(evaluate("'$strvalue' > 'foo')")); cr_assert(evaluate("'$strvalue' < 'zabkasa')")); } Test(filter, test_type_aware_comparison_null_equals_to_null_and_does_not_equal_to_anything_else) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("null('') == null('')")); cr_assert_not(evaluate("null('') != null('')")); cr_assert(evaluate("'$nullvalue' == null('')")); cr_assert_not(evaluate("'$nullvalue' != null('')")); cr_assert(evaluate("string('') != null('')")); cr_assert(evaluate("int64('0') != null('')")); cr_assert(evaluate("double('0.0') != null('')")); cr_assert(evaluate("list('') != null('')")); cr_assert(evaluate("json('') != null('')")); cr_assert(evaluate("datetime('') != null('')")); } Test(filter, test_non_existing_macro_has_a_null_value_so_it_equals_to_null) { /* not existing macro is null */ cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("'$doesnotexist' == null('')")); cr_assert_not(evaluate("'$doesnotexist' != null('')")); } Test(filter, test_type_aware_comparison_null_converts_to_zero_when_compared_with_less_than_or_greater_than) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("'$nullvalue' < 1")); cr_assert(evaluate("'$nullvalue' > -1")); } Test(filter, test_compat_mode_numeric_comparisons_are_compared_as_numbers) { cfg_set_version_without_validation(configuration, VERSION_VALUE_3_36); /* strings are converted to "0" before comparison */ cr_assert(evaluate("'alma' == 'korte'")); cr_assert_not(evaluate("'alma' != 'korte'")); cr_assert_not(evaluate("'alma' < 'korte'")); cr_assert_not(evaluate("'korte' > 'alma'")); cr_assert(evaluate("'$strvalue' == 'string'")); cr_assert(evaluate("'$strvalue' == '$strvalue'")); cr_assert_not(evaluate("'$strvalue' != '$strvalue'")); /* strings containing numbers are converted to numbers and compared numerically */ cr_assert(evaluate("'10' != '11'")); cr_assert_not(evaluate("'10' == '11'")); cr_assert(evaluate("'10' > '7'")); cr_assert(evaluate("'7' < '10'")); } Test(filter, test_type_aware_comparisons_mixed_types_or_numbers_are_compared_as_numbers_after_conversion) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("int('$int32value') == '32'")); cr_assert(evaluate("int('$int32value') < '321'")); cr_assert(evaluate("int('$int32value') > '7'")); /* booleans are converted to 0/1 */ cr_assert(evaluate("'$truevalue' == 1")); cr_assert(evaluate("'$falsevalue' == 0")); cr_assert(evaluate("'$dblvalue' < 3.145")); cr_assert(evaluate("'$dblvalue' > 3.14")); cr_assert(evaluate("'$dblvalue' > 0.314e1")); cr_assert(evaluate("'$dblvalue' < 0.314e2")); cr_assert(evaluate("'$datevalue' == 1653246684123")); cr_assert(evaluate("'$nullvalue' < 1")); cr_assert(evaluate("'$nullvalue' > -1")); /* JSON objects/lists are always NaN values, which produce FALSE comparisons */ cr_assert_not(evaluate("'$listvalue' < 01234")); cr_assert_not(evaluate("'$listvalue' > 01234")); cr_assert_not(evaluate("'$listvalue' == 01234")); cr_assert_not(evaluate("'$jsonvalue' < 01234")); cr_assert_not(evaluate("'$jsonvalue' > 01234")); cr_assert_not(evaluate("'$jsonvalue' == 01234")); /* bytes and protobuf types are behaving as they were unset (return NULL values) if not explicitly cast to bytes() */ cr_assert(evaluate("'$bytesvalue' < 1")); cr_assert(evaluate("'$bytesvalue' > -1")); cr_assert(evaluate("'$protobufvalue' < 1")); cr_assert(evaluate("'$protobufvalue' > -1")); /* bytes and protobuf types are NaN values if explicitly cast to bytes() */ cr_assert_not(evaluate("bytes('$bytesvalue') < 01234")); cr_assert_not(evaluate("bytes('$bytesvalue') > 01234")); cr_assert_not(evaluate("bytes('$bytesvalue') == 01234")); cr_assert_not(evaluate("protobuf('$protobufvalue') < 01234")); cr_assert_not(evaluate("protobuf('$protobufvalue') > 01234")); cr_assert_not(evaluate("protobuf('$protobufvalue') == 01234")); } Test(filter, test_type_aware_comparison_nan_is_always_different_from_anything) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("'$nanvalue' != '$nanvalue'")); cr_assert_not(evaluate("'$nanvalue' < '5'")); cr_assert_not(evaluate("'$nanvalue' > '5'")); cr_assert_not(evaluate("'$nanvalue' == '5'")); cr_assert(evaluate("'5' != '$nanvalue'")); cr_assert_not(evaluate("'$nanvalue' == '$nanvalue'")); cr_assert_not(evaluate("'$nanvalue' == int64('nan')")); cr_assert_not(evaluate("'$nanvalue' == int64('foobar')")); cr_assert_not(evaluate("'$nanvalue' < '$nanvalue'")); cr_assert_not(evaluate("'$nanvalue' > '$nanvalue'")); } Test(filter, test_type_and_value_comparison_checks_whether_type_and_value_match_completely) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("$strvalue === $strvalue")); cr_assert(evaluate("$strvalue === string")); cr_assert(evaluate("string(64) === string(64)")); cr_assert_not(evaluate("string(64) !== string(64)")); cr_assert_not(evaluate("string(64) === int64(64)")); cr_assert(evaluate("string(64) !== int64(64)")); /* types match, values don't */ cr_assert_not(evaluate("foo === bar")); cr_assert_not(evaluate("int64(123) === int64(256)")); cr_assert_not(evaluate("123 === 456")); /* string conversion */ cr_assert(evaluate("double( 1e1 ) === double(10)")); } Test(filter, test_int32_and_int64_are_aliases_to_int) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); cr_assert(evaluate("int32(64) === int64(64)")); cr_assert(evaluate("int32(64) === int(64)")); cr_assert(evaluate("int64(64) === int(64)")); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); } static void teardown(void) { app_shutdown(); cfg_free(configuration); } TestSuite(filter, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_in_list.c000066400000000000000000000127051450431004300251510ustar00rootroot00000000000000/* * Copyright (c) 2013, 2014 Balabit * Copyright (c) 2013, 2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "cfg.h" #include "messages.h" #include "syslog-names.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "plugin.h" #include "filter/filter-in-list.h" #include "msg-format.h" #include #include #define MSG_1 "<15>Sep 4 15:03:55 localhost test-program[3086]: some random message" #define MSG_2 "<15>Sep 4 15:03:55 localhost foo[3086]: some random message" #define MSG_3 "<15>Sep 4 15:03:55 192.168.1.1 foo[3086]: some random message" #define MSG_LONG "<15>Sep 4 15:03:55 test-hostAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA foo[3086]: some random message" #define LIST_FILE_DIR "%s/lib/filter/tests/filters-in-list/" static MsgFormatOptions parse_options; char *top_srcdir = TOP_SRCDIR; gboolean evaluate_testcase(const gchar *msg, FilterExprNode *filter_node) { LogMessage *log_msg; gboolean result; cr_assert_not_null(filter_node, "Constructing an in-list filter"); log_msg = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); result = filter_expr_eval(filter_node, log_msg); log_msg_unref(log_msg); filter_expr_unref(filter_node); return result; } Test(template_filters, test_filter_returns_false_when_list_is_empty) { gchar *list_file_with_zero_lines = g_strdup_printf(LIST_FILE_DIR "empty.list", top_srcdir); cr_assert_not(evaluate_testcase(MSG_1, filter_in_list_new(list_file_with_zero_lines, "PROGRAM")), "in-list filter matches"); g_free(list_file_with_zero_lines); } Test(template_filters, test_string_searched_for_is_not_in_the_list) { gchar *list_file_with_one_line = g_strdup_printf(LIST_FILE_DIR "test.list", top_srcdir); cr_assert_not(evaluate_testcase(MSG_2, filter_in_list_new(list_file_with_one_line, "PROGRAM")), "in-list filter matches"); g_free(list_file_with_one_line); } Test(template_filters, test_given_macro_is_not_available_in_this_message) { gchar *list_file_with_one_line = g_strdup_printf(LIST_FILE_DIR "test.list", top_srcdir); cr_assert_not(evaluate_testcase(MSG_2, filter_in_list_new(list_file_with_one_line, "FOO_MACRO")), "in-list filter matches"); g_free(list_file_with_one_line); } Test(template_filters, test_list_file_doesnt_exist) { gchar *list_file_which_doesnt_exist = g_strdup_printf(LIST_FILE_DIR "notexisting.list", top_srcdir); cr_assert_null(filter_in_list_new(list_file_which_doesnt_exist, "PROGRAM"), "in-list filter should fail, when the list file does not exist"); g_free(list_file_which_doesnt_exist); } Test(template_filters, test_list_file_contains_only_one_line) { gchar *list_file_with_one_line = g_strdup_printf(LIST_FILE_DIR "test.list", top_srcdir); cr_assert(evaluate_testcase(MSG_1, filter_in_list_new(list_file_with_one_line, "PROGRAM")), "in-list filter matches"); g_free(list_file_with_one_line); } Test(template_filters, test_list_file_contains_lot_of_lines) { gchar *list_file_which_has_a_lot_of_lines = g_strdup_printf(LIST_FILE_DIR "lot_of_lines.list", top_srcdir); cr_assert(evaluate_testcase(MSG_1, filter_in_list_new(list_file_which_has_a_lot_of_lines, "PROGRAM")), "in-list filter matches"); g_free(list_file_which_has_a_lot_of_lines); } Test(template_filters, test_filter_with_ip_address) { gchar *list_file_with_ip_address = g_strdup_printf(LIST_FILE_DIR "ip.list", top_srcdir); cr_assert(evaluate_testcase(MSG_3, filter_in_list_new(list_file_with_ip_address, "HOST")), "in-list filter matches"); g_free(list_file_with_ip_address); } Test(template_filters, test_filter_with_long_line) { gchar *list_file_with_long_line = g_strdup_printf(LIST_FILE_DIR "long_line.list", top_srcdir); cr_assert(evaluate_testcase(MSG_LONG, filter_in_list_new(list_file_with_long_line, "HOST")), "in-list filter matches"); g_free(list_file_with_long_line); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); cfg_load_module(configuration, "syslogformat"); msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); cr_assert_not_null(top_srcdir, "The $top_srcdir environment variable MUST NOT be empty!"); } static void teardown(void) { app_shutdown(); } TestSuite(template_filters, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_level_new.c000066400000000000000000000125451450431004300254720ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "test_filters_common.h" #include "filter/filter-expr.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "cfg.h" #include #include #include TestSuite(filter, .init = setup, .fini = teardown); typedef struct _FilterParamRange { const gchar *msg; const gchar *from; const gchar *to; gboolean expected_result; } FilterParamRange; ParameterizedTestParameters(filter, test_filter_severity_range) { static FilterParamRange test_data_list[] = { {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "emerg", .expected_result = TRUE}, {.msg = "<8> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = TRUE}, {.msg = "<9> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = TRUE}, {.msg = "<10> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = TRUE}, {.msg = "<11> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = FALSE}, {.msg = "<12> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = FALSE}, {.msg = "<13> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = FALSE}, {.msg = "<14> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = FALSE}, {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .from = "crit", .to = "emerg", .expected_result = FALSE}, {.msg = "<8> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = FALSE}, {.msg = "<9> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = FALSE}, {.msg = "<10> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = FALSE}, {.msg = "<11> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = FALSE}, {.msg = "<12> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = FALSE}, {.msg = "<13> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = TRUE}, {.msg = "<14> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = TRUE}, {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .from = "debug", .to = "notice", .expected_result = TRUE} }; return cr_make_param_array(FilterParamRange, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRange *param, filter, test_filter_severity_range) { FilterExprNode *filter = filter_severity_new(level_range(param->from, param->to)); testcase(param->msg, filter, param->expected_result); } typedef struct _FilterParamBits { const gchar *msg; const gchar *lev; gboolean expected_result; } FilterParamBits; ParameterizedTestParameters(filter, test_filter_severity_bits) { static FilterParamBits test_data_list[] = { {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .lev = "emerg", .expected_result = FALSE}, {.msg = "<0> openvpn[2499]: PTHREAD support initialized", .lev = "emerg", .expected_result = TRUE}, {.msg = "<1> openvpn[2499]: PTHREAD support initialized", .lev = "alert", .expected_result = TRUE}, {.msg = "<2> openvpn[2499]: PTHREAD support initialized", .lev = "crit", .expected_result = TRUE}, {.msg = "<3> openvpn[2499]: PTHREAD support initialized", .lev = "err", .expected_result = TRUE}, {.msg = "<4> openvpn[2499]: PTHREAD support initialized", .lev = "warning", .expected_result = TRUE}, {.msg = "<5> openvpn[2499]: PTHREAD support initialized", .lev = "notice", .expected_result = TRUE}, {.msg = "<6> openvpn[2499]: PTHREAD support initialized", .lev = "info", .expected_result = TRUE}, {.msg = "<7> openvpn[2499]: PTHREAD support initialized", .lev = "debug", .expected_result = TRUE} }; return cr_make_param_array(FilterParamBits, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamBits *param, filter, test_filter_severity_bits) { FilterExprNode *filter = filter_severity_new(level_bits(param->lev)); testcase(param->msg, filter, param->expected_result); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_netmask.c000066400000000000000000000064131450431004300251510ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "test_filters_common.h" #include "filter/filter-expr.h" #include "filter/filter-netmask6.h" #include "filter/filter-netmask.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "filter/filter-op.h" #include "filter/filter-cmp.h" #include "cfg.h" #include #include #include TestSuite(filter, .init = setup, .fini = teardown); typedef struct _FilterParamNetmask { const gchar *msg; const gchar *sockaddr; const gchar *cidr; gboolean expected_result; } FilterParamNetmask; ParameterizedTestParameters(filter, test_filter_netmask_ip4_socket) { static FilterParamNetmask test_data_list[] = { {.msg = "<15>Oct 15 16:19:01 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "10.10.0.1", .cidr = "10.10.0.0/16", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:19:02 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "10.10.0.1", .cidr = "10.10.0.0/24", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:19:03 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "10.10.0.1", .cidr = "10.10.10.0/24", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:19:04 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "10.10.0.1", .cidr = "0.0.10.10/24", .expected_result = FALSE}, }; return cr_make_param_array(FilterParamNetmask, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamNetmask *param, filter, test_filter_netmask_ip4_socket) { testcase_with_socket(param->msg, param->sockaddr, filter_netmask_new(param->cidr), param->expected_result); } ParameterizedTestParameters(filter, test_filter_netmask_ip4) { static FilterParamNetmask test_data_list[] = { {.msg = "<15>Oct 15 16:20:01 host openvpn[2499]: PTHREAD support initialized", .cidr = "127.0.0.1/32", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:20:02 host openvpn[2499]: PTHREAD support initialized", .cidr = "127.0.0.2/32", .expected_result = FALSE}, }; return cr_make_param_array(FilterParamNetmask, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamNetmask *param, filter, test_filter_netmask_ip4) { testcase(param->msg, filter_netmask_new(param->cidr), param->expected_result); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_netmask6.c000066400000000000000000000216371450431004300252440ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2014 Zoltan Fried * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "test_filters_common.h" #include "filter/filter-expr.h" #include "filter/filter-netmask6.h" #include "filter/filter-netmask.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "filter/filter-op.h" #include "filter/filter-cmp.h" #include "cfg.h" #include #include #include static void _replace_last_zero_with_wildcard(gchar *ipv6) { if (!ipv6) return; gsize n = strlen(ipv6); if ((n >= 2) && (ipv6[n-2] == ':') && (ipv6[n-1] == '0')) ipv6[n-1] = ':'; } gchar * calculate_network6(const gchar *ipv6, int prefix, gchar *calculated_network) { struct in6_addr network; struct in6_addr address; memset(&network, 0, sizeof(struct in6_addr)); inet_pton(AF_INET6, ipv6, &address); get_network_address(&address, prefix, &network); inet_ntop(AF_INET6, &network, calculated_network, INET6_ADDRSTRLEN); _replace_last_zero_with_wildcard(calculated_network); return calculated_network; } struct netmask6_tuple { gint prefix; const gchar *expected_network; }; ParameterizedTestParameters(netmask6, test_filter) { static struct netmask6_tuple params[] = { { 1, "::"}, { 3, "2000::"}, { 16, "2001::"}, { 17, "2001:8000::"}, { 18, "2001:c000::"}, { 20, "2001:d000::"}, { 21, "2001:d800::"}, { 23, "2001:da00::"}, { 24, "2001:db00::"}, { 25, "2001:db80::"}, { 33, "2001:db80:8000::"}, { 38, "2001:db80:8400::"}, { 40, "2001:db80:8500::"}, { 41, "2001:db80:8580::"}, { 43, "2001:db80:85a0::"}, { 47, "2001:db80:85a2::"}, { 48, "2001:db80:85a3::"}, { 49, "2001:db80:85a3:8000::"}, { 54, "2001:db80:85a3:8c00::"}, { 56, "2001:db80:85a3:8d00::"}, { 59, "2001:db80:85a3:8d20::"}, { 60, "2001:db80:85a3:8d30::"}, { 68, "2001:db80:85a3:8d30:1000::"}, { 71, "2001:db80:85a3:8d30:1200::"}, { 72, "2001:db80:85a3:8d30:1300::"}, { 76, "2001:db80:85a3:8d30:1310::"}, { 77, "2001:db80:85a3:8d30:1318::"}, { 80, "2001:db80:85a3:8d30:1319::"}, { 81, "2001:db80:85a3:8d30:1319:8000::"}, { 87, "2001:db80:85a3:8d30:1319:8a00::"}, { 91, "2001:db80:85a3:8d30:1319:8a20::"}, { 93, "2001:db80:85a3:8d30:1319:8a28::"}, { 94, "2001:db80:85a3:8d30:1319:8a2c::"}, { 95, "2001:db80:85a3:8d30:1319:8a2e::"}, { 99, "2001:db80:85a3:8d30:1319:8a2e:2000::"}, { 100, "2001:db80:85a3:8d30:1319:8a2e:3000::"}, { 102, "2001:db80:85a3:8d30:1319:8a2e:3400::"}, { 103, "2001:db80:85a3:8d30:1319:8a2e:3600::"}, { 104, "2001:db80:85a3:8d30:1319:8a2e:3700::"}, { 114, "2001:db80:85a3:8d30:1319:8a2e:3700:4000"}, { 115, "2001:db80:85a3:8d30:1319:8a2e:3700:6000"}, { 116, "2001:db80:85a3:8d30:1319:8a2e:3700:7000"}, { 119, "2001:db80:85a3:8d30:1319:8a2e:3700:7200"}, { 120, "2001:db80:85a3:8d30:1319:8a2e:3700:7300"}, { 122, "2001:db80:85a3:8d30:1319:8a2e:3700:7340"}, { 125, "2001:db80:85a3:8d30:1319:8a2e:3700:7348"}, }; return cr_make_param_array(struct netmask6_tuple, params, G_N_ELEMENTS(params)); } const gchar *ipv6 = "2001:db80:85a3:8d30:1319:8a2e:3700:7348"; ParameterizedTest(struct netmask6_tuple *tup, netmask6, test_filter) { gchar *calculated_network = g_new0(char, INET6_ADDRSTRLEN); calculate_network6(ipv6, tup->prefix, calculated_network); cr_assert_str_eq(calculated_network, tup->expected_network, "prefix: %d", tup->prefix); g_free(calculated_network); } typedef struct _FilterParamNetmask { const gchar *msg; const gchar *sockaddr; const gchar *cidr; gboolean expected_result; } FilterParamNetmask; ParameterizedTestParameters(filter, test_filter_netmask_ip6_socket) { static FilterParamNetmask test_data_list[] = { {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::/1", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:02 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "2001:db80:85a3:8d30:1319:8a2e::/95", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:03 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348/60", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:04 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "2001:db80:85a3:8d30:1319:8a2e:3700::/114", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:05 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::85a3:8d30:1319:8a2e:3700::/114", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "aaaaaa/32", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:07 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "/8", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:08 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:09 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:10 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::1/8", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:11 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::1/128", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:12 host openvpn[2499]: PTHREAD support initialized", .sockaddr = "2001:db80:85a3:8d30:1319:8a2e:3700:7348", .cidr = "::2/32", .expected_result = FALSE} }; return cr_make_param_array(FilterParamNetmask, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamNetmask *param, filter, test_filter_netmask_ip6_socket, .init = setup, .fini = teardown) { testcase_with_socket(param->msg, param->sockaddr, filter_netmask6_new(param->cidr), param->expected_result); } ParameterizedTestParameters(filter, test_filter_netmask_ip6) { static FilterParamNetmask test_data_list[] = { {.msg = "<15>Oct 15 16:18:01 host openvpn[2499]: PTHREAD support initialized", .cidr = "aaaaaa/32", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:18:02 host openvpn[2499]: PTHREAD support initialized", .cidr = "/8", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:18:03 host openvpn[2499]: PTHREAD support initialized", .cidr = "", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:18:04 host openvpn[2499]: PTHREAD support initialized", .cidr = "::1", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:18:05 host openvpn[2499]: PTHREAD support initialized", .cidr = "::/32", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:18:06 host openvpn[2499]: PTHREAD support initialized", .cidr = "::1/8", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:18:07 host openvpn[2499]: PTHREAD support initialized", .cidr = "::1/128", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:18:08 host openvpn[2499]: PTHREAD support initialized", .cidr = "::/16", .expected_result = TRUE}, {.msg = "<15>Oct 15 16:18:09 host openvpn[2499]: PTHREAD support initialized", .cidr = "::/599", .expected_result = FALSE}, {.msg = "<15>Oct 15 16:18:10 host openvpn[2499]: PTHREAD support initialized", .cidr = "::/aaa", .expected_result = FALSE}, }; return cr_make_param_array(FilterParamNetmask, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamNetmask *param, filter, test_filter_netmask_ip6, .init = setup, .fini = teardown) { testcase(param->msg, filter_netmask6_new(param->cidr), param->expected_result); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_regexp.c000066400000000000000000000766621450431004300250160ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/cr_template.h" #include "libtest/msg_parse_lib.h" #include "test_filters_common.h" #include "filter/filter-expr.h" #include "filter/filter-re.h" #include "filter/filter-pri.h" #include "filter/filter-op.h" #include "cfg.h" #include #include #include TestSuite(filter, .init = setup, .fini = teardown); typedef struct _FilterParamRegexp { const gchar *msg; gint field; const gchar *regexp; gint flags; const gchar *regexp2; gint flags2; gboolean expected_result; const gchar *name; const gchar *value; } FilterParamRegexp; Test(filter, create_pcre_regexp_filter) { cr_assert_eq(create_pcre_regexp_filter(LM_V_PROGRAM, "((", 0), NULL); cr_assert_eq(create_pcre_regexp_filter(LM_V_HOST, "((", 0), NULL); cr_assert_eq(create_pcre_regexp_match("((", 0), NULL); cr_assert_eq(create_pcre_regexp_filter(LM_V_PROGRAM, "((", 0), NULL); cr_assert_eq(create_pcre_regexp_filter(LM_V_HOST, "((", 0), NULL); cr_assert_eq(create_pcre_regexp_filter(LM_V_HOST, "(?iana", 0), NULL); cr_assert_eq(create_pcre_regexp_filter(LM_V_HOST, "(?iana", 0), NULL); cr_assert_eq(create_pcre_regexp_match("((", 0), NULL); cr_assert_eq(create_pcre_regexp_match("(?Pa)", 0), NULL); // Begins with a digit cr_assert_eq(create_pcre_regexp_match("(?Pa)", 0), NULL); // Begins with an illegal char cr_assert_eq(create_pcre_regexp_match("(?Pa)", 0), NULL); // Ends with an illegal char cr_assert_eq(create_pcre_regexp_match("\\1", 0), NULL); // Backreference cr_assert_eq(create_pcre_regexp_match("a[b-a]", 0), NULL); cr_assert_eq(create_pcre_regexp_match("a[]b", 0), NULL); cr_assert_eq(create_pcre_regexp_match("a[", 0), NULL); cr_assert_eq(create_pcre_regexp_match("*a", 0), NULL); cr_assert_eq(create_pcre_regexp_match("(*)b", 0), NULL); cr_assert_eq(create_pcre_regexp_match("a\\", 0), NULL); cr_assert_eq(create_pcre_regexp_match("abc)", 0), NULL); cr_assert_eq(create_pcre_regexp_match("(abc", 0), NULL); cr_assert_eq(create_pcre_regexp_match("a**", 0), NULL); cr_assert_eq(create_pcre_regexp_match(")(", 0), NULL); cr_assert_eq(create_pcre_regexp_match("(?foo)|(?bar)", 0), NULL); } ParameterizedTestParameters(filter, test_filter_regexp_backref_chk) { static FilterParamRegexp test_data_list[] = { {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:02 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "al fa"}, {.msg = "<15>Oct 15 16:17:03 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "232", .value = NULL}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: alma fa", .field = LM_V_MESSAGE, .regexp = "(?Pa)(?Pl)(?Pm)(?Pa) (?Pfa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "MM", .value = "m"}, {.msg = "<15>Oct 15 16:17:02 host openvpn[2499]: alma fa", .field = LM_V_MESSAGE, .regexp = "(?Pa)(?Pl)(?Pm)(?Pa) (?Pfa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "aaaa", .value = NULL}, {.msg = "<15>Oct 15 16:17:03 host openvpn[2499]: alma fa", .field = LM_V_MESSAGE, .regexp = "(?Pa)(?Pl)(?Pm)(?Pa) (?Pfa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "fa_name", .value = "fa"}, {.msg = "<15>Oct 15 16:17:04 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "l"}, {.msg = "<15>Oct 15 16:17:04 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "3", .value = "fa"}, {.msg = "<15>Oct 15 16:17:05 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "al fa"}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: al fa", .field = LM_V_MESSAGE, .regexp = "(a)(l) (fa)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "233", .value = NULL}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: foobar bar", .field = LM_V_MESSAGE, .regexp = "(?foobar) (?foo)?(?bar)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "bar", .value = "bar"}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: foobar bar", .field = LM_V_MESSAGE, .regexp = "(?foobar) (?foo)?(?bar)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "foobar", .value = "foobar"}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: foobar bar", .field = LM_V_MESSAGE, .regexp = "(?foobar) (?foo)?(?bar)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "foo", .value = NULL}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abc", .field = LM_V_MESSAGE, .regexp = "((a))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abc", .field = LM_V_MESSAGE, .regexp = "((a))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b)*", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b){0,}", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b)+", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b){1,}", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b)?", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ab", .field = LM_V_MESSAGE, .regexp = "(a+|b){0,1}", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abbbcd", .field = LM_V_MESSAGE, .regexp = "([abc])*d", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "c"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcd", .field = LM_V_MESSAGE, .regexp = "([abc])*bcd", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: xabyabbbz", .field = LM_V_MESSAGE, .regexp = "ab*", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "ab"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: xayabbbz", .field = LM_V_MESSAGE, .regexp = "ab*", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcdef", .field = LM_V_MESSAGE, .regexp = "(abc|)ef", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "ef"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcd", .field = LM_V_MESSAGE, .regexp = "(a|b)c*d", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abc", .field = LM_V_MESSAGE, .regexp = "(ab|ab*)bc", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abc", .field = LM_V_MESSAGE, .regexp = "a([bc]*)c*", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "bc"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcd", .field = LM_V_MESSAGE, .regexp = "a([bc]*)(c*d)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "d"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcd", .field = LM_V_MESSAGE, .regexp = "a([bc]+)(c*d)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "d"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcd", .field = LM_V_MESSAGE, .regexp = "a([bc]*)(c+d)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "cd"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: alpha", .field = LM_V_MESSAGE, .regexp = "[a-zA-Z_][a-zA-Z0-9_]*", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "alpha"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abh", .field = LM_V_MESSAGE, .regexp = "^a(bc+|b[eh])g|.h$", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = NULL}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: effgz", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "effgz"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: effgz", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = NULL}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ij", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "ij"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ij", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "j"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: reffgz", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "effgz"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: reffgz", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = NULL}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: a", .field = LM_V_MESSAGE, .regexp = "((((((((((a))))))))))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "10", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: aa", .field = LM_V_MESSAGE, .regexp = "((((((((((a))))))))))\\10", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "0", .value = "aa"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcde", .field = LM_V_MESSAGE, .regexp = "(.*)c(.*)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "ab"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcde", .field = LM_V_MESSAGE, .regexp = "(.*)c(.*)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "de"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: (a, b)", .field = LM_V_MESSAGE, .regexp = "\\((.*), (.*)\\)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "a"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: (a, b)", .field = LM_V_MESSAGE, .regexp = "\\((.*), (.*)\\)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "b"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcabc", .field = LM_V_MESSAGE, .regexp = "(abc)\\1", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "abc"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: abcabc", .field = LM_V_MESSAGE, .regexp = "([a-c]*)\\1", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "abc"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: a:bc-:de:f", .field = LM_V_MESSAGE, .regexp = "(?Oct 15 16:17:01 host openvpn[2499]: A", .field = LM_V_MESSAGE, .regexp = "(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "A"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: C", .field = LM_V_MESSAGE, .regexp = "(?i)(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "C"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ace", .field = LM_V_MESSAGE, .regexp = "a(?:b|c|d)(.)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "e"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ace", .field = LM_V_MESSAGE, .regexp = "a(?:b|c|d)*(.)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "e"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ace", .field = LM_V_MESSAGE, .regexp = "a(?:b|c|d)+?(.)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "e"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ace", .field = LM_V_MESSAGE, .regexp = "a(?:b|(c|e){1,2}?|d)+?(.)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "1", .value = "c"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: ace", .field = LM_V_MESSAGE, .regexp = "a(?:b|(c|e){1,2}?|d)+?(.)", .flags = LMF_STORE_MATCHES, .expected_result = TRUE, .name = "2", .value = "e"}, // using duplicate names for named subpatterns. {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: hello foo", .field = LM_V_MESSAGE, .regexp = "(?foo)|(?bar)", .flags = LMF_STORE_MATCHES | LMF_DUPNAMES, .expected_result = TRUE, .name = "DN", .value = "foo"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: hello bar", .field = LM_V_MESSAGE, .regexp = "(?foo)|(?bar)", .flags = LMF_STORE_MATCHES | LMF_DUPNAMES, .expected_result = TRUE, .name = "DN", .value = "bar"}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: foobar", .field = LM_V_MESSAGE, .regexp = "(?foo)(?bar)", .flags = LMF_STORE_MATCHES | LMF_DUPNAMES, .expected_result = TRUE, .name = "DN", .value = "bar"}, }; return cr_make_param_array(FilterParamRegexp, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRegexp *param, filter, test_filter_regexp_backref_chk) { FilterExprNode *filter = create_pcre_regexp_filter(param->field, param->regexp, param->flags); testcase_with_backref_chk(param->msg, filter, param->expected_result, param->name, param->value); } ParameterizedTestParameters(filter, test_filter_regexp_filter) { static FilterParamRegexp test_data_list[] = { {.msg = "<15> openvpn[2501]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = "^openvpn$", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2500]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = "^open$", .flags = 0, .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "^host$", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:02 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "^hos$", .flags = 0, .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:03 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "pthread", .flags = 0, .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:04 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "^PTHREAD ", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:05 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "PTHREAD s", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:06 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "^PTHREAD$", .flags = 0, .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:07 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "(?i)pthread", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2499]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = "^openvpn$", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2498]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = "^open$", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2497]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "^host$", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2496]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "^hos$", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2495]: PTHREAD support initialized", .field = LM_V_HOST, .regexp = "pthread", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2494]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "^PTHREAD ", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2493]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "PTHREAD s", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2492]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "^PTHREAD$", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: PTHREAD support initialized", .field = LM_V_MESSAGE, .regexp = "(?i)pthread", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a", .field = LM_V_MESSAGE, .regexp = "\\141", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: \1", .field = LM_V_MESSAGE, .regexp = "[\\1]", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abc", .field = LM_V_MESSAGE, .regexp = "ab*c", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abc", .field = LM_V_MESSAGE, .regexp = "ab*bc", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abbbbc", .field = LM_V_MESSAGE, .regexp = "ab{0,}bc", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abbc", .field = LM_V_MESSAGE, .regexp = "ab+bc", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abq", .field = LM_V_MESSAGE, .regexp = "ab+bc", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abq", .field = LM_V_MESSAGE, .regexp = "ab+bc", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abbbbc", .field = LM_V_MESSAGE, .regexp = "ab{1,3}bc", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abbbbc", .field = LM_V_MESSAGE, .regexp = "ab{4,5}bc", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abbc", .field = LM_V_MESSAGE, .regexp = "ab?bc", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abbbbc", .field = LM_V_MESSAGE, .regexp = "ab?bc", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: axyzc", .field = LM_V_MESSAGE, .regexp = "a.*c", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: axyzd", .field = LM_V_MESSAGE, .regexp = "a.*c", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abc", .field = LM_V_MESSAGE, .regexp = "a[bc]d", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abd", .field = LM_V_MESSAGE, .regexp = "a[bc]d", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abd", .field = LM_V_MESSAGE, .regexp = "a[b-d]e", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: ace", .field = LM_V_MESSAGE, .regexp = "a[b-d]e", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a-", .field = LM_V_MESSAGE, .regexp = "a[-b]", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a-", .field = LM_V_MESSAGE, .regexp = "a[b-]", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a]", .field = LM_V_MESSAGE, .regexp = "a]", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a]b", .field = LM_V_MESSAGE, .regexp = "a[]]b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: aed", .field = LM_V_MESSAGE, .regexp = "a[^bc]d", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abd", .field = LM_V_MESSAGE, .regexp = "a[^bc]d", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: adc", .field = LM_V_MESSAGE, .regexp = "a[^-b]c", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a-c", .field = LM_V_MESSAGE, .regexp = "a[^-b]c", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: a]c", .field = LM_V_MESSAGE, .regexp = "a[^]b]", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: adc", .field = LM_V_MESSAGE, .regexp = "a[^]b]c", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abc", .field = LM_V_MESSAGE, .regexp = "ab|cd", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abcd", .field = LM_V_MESSAGE, .regexp = "ab|cd", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a(b", .field = LM_V_MESSAGE, .regexp = "a\\(b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: ab", .field = LM_V_MESSAGE, .regexp = "a\\(*b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a((b", .field = LM_V_MESSAGE, .regexp = "a\\(*b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a\\b", .field = LM_V_MESSAGE, .regexp = "a\\\\b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abcabc", .field = LM_V_MESSAGE, .regexp = "a.+?c", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: effg", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: bcdd", .field = LM_V_MESSAGE, .regexp = "(bc+d$|ef*g.|h?i(j|k))", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: abad", .field = LM_V_MESSAGE, .regexp = "a(?!b).", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abad", .field = LM_V_MESSAGE, .regexp = "a(?=d).", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: abad", .field = LM_V_MESSAGE, .regexp = "a(?=c|d).", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: a\nb", .field = LM_V_MESSAGE, .regexp = "a.b", .flags = 0, .expected_result = FALSE}, {.msg = "<15> openvpn[2491]: a\nb", .field = LM_V_MESSAGE, .regexp = "(?s)a.b", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: --ab_cd0123--", .field = LM_V_MESSAGE, .regexp = "\\w+", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: --ab_cd0123--", .field = LM_V_MESSAGE, .regexp = "[\\w]+", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: 1234abc5678", .field = LM_V_MESSAGE, .regexp = "\\D+", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: 1234abc5678", .field = LM_V_MESSAGE, .regexp = "[\\D]+", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: 123abc", .field = LM_V_MESSAGE, .regexp = "[\\da-fA-F]+", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: testing!1972", .field = LM_V_MESSAGE, .regexp = "([\\s]*)([\\S]*)([\\s]*)", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: testing!1972", .field = LM_V_MESSAGE, .regexp = "(\\s*)(\\S*)(\\s*)", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: \377", .field = LM_V_MESSAGE, .regexp = "\\xff", .flags = 0, .expected_result = TRUE}, {.msg = "<15> openvpn[2491]: \377", .field = LM_V_MESSAGE, .regexp = "\\x00ff", .flags = 0, .expected_result = FALSE}, }; return cr_make_param_array(FilterParamRegexp, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRegexp *param, filter, test_filter_regexp_filter) { FilterExprNode *filter = create_pcre_regexp_filter(param->field, param->regexp, param->flags); testcase(param->msg, filter, param->expected_result); } ParameterizedTestParameters(filter, test_filter_regexp_filter_fop) { static FilterParamRegexp test_data_list[] = { {.msg = "<15>Oct 16 16:17:01 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = " PTHREAD ", .flags = 0, .regexp2 = "PTHREAD", .flags2 = 0, .expected_result = TRUE}, {.msg = "<15>Oct 16 16:17:02 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = " PTHREAD ", .flags = 0, .regexp2 = "^PTHREAD$", .flags2 = 0, .expected_result = FALSE}, {.msg = "<15>Oct 16 16:17:03 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = "^PTHREAD$", .flags = 0, .regexp2 = " PTHREAD ", .flags2 = 0, .expected_result = FALSE}, {.msg = "<15>Oct 16 16:17:04 host openvpn[2499]: PTHREAD support initialized", .field = LM_V_PROGRAM, .regexp = " PAD ", .flags = 0, .regexp2 = "^PTHREAD$", .flags2 = 0, .expected_result = FALSE}, }; return cr_make_param_array(FilterParamRegexp, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRegexp *param, filter, test_filter_regexp_filter_fop) { FilterExprNode *filter = fop_and_new(create_pcre_regexp_match(param->regexp, param->flags), create_pcre_regexp_match(param->regexp2, param->flags2)); testcase(param->msg, filter, param->expected_result); } ParameterizedTestParameters(filter, test_filter_regexp_match_fop) { static FilterParamRegexp test_data_list[] = { {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = " PTHREAD ", .flags = 0, .regexp2 = "PTHREAD", .flags2 = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:02 host openvpn[2499]: PTHREAD support initialized", .regexp = " PTHREAD ", .flags = 0, .regexp2 = "^PTHREAD$", .flags2 = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:03 host openvpn[2499]: PTHREAD support initialized", .regexp = "^PTHREAD$", .flags = 0, .regexp2 = " PTHREAD ", .flags2 = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:04 host openvpn[2499]: PTHREAD support initialized", .regexp = " PAD ", .flags = 0, .regexp2 = "^PTHREAD$", .flags2 = 0, .expected_result = FALSE}, }; return cr_make_param_array(FilterParamRegexp, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRegexp *param, filter, test_filter_regexp_match_fop) { FilterExprNode *filter = fop_or_new(create_pcre_regexp_match(param->regexp, param->flags), create_pcre_regexp_match(param->regexp2, param->flags2)); testcase(param->msg, filter, param->expected_result); } ParameterizedTestParameters(filter, test_filter_regexp_match) { static FilterParamRegexp test_data_list[] = { {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = " PTHREAD ", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = "^openvpn\\[2499\\]: PTHREAD", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = "^PTHREAD$", .flags = 0, .expected_result = FALSE}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = "(?i)pthread", .flags = 0, .expected_result = TRUE}, {.msg = "<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", .regexp = "pthread", .flags = LMF_ICASE, .expected_result = TRUE}, }; return cr_make_param_array(FilterParamRegexp, test_data_list, G_N_ELEMENTS(test_data_list)); } ParameterizedTest(FilterParamRegexp *param, filter, test_filter_regexp_match) { FilterExprNode *filter = create_pcre_regexp_match(param->regexp, param->flags); testcase(param->msg, filter, param->expected_result); } Test(filter, test_match_with_overwritten_match_as_source) { FilterExprNode *filter; filter = create_pcre_regexp_match("^(PTHREAD)( )(support)", LMF_STORE_MATCHES); filter_match_set_value_handle(filter, log_msg_get_value_handle("1")); cr_assert(filter_expr_init(filter, configuration) == TRUE); LogMessage *msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "PTHREAD support initialized", -1); gboolean res = filter_expr_eval(filter, msg); cr_assert(res == TRUE); /* $1 reset to the capture group's value */ assert_log_message_match_value(msg, 1, "PTHREAD"); assert_log_message_match_value(msg, 2, " "); assert_log_message_match_value(msg, 3, "support"); } Test(filter, test_match_with_overwritten_trivial_template_as_source) { FilterExprNode *filter; filter = create_pcre_regexp_match("^(PTHREAD)( )(support) initialized", LMF_STORE_MATCHES); filter_match_set_template_ref(filter, compile_template("$1")); cr_assert(filter_expr_init(filter, configuration) == TRUE); LogMessage *msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "PTHREAD support initialized", -1); gboolean res = filter_expr_eval(filter, msg); cr_assert(res == TRUE); /* $1 reset to the capture group's value */ assert_log_message_match_value(msg, 1, "PTHREAD"); assert_log_message_match_value(msg, 2, " "); assert_log_message_match_value(msg, 3, "support"); } Test(filter, test_match_with_value) { FilterExprNode *filter; filter = create_pcre_regexp_match("^PTHREAD", 0); filter_match_set_value_handle(filter, LM_V_MESSAGE); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); filter = create_pcre_regexp_match("^2499", 0); filter_match_set_value_handle(filter, LM_V_PID); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); } Test(filter, test_match_with_template_literal) { FilterExprNode *filter; filter = create_pcre_regexp_match("^PTHREAD", 0); filter_match_set_template_ref(filter, compile_template("PTHREAD")); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); filter = create_pcre_regexp_match("^2499", 0); filter_match_set_template_ref(filter, compile_template("2499")); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); } Test(filter, test_match_with_template_trivial) { FilterExprNode *filter; filter = create_pcre_regexp_match("^PTHREAD", 0); filter_match_set_template_ref(filter, compile_template("$MSG")); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); filter = create_pcre_regexp_match("^2499", 0); filter_match_set_template_ref(filter, compile_template("$PID")); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); } Test(filter, test_match_with_template_non_trivial) { FilterExprNode *filter; filter = create_pcre_regexp_match("^2499 openvpn", 0); filter_match_set_template_ref(filter, compile_template("$PID $PROGRAM")); testcase("<15>Oct 15 16:17:01 host openvpn[2499]: PTHREAD support initialized", filter, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/filter/tests/test_filters_statistics.c000066400000000000000000000056711450431004300257060ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "plugin.h" #include "apphook.h" #include "syslog-names.h" #include "stats/stats-registry.h" #include "filter/filter-pipe.h" #include "filter/filter-pri.h" #include "msg-format.h" static gint level_bits(gchar *lev) { return 1 << syslog_name_lookup_severity_by_name(lev); } MsgFormatOptions parse_options; static LogFilterPipe * create_log_filter_pipe(void) { FilterExprNode *filter = filter_severity_new(level_bits("debug")); filter_expr_init(filter, configuration); LogFilterPipe *p = (LogFilterPipe *)log_filter_pipe_new(filter, configuration); log_pipe_init(&p->super); return p; } static void queue_and_assert_statistics(LogFilterPipe *pipe, gchar *msg, guint32 matched_expected, guint32 not_matched_expected) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *logmsg = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); LogPipe *p = (LogPipe *)pipe; p->queue(p, logmsg, &path_options); cr_assert_eq(stats_counter_get(pipe->not_matched), not_matched_expected); cr_assert_eq(stats_counter_get(pipe->matched), matched_expected); } void setup(void) { app_startup(); configuration = cfg_new_snippet(); configuration->stats_options.level = 1; cfg_load_module(configuration, "syslogformat"); cfg_init(configuration); } void teardown(void) { cfg_deinit(configuration); cfg_free(configuration); app_shutdown(); } TestSuite(test_filters_statistics, .init = setup, .fini = teardown); Test(test_filters_statistics, filter_stastistics) { msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); LogFilterPipe *p = create_log_filter_pipe(); queue_and_assert_statistics(p, "<15> openvpn[2499]: PTHREAD support initialized", 1, 0); queue_and_assert_statistics(p, "<16> openvpn[2499]: PTHREAD support initialized", 1, 1); queue_and_assert_statistics(p, "<16> openvpn[2499]: PTHREAD support initialized", 1, 2); log_pipe_deinit(&p->super); log_pipe_unref(&p->super); } syslog-ng-syslog-ng-4.4.0/lib/find-crlf.c000066400000000000000000000055331450431004300201370ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "find-crlf.h" #include /** * This is an optimized version of finding either a CR or LF or NUL * character in a buffer. It is used to find these line terminators in * syslog traffic. * * It uses an algorithm very similar to what there's in libc memchr/strchr. **/ gchar * find_cr_or_lf_or_nul(gchar *s, gsize n) { gchar *char_ptr; gulong *longword_ptr; gulong longword, magic_bits, cr_charmask, lf_charmask; const char CR = '\r'; const char LF = '\n'; /* align input to long boundary */ for (char_ptr = s; n > 0 && ((gulong) char_ptr & (sizeof(longword) - 1)) != 0; ++char_ptr, n--) { if (*char_ptr == CR || *char_ptr == LF || *char_ptr == 0) return char_ptr; } longword_ptr = (gulong *) char_ptr; #if GLIB_SIZEOF_LONG == 8 magic_bits = 0x7efefefefefefeffL; #elif GLIB_SIZEOF_LONG == 4 magic_bits = 0x7efefeffL; #else #error "unknown architecture" #endif memset(&cr_charmask, CR, sizeof(cr_charmask)); memset(&lf_charmask, LF, sizeof(lf_charmask)); while (n > sizeof(longword)) { longword = *longword_ptr++; if ((((longword + magic_bits) ^ ~longword) & ~magic_bits) != 0 || ((((longword ^ cr_charmask) + magic_bits) ^ ~(longword ^ cr_charmask)) & ~magic_bits) != 0 || ((((longword ^ lf_charmask) + magic_bits) ^ ~(longword ^ lf_charmask)) & ~magic_bits) != 0) { gint i; char_ptr = (gchar *) (longword_ptr - 1); for (i = 0; i < sizeof(longword); i++) { if (*char_ptr == CR || *char_ptr == LF || *char_ptr == 0) return char_ptr; char_ptr++; } } n -= sizeof(longword); } char_ptr = (gchar *) longword_ptr; while (n-- > 0) { if (*char_ptr == CR || *char_ptr == LF || *char_ptr == 0) return char_ptr; ++char_ptr; } return NULL; } syslog-ng-syslog-ng-4.4.0/lib/find-crlf.h000066400000000000000000000021711450431004300201370ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef FIND_CRLF_H_INCLUDED #define FIND_CRLF_H_INCLUDED 1 #include "syslog-ng.h" gchar *find_cr_or_lf_or_nul(gchar *s, gsize n); #endif syslog-ng-syslog-ng-4.4.0/lib/generic-number.c000066400000000000000000000065721450431004300212010ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "generic-number.h" #include gdouble gn_as_double(const GenericNumber *number) { if (number->type == GN_DOUBLE) return number->value.raw_double; else if (number->type == GN_INT64) return (gdouble) number->value.raw_int64; g_assert_not_reached(); } void gn_set_double(GenericNumber *number, gdouble value, gint precision) { number->type = GN_DOUBLE; number->value.raw_double = value; number->precision = precision > 0 ? precision : 20; } gint64 gn_as_int64(const GenericNumber *number) { if (number->type == GN_DOUBLE) { double r = round(number->value.raw_double); if (r <= (double) G_MININT64) return G_MININT64; if (r >= (double) G_MAXINT64) return G_MAXINT64; return (gint64) r; } else if (number->type == GN_INT64) return number->value.raw_int64; g_assert_not_reached(); } void gn_set_int64(GenericNumber *number, gint64 value) { number->type = GN_INT64; number->value.raw_int64 = value; number->precision = 0; } gboolean gn_is_zero(const GenericNumber *number) { if (number->type == GN_INT64) return number->value.raw_int64 == 0; if (number->type == GN_DOUBLE) return fabs(number->value.raw_double) < DBL_EPSILON; g_assert_not_reached(); } void gn_set_nan(GenericNumber *number) { number->type = GN_NAN; } gboolean gn_is_nan(const GenericNumber *number) { return number->type == GN_NAN || (number->type == GN_DOUBLE && isnan(number->value.raw_double)); } static gint _compare_int64(gint64 l, gint64 r) { if (l == r) return 0; else if (l < r) return -1; return 1; } static gint _compare_double(gdouble l, gdouble r) { if (fabs(l - r) < DBL_EPSILON) return 0; else if (l < r) return -1; return 1; } gint gn_compare(const GenericNumber *left, const GenericNumber *right) { if (left->type == right->type) { if (left->type == GN_INT64) return _compare_int64(gn_as_int64(left), gn_as_int64(right)); else if (left->type == GN_DOUBLE) return _compare_double(gn_as_double(left), gn_as_double(right)); } else if (left->type == GN_NAN || right->type == GN_NAN) { ; } else if (left->type == GN_DOUBLE || right->type == GN_DOUBLE) { return _compare_double(gn_as_double(left), gn_as_double(right)); } else { return _compare_int64(gn_as_int64(left), gn_as_int64(right)); } /* NaNs cannot be compared */ g_assert_not_reached(); } syslog-ng-syslog-ng-4.4.0/lib/generic-number.h000066400000000000000000000033151450431004300211760ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef SYSLOG_NG_GENERIC_NUMBER_H_INCLUDED #define SYSLOG_NG_GENERIC_NUMBER_H_INCLUDED #include "syslog-ng.h" typedef struct _GenericNumber { enum { GN_INT64, GN_DOUBLE, GN_NAN, } type; union { gint64 raw_int64; gdouble raw_double; } value; gint precision; } GenericNumber; void gn_set_double(GenericNumber *number, double value, gint precision); gdouble gn_as_double(const GenericNumber *number); void gn_set_int64(GenericNumber *number, gint64 value); gint64 gn_as_int64(const GenericNumber *number); gboolean gn_is_zero(const GenericNumber *number); void gn_set_nan(GenericNumber *number); gboolean gn_is_nan(const GenericNumber *number); gint gn_compare(const GenericNumber *left, const GenericNumber *right); #endif syslog-ng-syslog-ng-4.4.0/lib/globals.c000066400000000000000000000020701450431004300177070ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" GlobalConfig *configuration; int cfg_parser_debug; syslog-ng-syslog-ng-4.4.0/lib/gprocess.c000066400000000000000000001260431450431004300201200ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "gprocess.h" #include "userdb.h" #include "messages.h" #include "reloc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if SYSLOG_NG_ENABLE_LINUX_CAPS # include # include #endif /* * NOTES: * * * pidfile is created and removed by the daemon (e.g. the child) itself, * the parent does not touch that * * * we communicate with the user using stderr (using fprintf) as long as it * is available and using syslog() afterwards * * * there are 3 processes involved in safe_background mode (e.g. auto-restart) * - startup process which was started by the user (zorpctl) * - supervisor process which automatically restarts the daemon when it exits abnormally * - daemon processes which perform the actual task at hand * * The startup process delivers the result of the first startup to its * caller, if we can deliver a failure in this case then restarts will not * be performed (e.g. if the first startup fails, the daemon will not be * restarted even if auto-restart was enabled). After the first successful * start, the startup process exits (delivering that startup was * successful) and the supervisor process wait()s for the daemon processes * to exit. If they exit prematurely (e.g. they crash) they will be * restarted, if the startup is not successful in this case the restart * will be attempted again just as if they crashed. * * The processes communicate with two pairs of pipes, startup_result_pipe * is used to indicate success/failure to the startup process, * init_result_pipe (as in "initialization") is used to deliver success * reports from the daemon to the supervisor. */ typedef enum { G_PK_STARTUP, G_PK_SUPERVISOR, G_PK_DAEMON, } GProcessKind; #define SAFE_STRING(x) ((x) ? (x) : "NULL") #define G_PROCESS_FD_LIMIT_RESERVE 64 #define G_PROCESS_FAILURE_NOTIFICATION SYSLOG_NG_PATH_PREFIX "/sbin/syslog-ng-failure" /* pipe used to deliver the initialization result to the calling process */ static gint startup_result_pipe[2] = { -1, -1 }; /* pipe used to deliver initialization result to the supervisor */ static gint init_result_pipe[2] = { -1, -1 }; static GProcessKind process_kind = G_PK_STARTUP; static gboolean stderr_present = TRUE; #if SYSLOG_NG_ENABLE_LINUX_CAPS static int have_capsyslog = FALSE; static cap_value_t cap_syslog; #endif #ifdef SYSLOG_NG_HAVE_ENVIRON extern char **environ; #endif /* global variables */ static struct { GProcessMode mode; const gchar *name; const gchar *user; gint uid; const gchar *group; gint gid; const gchar *chroot_dir; const gchar *pidfile; const gchar *pidfile_dir; const gchar *cwd; const gchar *caps; gboolean enable_caps; gint argc; gchar **argv; gchar *argv_start; size_t argv_env_len; gchar *argv_orig; gboolean core; gint fd_limit_min; gint check_period; gboolean (*check_fn)(void); } process_opts = { .mode = G_PM_SAFE_BACKGROUND, .argc = 0, .argv = NULL, .argv_start = NULL, .argv_env_len = 0, .fd_limit_min = 0, .check_period = -1, .check_fn = NULL, .uid = -1, .gid = -1, .enable_caps = TRUE, .caps = NULL }; #if SYSLOG_NG_ENABLE_SYSTEMD /** * Inherits systemd socket activation from parent process updating the pid * in LISTEN_PID to the pid of the child process. * * @return same as sd_listen_fds * r == 0: no socket activation or this process is not responsible * r > 0: success, number of sockets * r < 0: an error occurred */ static int inherit_systemd_activation(void) { const char *e; char buf[24] = { '\0' }; char *p = NULL; unsigned long l; /* fetch listen pid */ if (!(e = getenv("LISTEN_PID"))) return 0; errno = 0; l = strtoul(e, &p, 10); if (errno != 0 || !p || *p || l == 0) return (errno) ? -errno : -EINVAL; /* was it for our parent? */ if (getppid() != (pid_t)l) return 0; /* verify listen fds */ if (!(e = getenv("LISTEN_FDS"))) return 0; errno = 0; l = strtoul(e, &p, 10); if (errno != 0 || !p || *p) return (errno) ? -errno : -EINVAL; /* update the listen pid to ours */ snprintf(buf, sizeof(buf), "%d", getpid()); if (errno != 0 || !*buf) return (errno) ? -errno : -EINVAL; if (setenv("LISTEN_PID", buf, 1) == 0) return (int)l; return -1; } #else #define inherit_systemd_activation() #endif #if SYSLOG_NG_ENABLE_LINUX_CAPS typedef enum _cap_result_type { CAP_NOT_SUPPORTED_BY_KERNEL = -2, CAP_NOT_SUPPORTED_BY_LIBCAP = -1, CAP_SUPPORTED = 1, } cap_result_type; static cap_result_type _check_and_get_cap_from_text(const gchar *cap_text, cap_value_t *cap) { int ret; ret = cap_from_name(cap_text, cap); if (ret == -1) { return CAP_NOT_SUPPORTED_BY_LIBCAP; } ret = prctl(PR_CAPBSET_READ, *cap); if (ret == -1) { return CAP_NOT_SUPPORTED_BY_KERNEL; } return CAP_SUPPORTED; } static EVTTAG * evt_tag_cap_t(const char *tag, cap_t cap) { gchar *cap_text = cap_to_text(cap, NULL); EVTTAG *evt_tag = evt_tag_str(tag, cap_text); cap_free(cap_text); return evt_tag; } /** * g_process_enable_cap: * @capability: capability to turn on * * This function modifies the current permitted set of capabilities by * enabling the capability specified in @capability. * * Returns: whether the operation was successful. **/ gboolean g_process_enable_cap(const gchar *cap_name) { if (!g_process_is_cap_enabled()) return TRUE; cap_value_t capability; cap_result_type ret = _check_and_get_cap_from_text(cap_name, &capability); if (CAP_SUPPORTED != ret) return FALSE; /* * if libcap or kernel doesn't support cap_syslog, then resort to * cap_sys_admin */ if (capability == cap_syslog && !have_capsyslog) { ret = _check_and_get_cap_from_text("cap_sys_admin", &capability); if (ret != CAP_SUPPORTED) return FALSE; } cap_t caps = cap_get_proc(); if (!caps) return FALSE; if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability, CAP_SET) == -1) { goto error; } if (cap_set_proc(caps) == -1) { goto error; } cap_free(caps); return TRUE; error: msg_error("Error managing capability set", evt_tag_cap_t("caps", caps), evt_tag_error("error")); cap_free(caps); return FALSE; } /** * g_process_cap_save: * * Save the set of current capabilities and return it. The caller might * restore the saved set of capabilities by using cap_restore(). * * Returns: the current set of capabilities **/ cap_t g_process_cap_save(void) { if (!g_process_is_cap_enabled()) return NULL; return cap_get_proc(); } /** * cap_restore: * @r: capability set saved by cap_save() * * Restore the set of current capabilities specified by @r. * * Returns: whether the operation was successful. **/ void g_process_cap_restore(cap_t r) { gboolean rc; if (!g_process_is_cap_enabled()) return; rc = cap_set_proc(r) != -1; if (!rc) { msg_error("Error managing capability set, cap_set_proc returned an error", evt_tag_cap_t("caps", r), evt_tag_error("error")); } cap_free(r); } #ifndef PR_CAPBSET_READ /* old glibc versions don't have PR_CAPBSET_READ, we define it to the * value as defined in newer versions. */ #define PR_CAPBSET_READ 23 #endif gboolean g_process_check_cap_syslog(void) { if (have_capsyslog) return TRUE; switch (_check_and_get_cap_from_text("cap_syslog", &cap_syslog)) { case CAP_NOT_SUPPORTED_BY_LIBCAP: if (debug_flag) { fprintf (stderr, "The CAP_SYSLOG is not supported by libcap;" "Falling back to CAP_SYS_ADMIN!\n"); } return FALSE; break; case CAP_NOT_SUPPORTED_BY_KERNEL: if (debug_flag) { fprintf (stderr, "CAP_SYSLOG seems to be supported by libcap, but " "the kernel does not appear to recognize it. Falling back " "to CAP_SYS_ADMIN!\n"); } return FALSE; break; case CAP_SUPPORTED: have_capsyslog = TRUE; return TRUE; break; default: return FALSE; break; } } gboolean g_process_is_cap_enabled(void) { return process_opts.enable_caps; } #endif /** * g_process_set_mode: * @mode: an element from ZProcessMode * * This function should be called by the daemon to set the processing mode * as specified by @mode. **/ void g_process_set_mode(GProcessMode mode) { process_opts.mode = mode; } /** * g_process_get_mode: * * Return the processing mode applied to the daemon. **/ GProcessMode g_process_get_mode(void) { return process_opts.mode; } /** * g_process_set_name: * @name: the name of the process to be reported as program name * * This function should be called by the daemon to set the program name * which is present in various error message and might influence the PID * file if not overridden by g_process_set_pidfile(). **/ void g_process_set_name(const gchar *name) { process_opts.name = name; } /** * g_process_set_user: * @user: the name of the user the process should switch to during startup * * This function should be called by the daemon to set the user name. **/ void g_process_set_user(const gchar *user) { if (!process_opts.user) process_opts.user = user; } /** * g_process_set_group: * @group: the name of the group the process should switch to during startup * * This function should be called by the daemon to set the group name. **/ void g_process_set_group(const gchar *group) { if (!process_opts.group) process_opts.group = group; } /** * g_process_set_chroot: * @chroot_dir: the name of the chroot directory the process should switch to during startup * * This function should be called by the daemon to set the chroot directory **/ void g_process_set_chroot(const gchar *chroot_dir) { if (!process_opts.chroot_dir) process_opts.chroot_dir = chroot_dir; } /** * g_process_set_pidfile: * @pidfile: the name of the complete pid file with full path * * This function should be called by the daemon to set the PID file name to * store the pid of the process. This value will be used as the pidfile * directly, neither name nor pidfile_dir influences the pidfile location if * this is set. **/ void g_process_set_pidfile(const gchar *pidfile) { if (!process_opts.pidfile) process_opts.pidfile = pidfile; } /** * g_process_set_pidfile_dir: * @pidfile_dir: name of the pidfile directory * * This function should be called by the daemon to set the PID file * directory. This value is not used if set_pidfile() was called. **/ void g_process_set_pidfile_dir(const gchar *pidfile_dir) { if (!process_opts.pidfile_dir) process_opts.pidfile_dir = pidfile_dir; } /** * g_process_set_working_dir: * @working_dir: name of the working directory * * This function should be called by the daemon to set the working * directory. The process will change its current directory to this value or * to pidfile_dir if it is unset. **/ void g_process_set_working_dir(const gchar *cwd) { if (!process_opts.cwd) process_opts.cwd = cwd; } /** * g_process_set_caps: * @caps: capability specification in text form * * This function should be called by the daemon to set the initial * capability set. The process will change its capabilities to this value * during startup, provided it has enough permissions to do so. **/ void g_process_set_caps(const gchar *caps) { if (!process_opts.caps) process_opts.caps = caps; } /** * g_process_set_argv_space: * @argc: Original argc, as received by the main function in it's first parameter * @argv: Original argv, as received by the main function in it's second parameter * * This function should be called by the daemon if it wants to enable * process title manipulation in the supervisor process. **/ void g_process_set_argv_space(gint argc, gchar **argv) { #ifdef SYSLOG_NG_HAVE_ENVIRON gchar *lastargv = NULL; gchar **envp = environ; gint i; if (process_opts.argv) return; process_opts.argv = argv; process_opts.argc = argc; for (i = 0; envp[i] != NULL; i++) ; environ = g_new(char *, i + 1); /* * Find the last argv string or environment variable within * our process memory area. */ for (i = 0; i < process_opts.argc; i++) { if (lastargv == NULL || lastargv + 1 == process_opts.argv[i]) lastargv = process_opts.argv[i] + strlen(process_opts.argv[i]); } for (i = 0; envp[i] != NULL; i++) { if (lastargv + 1 == envp[i]) lastargv = envp[i] + strlen(envp[i]); } process_opts.argv_start = process_opts.argv[0]; process_opts.argv_env_len = lastargv - process_opts.argv[0] - 1; process_opts.argv_orig = malloc(sizeof(gchar) * process_opts.argv_env_len); memcpy(process_opts.argv_orig, process_opts.argv_start, process_opts.argv_env_len); /* * Copy environment * XXX - will truncate env on strdup fail */ for (i = 0; envp[i] != NULL; i++) environ[i] = g_strdup(envp[i]); environ[i] = NULL; #endif } /** * g_process_set_check: * @check_period: check period in seconds * @check_fn: checker function * * Installs a checker function that is called at the specified rate. * The checked process is allowed to run as long as this function * returns TRUE. */ void g_process_set_check(gint check_period, gboolean (*check_fn)(void)) { process_opts.check_period = check_period; process_opts.check_fn = check_fn; } /** * g_process_message: * @fmt: format string * @...: arguments to @fmt * * This function sends a message to the client preferring to use the stderr * channel as long as it is available and switching to using syslog() if it * isn't. Generally the stderr channell will be available in the startup * process and in the beginning of the first startup in the * supervisor/daemon processes. Later on the stderr fd will be closed and we * have to fall back to using the system log. **/ void g_process_message(const gchar *fmt, ...) { gchar buf[2048]; va_list ap; va_start(ap, fmt); g_vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (stderr_present) fprintf(stderr, "%s: %s\n", process_opts.name, buf); else { gchar name[32]; g_snprintf(name, sizeof(name), "%s/%s", process_kind == G_PK_SUPERVISOR ? "supervise" : "daemon", process_opts.name); openlog(name, LOG_PID, LOG_DAEMON); syslog(LOG_CRIT, "%s\n", buf); closelog(); } } /** * g_process_detach_tty: * * This function is called from g_process_start() to detach from the * controlling tty. **/ static void g_process_detach_tty(void) { if (process_opts.mode != G_PM_FOREGROUND) { /* detach ourselves from the tty when not staying in the foreground */ if (isatty(STDIN_FILENO)) { #ifdef TIOCNOTTY ioctl(STDIN_FILENO, TIOCNOTTY, 0); #endif } setsid(); } } /** * g_process_change_limits: * * Set fd limit. * **/ static void g_process_change_limits(void) { struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit); #if defined(__APPLE__) && defined(__MACH__) limit.rlim_cur = MIN(OPEN_MAX, limit.rlim_max); #else limit.rlim_cur = limit.rlim_max; #endif if (process_opts.fd_limit_min) { limit.rlim_cur = limit.rlim_max = process_opts.fd_limit_min; } if (setrlimit(RLIMIT_NOFILE, &limit) < 0) g_process_message("Error setting file number limit; limit='%d'; error='%s'", process_opts.fd_limit_min, g_strerror(errno)); } /** * g_process_detach_stdio: * * Use /dev/null as input/output/error. This function is idempotent, can be * called any number of times without harm. **/ static void g_process_detach_stdio(void) { gint devnull_fd; if (process_opts.mode != G_PM_FOREGROUND && stderr_present) { devnull_fd = open("/dev/null", O_RDONLY); if (devnull_fd >= 0) { dup2(devnull_fd, STDIN_FILENO); close(devnull_fd); } devnull_fd = open("/dev/null", O_WRONLY); if (devnull_fd >= 0) { dup2(devnull_fd, STDOUT_FILENO); dup2(devnull_fd, STDERR_FILENO); close(devnull_fd); } stderr_present = FALSE; } } static void g_process_set_dumpable(void) { #if SYSLOG_NG_ENABLE_LINUX_CAPS if (!prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { gint rc; rc = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); if (rc < 0) g_process_message("Cannot set process to be dumpable; error='%s'", g_strerror(errno)); } #endif } /** * g_process_enable_core: * * Enable core file dumping by setting PR_DUMPABLE and changing the core * file limit to infinity. **/ static void g_process_enable_core(void) { struct rlimit limit; if (process_opts.core) { g_process_set_dumpable(); limit.rlim_cur = limit.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &limit) < 0) g_process_message("Error setting core limit to infinity; error='%s'", g_strerror(errno)); } } /** * g_process_format_pidfile_name: * @buf: buffer to store the pidfile name * @buflen: size of @buf * * Format the pid file name according to the settings specified by the * process. **/ static const gchar * g_process_format_pidfile_name(gchar *buf, gsize buflen) { const gchar *pidfile = process_opts.pidfile; if (pidfile == NULL) { g_snprintf(buf, buflen, "%s/%s.pid", process_opts.pidfile_dir ? process_opts.pidfile_dir : get_installation_path_for(SYSLOG_NG_PATH_PIDFILEDIR), process_opts.name); pidfile = buf; } else if (pidfile[0] != '/') { /* complete path to pidfile not specified, assume it is a relative path to pidfile_dir */ g_snprintf(buf, buflen, "%s/%s", process_opts.pidfile_dir ? process_opts.pidfile_dir : get_installation_path_for( SYSLOG_NG_PATH_PIDFILEDIR), pidfile); pidfile = buf; } return pidfile; } /** * g_process_write_pidfile: * @pid: pid to write into the pidfile * * Write the pid to the pidfile. **/ static void g_process_write_pidfile(pid_t pid) { gchar buf[256]; const gchar *pidfile; FILE *fd; pidfile = g_process_format_pidfile_name(buf, sizeof(buf)); fd = fopen(pidfile, "w"); if (fd != NULL) { fprintf(fd, "%d\n", (int) pid); fclose(fd); } else { g_process_message("Error creating pid file; file='%s', error='%s'", pidfile, g_strerror(errno)); } } /** * g_process_remove_pidfile: * * Remove the pidfile. **/ static void g_process_remove_pidfile(void) { gchar buf[256]; const gchar *pidfile; pidfile = g_process_format_pidfile_name(buf, sizeof(buf)); if (unlink(pidfile) < 0) { g_process_message("Error removing pid file; file='%s', error='%s'", pidfile, g_strerror(errno)); } } /** * g_process_change_root: * * Change the current root to the value specified by the user, causes the * startup process to fail if this function returns FALSE. (e.g. the user * specified a chroot but we could not change to that directory) * * Returns: TRUE to indicate success **/ static gboolean g_process_change_root(void) { if (process_opts.chroot_dir) { if (chroot(process_opts.chroot_dir) < 0) { g_process_message("Error in chroot(); chroot='%s', error='%s'\n", process_opts.chroot_dir, g_strerror(errno)); return FALSE; } if (chdir("/") < 0) { g_process_message("Error in chdir() after chroot; chroot='%s', error='%s'\n", process_opts.chroot_dir, g_strerror(errno)); return FALSE; } } return TRUE; } static void g_process_keep_caps(void) { #if SYSLOG_NG_ENABLE_LINUX_CAPS if (g_process_is_cap_enabled()) prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); #endif } /** * g_process_change_user: * * Change the current user/group/groups to the value specified by the user. * causes the startup process to fail if this function returns FALSE. (e.g. * the user requested the uid/gid to change we could not change to that uid) * * Returns: TRUE to indicate success **/ static gboolean g_process_change_user(void) { g_process_keep_caps(); if (process_opts.gid >= 0) { if (setgid((gid_t) process_opts.gid) < 0) { g_process_message("Error in setgid(); group='%s', gid='%d', error='%s'", process_opts.group, process_opts.gid, g_strerror(errno)); if (getuid() == 0) return FALSE; } if (process_opts.user && initgroups(process_opts.user, (gid_t) process_opts.gid) < 0) { g_process_message("Error in initgroups(); user='%s', error='%s'", process_opts.user, g_strerror(errno)); if (getuid() == 0) return FALSE; } } if (process_opts.uid >= 0) { if (setuid((uid_t) process_opts.uid) < 0) { g_process_message("Error in setuid(); user='%s', uid='%d', error='%s'", process_opts.user, process_opts.uid, g_strerror(errno)); if (getuid() == 0) return FALSE; } } return TRUE; } #if SYSLOG_NG_ENABLE_LINUX_CAPS /** * g_process_change_caps: * * Change the current capset to the value specified by the user. causes the * startup process to fail if this function returns FALSE, but we only do * this if the capset cannot be parsed, otherwise a failure changing the * capabilities will not result in failure * * Returns: TRUE to indicate success **/ static gboolean g_process_change_caps(void) { if (g_process_is_cap_enabled()) { cap_t cap = cap_from_text(process_opts.caps); if (cap == NULL) { g_process_message("Error parsing capabilities: %s", process_opts.caps); g_process_disable_caps(); return FALSE; } else { if (cap_set_proc(cap) == -1) { g_process_message("Error setting capabilities, capability management disabled; error='%s'", g_strerror(errno)); g_process_disable_caps(); } cap_free(cap); } } return TRUE; } #else static gboolean g_process_change_caps(void) { return TRUE; } #endif static void g_process_resolve_names(void) { if (process_opts.user && !resolve_user(process_opts.user, &process_opts.uid)) { g_process_message("Error resolving user; user='%s'", process_opts.user); process_opts.uid = -1; } if (process_opts.group && !resolve_group(process_opts.group, &process_opts.gid)) { g_process_message("Error resolving group; group='%s'", process_opts.group); process_opts.gid = -1; } } /** * g_process_change_dir: * * Change the current working directory to the value specified by the user * and verify that the daemon would be able to dump core to that directory * if that is requested. **/ static void g_process_change_dir(void) { const gchar *cwd = NULL; if (process_opts.mode != G_PM_FOREGROUND) { if (process_opts.cwd) cwd = process_opts.cwd; else if (process_opts.pidfile_dir) cwd = process_opts.pidfile_dir; if (!cwd) cwd = get_installation_path_for(SYSLOG_NG_PATH_PIDFILEDIR); if (cwd) if (chdir(cwd)) g_process_message("Error changing to directory=%s, errcode=%d", cwd, errno); } /* this check is here to avoid having to change directory early in the startup process */ if ((process_opts.core) && access(".", W_OK) < 0) { gchar buf[256]; if (!getcwd(buf, sizeof(buf))) strncpy(buf, "unable-to-query", sizeof(buf)); g_process_message("Unable to write to current directory, core dumps will not be generated; dir='%s', error='%s'", buf, g_strerror(errno)); } } /** * g_process_send_result: * @ret_num: exit code of the process * * This function is called to notify our parent process (which is the same * executable process but separated with a fork()) about the result of the * process startup phase. Specifying ret_num == 0 means that everything was * dandy, all other values mean that the initialization failed and the * parent should exit using ret_num as the exit code. The function behaves * differently depending on which process it was called from, determined by * the value of the process_kind global variable. In the daemon process it * writes to init_result_pipe, in the startup process it writes to the * startup_result_pipe. * * This function can only be called once, further invocations will do nothing. **/ static void g_process_send_result(guint ret_num) { gchar buf[10]; guint buf_len; gint *fd; if (process_kind == G_PK_SUPERVISOR) fd = &startup_result_pipe[1]; else if (process_kind == G_PK_DAEMON) fd = &init_result_pipe[1]; else g_assert_not_reached(); if (*fd != -1) { buf_len = g_snprintf(buf, sizeof(buf), "%d\n", ret_num); if (write(*fd, buf, buf_len) < buf_len) g_assert_not_reached(); close(*fd); *fd = -1; } } /** * g_process_recv_result: * * Retrieves an exit code value from one of the result pipes depending on * which process the function was called from. This function can be called * only once, further invocations will return non-zero result code. **/ static gint g_process_recv_result(void) { gchar ret_buf[6]; gint ret_num = 1; gint *fd; /* FIXME: use a timer */ if (process_kind == G_PK_SUPERVISOR) fd = &init_result_pipe[0]; else if (process_kind == G_PK_STARTUP) fd = &startup_result_pipe[0]; else g_assert_not_reached(); if (*fd != -1) { memset(ret_buf, 0, sizeof(ret_buf)); if (read(*fd, ret_buf, sizeof(ret_buf)) > 0) { ret_num = atoi(ret_buf); } else { /* the process probably crashed without telling a proper exit code */ ret_num = 1; } close(*fd); *fd = -1; } return ret_num; } /** * g_process_perform_startup: * * This function is the startup process, never returns, the startup process exits here. **/ static void g_process_perform_startup(void) { /* startup process */ exit(g_process_recv_result()); } #define SPT_PADCHAR '\0' static void g_process_setproctitle(const gchar *proc_title) { #ifdef SYSLOG_NG_HAVE_ENVIRON size_t len; g_assert(process_opts.argv_start != NULL); len = g_strlcpy(process_opts.argv_start, proc_title, process_opts.argv_env_len); for (; len < process_opts.argv_env_len; ++len) process_opts.argv_start[len] = SPT_PADCHAR; #endif } #define PROC_TITLE_SPACE 1024 /** * g_process_perform_supervise: * * Supervise process, returns only in the context of the daemon process, the * supervisor process exits here. **/ static void g_process_perform_supervise(void) { pid_t pid; gboolean first = TRUE, exited = FALSE; gchar proc_title[PROC_TITLE_SPACE]; struct sigaction sa; g_snprintf(proc_title, PROC_TITLE_SPACE, "supervising %s", process_opts.name); g_process_setproctitle(proc_title); memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, NULL); while (1) { if (pipe(init_result_pipe) != 0) { g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); g_process_startup_failed(1, TRUE); } /* fork off a child process */ if ((pid = fork()) < 0) { g_process_message("Error forking child process; error='%s'", g_strerror(errno)); g_process_startup_failed(1, TRUE); } else if (pid != 0) { gint rc; gboolean deadlock = FALSE; /* this is the supervisor process */ /* shut down init_result_pipe write side */ close(init_result_pipe[1]); init_result_pipe[1] = -1; rc = g_process_recv_result(); if (first) { /* first time encounter, we have a chance to report back, do it */ g_process_send_result(rc); if (rc != 0) break; g_process_detach_stdio(); } first = FALSE; if (rc != 0) { gint i = 0; /* initialization failed in daemon, it will probably exit soon, wait and restart */ while (i < 6 && waitpid(pid, &rc, WNOHANG) == 0) { if (i > 3) kill(pid, i > 4 ? SIGKILL : SIGTERM); sleep(1); i++; } if (i == 6) g_process_message("Initialization failed but the daemon did not exit, even when forced to, trying to recover; pid='%d'", pid); continue; } if (process_opts.check_fn && (process_opts.check_period >= 0)) { gint i = 1; while (!(exited = waitpid(pid, &rc, WNOHANG))) { if (i >= process_opts.check_period) { if (!process_opts.check_fn()) break; i = 0; } sleep(1); i++; } if (!exited) { gint j = 0; g_process_message("Daemon deadlock detected, killing process;"); deadlock = TRUE; while (j < 6 && waitpid(pid, &rc, WNOHANG) == 0) { if (j > 3) kill(pid, j > 4 ? SIGKILL : SIGABRT); sleep(1); j++; } if (j == 6) g_process_message("The daemon did not exit after deadlock, even when forced to, trying to recover; pid='%d'", pid); } } else { waitpid(pid, &rc, 0); } if (deadlock || WIFSIGNALED(rc) || (WIFEXITED(rc) && WEXITSTATUS(rc) != 0)) { gchar argbuf[64]; if (!access(G_PROCESS_FAILURE_NOTIFICATION, R_OK | X_OK)) { const gchar *notify_reason; pid_t npid = fork(); gint nrc; switch (npid) { case -1: g_process_message("Could not fork for external notification; reason='%s'", strerror(errno)); break; case 0: switch(fork()) { case -1: g_process_message("Could not fork for external notification; reason='%s'", strerror(errno)); exit(1); break; case 0: if (deadlock) { notify_reason = "deadlock detected"; argbuf[0] = 0; } else { snprintf(argbuf, sizeof(argbuf), "%d", WIFSIGNALED(rc) ? WTERMSIG(rc) : WEXITSTATUS(rc)); if (WIFSIGNALED(rc)) notify_reason = "signalled"; else notify_reason = "non-zero exit code"; } execlp(G_PROCESS_FAILURE_NOTIFICATION, G_PROCESS_FAILURE_NOTIFICATION, SAFE_STRING(process_opts.name), SAFE_STRING(process_opts.chroot_dir), SAFE_STRING(process_opts.pidfile_dir), SAFE_STRING(process_opts.pidfile), SAFE_STRING(process_opts.cwd), SAFE_STRING(process_opts.caps), notify_reason, argbuf, (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL) ? "restarting" : "not-restarting", (gchar *) NULL); g_process_message("Could not execute external notification; reason='%s'", strerror(errno)); break; default: exit(0); break; } /* child process */ default: waitpid(npid, &nrc, 0); break; } } if (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL) { g_process_message("Daemon exited due to a deadlock/signal/failure, restarting; exitcode='%d'", rc); sleep(1); } else { g_process_message("Daemon was killed, not restarting; exitcode='%d'", rc); break; } } else { g_process_message("Daemon exited gracefully, not restarting; exitcode='%d'", rc); break; } } else { /* this is the daemon process, thus we should return to the caller of g_process_start() */ /* shut down init_result_pipe read side */ process_kind = G_PK_DAEMON; close(init_result_pipe[0]); init_result_pipe[0] = -1; /* update systemd socket activation pid */ inherit_systemd_activation(); memcpy(process_opts.argv_start, process_opts.argv_orig, process_opts.argv_env_len); return; } } exit(0); } /** * g_process_start: * * Start the process as directed by the options set by various * g_process_set_*() functions. **/ void g_process_start(void) { pid_t pid; g_process_detach_tty(); g_process_change_limits(); g_process_resolve_names(); if (process_opts.mode == G_PM_BACKGROUND) { /* no supervisor, sends result to startup process directly */ if (pipe(init_result_pipe) != 0) { g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); exit(1); } if ((pid = fork()) < 0) { g_process_message("Error forking child process; error='%s'", g_strerror(errno)); exit(1); } else if (pid != 0) { /* shut down init_result_pipe write side */ close(init_result_pipe[1]); /* connect startup_result_pipe with init_result_pipe */ startup_result_pipe[0] = init_result_pipe[0]; init_result_pipe[0] = -1; g_process_perform_startup(); /* NOTE: never returns */ g_assert_not_reached(); } process_kind = G_PK_DAEMON; /* shut down init_result_pipe read side */ close(init_result_pipe[0]); init_result_pipe[0] = -1; /* update systemd socket activation pid */ inherit_systemd_activation(); } else if (process_opts.mode == G_PM_SAFE_BACKGROUND) { /* full blown startup/supervisor/daemon */ if (pipe(startup_result_pipe) != 0) { g_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); exit(1); } /* first fork off supervisor process */ if ((pid = fork()) < 0) { g_process_message("Error forking child process; error='%s'", g_strerror(errno)); exit(1); } else if (pid != 0) { /* this is the startup process */ /* shut down startup_result_pipe write side */ close(startup_result_pipe[1]); startup_result_pipe[1] = -1; /* NOTE: never returns */ g_process_perform_startup(); g_assert_not_reached(); } /* this is the supervisor process */ /* shut down startup_result_pipe read side */ close(startup_result_pipe[0]); startup_result_pipe[0] = -1; /* update systemd socket activation pid */ inherit_systemd_activation(); process_kind = G_PK_SUPERVISOR; g_process_perform_supervise(); /* we only return in the daamon process here */ } else if (process_opts.mode == G_PM_FOREGROUND) { process_kind = G_PK_DAEMON; } else { g_assert_not_reached(); } /* daemon process, we should return to the caller to perform work */ /* Only call setsid() for backgrounded processes. */ if (process_opts.mode != G_PM_FOREGROUND) { setsid(); } /* NOTE: we need to signal the parent in case of errors from this point. * This is accomplished by writing the appropriate exit code to * init_result_pipe, the easiest way doing so is calling g_process_startup_failed. * */ if (!g_process_change_root() || !g_process_change_user() || !g_process_change_caps()) { g_process_startup_failed(1, TRUE); } g_process_enable_core(); g_process_change_dir(); } /** * g_process_startup_failed: * @ret_num: exit code * @may_exit: whether to exit the process * * This is a public API function to be called by the user code when * initialization failed. **/ void g_process_startup_failed(guint ret_num, gboolean may_exit) { if (process_kind != G_PK_STARTUP) g_process_send_result(ret_num); if (may_exit) { exit(ret_num); } else { g_process_detach_stdio(); } } /** * g_process_startup_ok: * * This is a public API function to be called by the user code when * initialization was successful, we can report back to the user. **/ void g_process_startup_ok(void) { g_process_write_pidfile(getpid()); g_process_send_result(0); g_process_detach_stdio(); } /** * g_process_finish: * * This is a public API function to be called by the user code when the * daemon exits after properly initialized (e.g. when it terminates because * of SIGTERM). This function currently only removes the PID file. **/ void g_process_finish(void) { #ifdef SYSLOG_NG_HAVE_ENVIRON /** * There is a memory leak for **environ and elements that should be * freed here theoretically. * * The reason why environ is copied during g_process_set_argv_space * so to be able to overwrite process title in ps/top commands to * supervisor. In bsd there is setproctitle call which solve this, * but currently it is not available for linux. * * The problem is that modules can add their own env variables to the * list, which must not be freed here, otherwise it would result * double free (e.g some version of Oracle Java). One might also would * try to track which environment variables are added by syslog-ng, * and free only those. There is still a problem with this, **environ * itself cannot be freed in some cases. For example libcurl registers * an atexit function which needs an environment variable, that would * be freed here before at_exit is called, resulting in invalid read. * * As this leak does not cause any real problem like accumulating over * time, it is safe to leave it as it is. */ #endif g_process_remove_pidfile(); } static gboolean g_process_process_mode_arg(const gchar *option_name G_GNUC_UNUSED, const gchar *value, gpointer data G_GNUC_UNUSED, GError **error) { if (strcmp(value, "foreground") == 0) { process_opts.mode = G_PM_FOREGROUND; } else if (strcmp(value, "background") == 0) { process_opts.mode = G_PM_BACKGROUND; } else if (strcmp(value, "safe-background") == 0) { process_opts.mode = G_PM_SAFE_BACKGROUND; } else { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing process-mode argument"); return FALSE; } return TRUE; } void g_process_disable_caps(void) { process_opts.caps = NULL; process_opts.enable_caps = FALSE; } static gboolean g_process_process_no_caps(const gchar *option_name G_GNUC_UNUSED, const gchar *value G_GNUC_UNUSED, gpointer data G_GNUC_UNUSED, GError *error) { g_process_disable_caps(); return TRUE; } static GOptionEntry g_process_option_entries[] = { { "foreground", 'F', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &process_opts.mode, "Do not go into the background after initialization", NULL }, { "process-mode", 0, 0, G_OPTION_ARG_CALLBACK, g_process_process_mode_arg, "Set process running mode", "" }, { "user", 'u', 0, G_OPTION_ARG_STRING, &process_opts.user, "Set the user to run as", "" }, { "uid", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &process_opts.user, NULL, NULL }, { "group", 'g', 0, G_OPTION_ARG_STRING, &process_opts.group, "Set the group to run as", "" }, { "gid", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &process_opts.group, NULL, NULL }, { "chroot", 'C', 0, G_OPTION_ARG_STRING, &process_opts.chroot_dir, "Chroot to this directory", "" }, { "caps", 0, 0, G_OPTION_ARG_STRING, &process_opts.caps, "Set default capability set", "" }, { "no-caps", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, g_process_process_no_caps, "Disable managing Linux capabilities", NULL }, { "pidfile", 'p', 0, G_OPTION_ARG_STRING, &process_opts.pidfile, "Set path to pid file", "" }, { "enable-core", 0, 0, G_OPTION_ARG_NONE, &process_opts.core, "Enable dumping core files", NULL }, { "fd-limit", 0, 0, G_OPTION_ARG_INT, &process_opts.fd_limit_min, "The minimum required number of fds", NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL }, }; void g_process_add_option_group(GOptionContext *ctx) { GOptionGroup *group; group = g_option_group_new("process", "Process options", "Process options", NULL, NULL); g_option_group_add_entries(group, g_process_option_entries); g_option_context_add_group(ctx, group); } syslog-ng-syslog-ng-4.4.0/lib/gprocess.h000066400000000000000000000051351450431004300201230ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef GPROCESS_H_INCLUDED #define GPROCESS_H_INCLUDED #include "syslog-ng.h" #include #include #if SYSLOG_NG_ENABLE_LINUX_CAPS # include #endif typedef enum { G_PM_FOREGROUND, G_PM_BACKGROUND, G_PM_SAFE_BACKGROUND, } GProcessMode; #if SYSLOG_NG_ENABLE_LINUX_CAPS gboolean g_process_enable_cap(const gchar *cap_name); gboolean g_process_is_cap_enabled(void); cap_t g_process_cap_save(void); void g_process_cap_restore(cap_t r); #else typedef gpointer cap_t; #define g_process_enable_cap(cap) #define g_process_cap_save() NULL #define g_process_cap_restore(cap) cap = cap #endif void g_process_message(const gchar *fmt, ...) G_GNUC_PRINTF(1, 2); void g_process_set_mode(GProcessMode mode); GProcessMode g_process_get_mode(void); void g_process_set_name(const gchar *name); void g_process_set_user(const gchar *user); void g_process_set_group(const gchar *group); void g_process_set_chroot(const gchar *chroot); void g_process_set_pidfile(const gchar *pidfile); void g_process_set_pidfile_dir(const gchar *pidfile_dir); void g_process_set_working_dir(const gchar *cwd); void g_process_disable_caps(void); void g_process_set_caps(const gchar *caps); void g_process_set_argv_space(gint argc, gchar **argv); void g_process_set_use_fdlimit(gboolean use); void g_process_set_check(gint check_period, gboolean (*check_fn)(void)); gboolean g_process_check_cap_syslog(void); void g_process_start(void); void g_process_startup_failed(guint ret_num, gboolean may_exit); void g_process_startup_ok(void); void g_process_finish(void); void g_process_add_option_group(GOptionContext *ctx); #endif syslog-ng-syslog-ng-4.4.0/lib/gsockaddr.c000066400000000000000000000356531450431004300202420ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "gsockaddr.h" #include "gsocket.h" #include #include #include #include #include #include #include #include #include #include #include #include /* general GSockAddr functions */ /** * g_sockaddr_new: * @sa: libc sockaddr * pointer to convert * @salen: size of sa * * General function to allocate and initialize a GSockAddr structure, * and convert a libc style sockaddr * pointer to our representation. * * Returns: a GSockAddr instance or NULL if failure * **/ GSockAddr * g_sockaddr_new(struct sockaddr *sa, int salen) { GSockAddr *addr = NULL; switch (sa->sa_family) { #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: if (salen >= sizeof(struct sockaddr_in6)) addr = g_sockaddr_inet6_new2((struct sockaddr_in6 *) sa); break; #endif case AF_INET: if (salen == sizeof(struct sockaddr_in)) addr = g_sockaddr_inet_new2((struct sockaddr_in *) sa); break; case AF_UNIX: addr = g_sockaddr_unix_new2((struct sockaddr_un *) sa, salen); break; default: /*LOG This message indicates an internal error, Zorp tries to use an address family it doesn't support. */ g_error("Unsupported socket family in g_sockaddr_new(); family='%d'", sa->sa_family); break; } return addr; } /** * g_sockaddr_format: * @a instance pointer of a GSockAddr * @text destination buffer * @n the size of text * * Format a GSockAddr into human readable form, calls the format * virtual method of GSockAddr. * * Returns: text is filled with a human readable representation of a, and a * pointer to text is returned. * **/ char * g_sockaddr_format(GSockAddr *a, gchar *text, gulong n, gint format) { return a->sa_funcs->format(a, text, n, format); } guint16 g_sockaddr_get_port(GSockAddr *a) { g_assert(a->sa_funcs->get_port != NULL); return a->sa_funcs->get_port(a); } void g_sockaddr_set_port(GSockAddr *a, guint16 port) { g_assert(a->sa_funcs->set_port != NULL); return a->sa_funcs->set_port(a, port); } guint8 * g_sockaddr_get_address(GSockAddr *self, guint8 *buffer, socklen_t buffer_size) { if (self->sa.sa_family == AF_INET) { struct in_addr addr = g_sockaddr_inet_get_address(self); socklen_t len = sizeof(addr); if (buffer_size < len) { errno = EINVAL; return NULL; } memcpy(buffer, &addr, len); return buffer; } #if SYSLOG_NG_ENABLE_IPV6 else if (self->sa.sa_family == AF_INET6) { struct in6_addr *addr = g_sockaddr_inet6_get_address(self); socklen_t len = sizeof(struct in6_addr); if (buffer_size < len) { errno = EINVAL; return NULL; } memcpy(buffer, addr, len); return buffer; } #endif else { errno = EAFNOSUPPORT; return NULL; } } /*+ Increment the reference count of a GSockAddr instance. Parameters: a pointer to GSockAddr Returns: the same instance +*/ GSockAddr * g_sockaddr_ref(GSockAddr *a) { if (a) g_atomic_counter_inc(&a->refcnt); return a; } /*+ Decrement the reference count of a GSockAddr instance, and free if the refcnt reaches 0. Parameters: a GSockAddr instance Returns: none +*/ void g_sockaddr_unref(GSockAddr *a) { /* FIXME: maybe add a callback to funcs table */ if (a) { if (g_atomic_counter_dec_and_test(&a->refcnt)) { g_slice_free1(g_sockaddr_len(a), a); } } } /* AF_INET socket address */ /*+ GSockAddrInet is an implementation of the GSockAddr interface, encapsulating an IPv4 host address and port number. +*/ typedef struct _GSockAddrInet { GAtomicCounter refcnt; guint32 flags; GSockAddrFuncs *sa_funcs; int salen; struct sockaddr_in sin; } GSockAddrInet; /*+ private function to prepare an IPv4 style bind, e.g. set SO_REUSEADDR +*/ static GIOStatus g_sockaddr_inet_bind_prepare(int sock, GSockAddr *addr) { int tmp = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)); return G_IO_STATUS_NORMAL; } /*+ format an IPv4 address into human readable form */ gchar * g_sockaddr_inet_format(GSockAddr *addr, gchar *text, gulong n, gint format) { GSockAddrInet *self = (GSockAddrInet *) addr; char buf[32]; if (format == GSA_FULL) g_snprintf(text, n, "AF_INET(%s:%d)", g_inet_ntoa(buf, sizeof(buf), self->sin.sin_addr), htons(self->sin.sin_port)); else if (format == GSA_ADDRESS_ONLY) g_inet_ntoa(text, n, self->sin.sin_addr); else g_assert_not_reached(); return text; } /** * g_sockaddr_inet_get_port: * @s: GSockAddrInet instance * * This GSockAddrInet specific function returns the port part of the * address. * * Returns: the port in host byte order * **/ static guint16 g_sockaddr_inet_get_port(GSockAddr *s) { return ntohs(g_sockaddr_inet_get_sa(s)->sin_port); } /** * g_sockaddr_inet_set_port: * @s: GSockAddrInet instance * @port: new port in host byte order * * **/ static void g_sockaddr_inet_set_port(GSockAddr *s, guint16 port) { g_sockaddr_inet_get_sa(s)->sin_port = htons(port); } static GSockAddrFuncs inet_sockaddr_funcs = { .bind_prepare = g_sockaddr_inet_bind_prepare, NULL, .format = g_sockaddr_inet_format, .get_port = g_sockaddr_inet_get_port, .set_port = g_sockaddr_inet_set_port, }; gboolean g_sockaddr_inet_check(GSockAddr *a) { return a->sa_funcs == &inet_sockaddr_funcs; } /*+ Allocate and initialize an IPv4 socket address. Parameters: ip text representation of an IP address port port number in host byte order Returns: the new instance +*/ GSockAddr * g_sockaddr_inet_new(const gchar *ip, guint16 port) { GSockAddrInet *self = NULL; struct in_addr ina; if (inet_aton(ip, &ina)) { self = g_slice_new0(GSockAddrInet); g_atomic_counter_set(&self->refcnt, 1); self->flags = 0; self->salen = sizeof(struct sockaddr_in); self->sin.sin_family = AF_INET; self->sin.sin_port = htons(port); self->sin.sin_addr = ina; self->sa_funcs = &inet_sockaddr_funcs; } return (GSockAddr *) self; } /*+ Allocate and initialize an IPv4 socket address using libc sockaddr * structure. Parameters: sin the sockaddr_in structure to convert Returns: the allocated instance. +*/ GSockAddr * g_sockaddr_inet_new2(struct sockaddr_in *sin) { GSockAddrInet *self = g_slice_new0(GSockAddrInet); g_atomic_counter_set(&self->refcnt, 1); self->flags = 0; self->salen = sizeof(struct sockaddr_in); self->sin = *sin; self->sa_funcs = &inet_sockaddr_funcs; return (GSockAddr *) self; } #if SYSLOG_NG_ENABLE_IPV6 /* AF_INET6 socket address */ /*+ GSockAddrInet6 is an implementation of the GSockAddr interface, encapsulating an IPv6 host address and port number. +*/ typedef struct _GSockAddrInet6 { GAtomicCounter refcnt; guint32 flags; GSockAddrFuncs *sa_funcs; int salen; struct sockaddr_in6 sin6; } GSockAddrInet6; /*+ format an IPv6 address into human readable form */ static gchar * g_sockaddr_inet6_format(GSockAddr *s, gchar *text, gulong n, gint format) { GSockAddrInet6 *self = (GSockAddrInet6 *) s; char buf[64]; if (format == GSA_FULL) { inet_ntop(AF_INET6, &self->sin6.sin6_addr, buf, sizeof(buf)); g_snprintf(text, n, "AF_INET6([%s]:%d)", buf, htons(self->sin6.sin6_port)); } else if (format == GSA_ADDRESS_ONLY) { inet_ntop(AF_INET6, &self->sin6.sin6_addr, text, n); } else g_assert_not_reached(); return text; } /** * g_sockaddr_inet6_get_port: * @s: GSockAddrInet instance * * This GSockAddrInet specific function returns the port part of the * address. * * Returns: the port in host byte order * **/ static guint16 g_sockaddr_inet6_get_port(GSockAddr *s) { return ntohs(g_sockaddr_inet6_get_sa(s)->sin6_port); } /** * g_sockaddr_inet6_set_port: * @s: GSockAddrInet instance * @port: new port in host byte order * * **/ static void g_sockaddr_inet6_set_port(GSockAddr *s, guint16 port) { g_sockaddr_inet6_get_sa(s)->sin6_port = htons(port); } static GSockAddrFuncs inet6_sockaddr_funcs = { .bind_prepare = g_sockaddr_inet_bind_prepare, .format = g_sockaddr_inet6_format, .get_port = g_sockaddr_inet6_get_port, .set_port = g_sockaddr_inet6_set_port, }; gboolean g_sockaddr_inet6_check(GSockAddr *a) { return a->sa_funcs == &inet6_sockaddr_funcs; } /*+ Allocate and initialize an IPv6 socket address. Parameters: ip text representation of an IP address port port number in host byte order Returns: the new instance +*/ GSockAddr * g_sockaddr_inet6_new(const gchar *ip, guint16 port) { GSockAddrInet6 *addr = NULL; struct in6_addr sin6_addr; if (inet_pton(AF_INET6, ip, &sin6_addr)) { addr = g_slice_new0(GSockAddrInet6); g_atomic_counter_set(&addr->refcnt, 1); addr->flags = 0; addr->salen = sizeof(struct sockaddr_in6); addr->sin6.sin6_family = AF_INET6; addr->sin6.sin6_addr = sin6_addr; addr->sin6.sin6_port = htons(port); addr->sa_funcs = &inet6_sockaddr_funcs; } return (GSockAddr *) addr; } /*+ Allocate and initialize an IPv6 socket address using libc sockaddr * structure. Parameters: sin the sockaddr_in6 structure to convert Returns: the allocated instance. +*/ GSockAddr * g_sockaddr_inet6_new2(struct sockaddr_in6 *sin6) { GSockAddrInet6 *addr = g_slice_new0(GSockAddrInet6); g_atomic_counter_set(&addr->refcnt, 1); addr->flags = 0; addr->salen = sizeof(struct sockaddr_in6); addr->sin6 = *sin6; addr->sa_funcs = &inet6_sockaddr_funcs; return (GSockAddr *) addr; } #endif GSockAddr * g_sockaddr_inet_or_inet6_new(const gchar *name, guint16 port) { GSockAddr *addr = g_sockaddr_inet_new(name, port); #if SYSLOG_NG_ENABLE_IPV6 if (!addr) addr = g_sockaddr_inet6_new(name, port); #endif return addr; } /* AF_UNIX socket address */ /*+ The GSockAddrUnix class is an implementation of the GSockAddr interface encapsulating AF_UNIX domain socket names. +*/ typedef struct _GSockAddrUnix { GAtomicCounter refcnt; guint32 flags; GSockAddrFuncs *sa_funcs; int salen; struct sockaddr_un saun; } GSockAddrUnix; static GIOStatus g_sockaddr_unix_bind_prepare(int sock, GSockAddr *addr); static GIOStatus g_sockaddr_unix_bind(int sock, GSockAddr *addr); static gchar *g_sockaddr_unix_format(GSockAddr *addr, gchar *text, gulong n, gint format); static GSockAddrFuncs unix_sockaddr_funcs = { .bind_prepare = g_sockaddr_unix_bind_prepare, .bind = g_sockaddr_unix_bind, .format = g_sockaddr_unix_format }; /* anonymous if name == NULL */ /*+ Allocate and initialize a GSockAddrUnix instance. Parameters: name socket filename Returns: the new instance +*/ GSockAddr * g_sockaddr_unix_new(const gchar *name) { GSockAddrUnix *addr = g_slice_new0(GSockAddrUnix); g_atomic_counter_set(&addr->refcnt, 1); addr->flags = 0; addr->sa_funcs = &unix_sockaddr_funcs; addr->saun.sun_family = AF_UNIX; if (name) { strncpy(addr->saun.sun_path, name, sizeof(addr->saun.sun_path) - 1); addr->saun.sun_path[sizeof(addr->saun.sun_path) - 1] = 0; addr->salen = SUN_LEN(&(addr->saun)); } else { addr->saun.sun_path[0] = 0; addr->salen = 2; } return (GSockAddr *) addr; } /*+ Allocate and initialize a GSockAddrUnix instance, using libc sockaddr_un structure. Parameters: saun sockaddr_un structure to convert sunlen size of saun Returns: the new instance +*/ GSockAddr * g_sockaddr_unix_new2(struct sockaddr_un *saun, int sunlen) { GSockAddrUnix *addr = g_slice_new0(GSockAddrUnix); g_atomic_counter_set(&addr->refcnt, 1); addr->flags = 0; addr->sa_funcs = &unix_sockaddr_funcs; addr->salen = sunlen; addr->saun = *saun; return (GSockAddr *) addr; } /*+ private function to prepare a bind on AF_UNIX sockets, e.g. unlink the socket if it exists and is a socket. +*/ static GIOStatus g_sockaddr_unix_bind_prepare(int sock, GSockAddr *addr) { GSockAddrUnix *unix_addr = (GSockAddrUnix *) addr; struct stat st; if (unix_addr->saun.sun_path[0] == 0) return G_IO_STATUS_NORMAL; if (stat(unix_addr->saun.sun_path, &st) == -1 || !S_ISSOCK(st.st_mode)) return G_IO_STATUS_NORMAL; unlink(unix_addr->saun.sun_path); return G_IO_STATUS_NORMAL; } /** * Virtual bind callback for UNIX domain sockets. Avoids binding if the * length of the UNIX domain socket filename is zero. **/ static GIOStatus g_sockaddr_unix_bind(int sock, GSockAddr *addr) { GSockAddrUnix *unix_addr = (GSockAddrUnix *) addr; if (unix_addr->saun.sun_path[0] == 0) return G_IO_STATUS_NORMAL; if (bind(sock, &addr->sa, addr->salen) < 0) { return G_IO_STATUS_ERROR; } return G_IO_STATUS_NORMAL; } /*+ Convert a GSockAddrUnix into human readable form. +*/ gchar * g_sockaddr_unix_format(GSockAddr *addr, gchar *text, gulong n, gint format) { GSockAddrUnix *unix_addr = (GSockAddrUnix *) addr; if (format == GSA_FULL) { g_snprintf(text, n, "AF_UNIX(%s)", unix_addr->salen > sizeof(unix_addr->saun.sun_family) && unix_addr->saun.sun_path[0] ? unix_addr->saun.sun_path : "anonymous"); } else if (format == GSA_ADDRESS_ONLY) { g_snprintf(text, n, "%s", unix_addr->salen > sizeof(unix_addr->saun.sun_family) && unix_addr->saun.sun_path[0] ? unix_addr->saun.sun_path : "anonymous"); } return text; } gsize g_sockaddr_len(GSockAddr *a) { gsize len; if (!a) return 0; if (a->sa_funcs == &inet_sockaddr_funcs) len = sizeof(GSockAddrInet); #if SYSLOG_NG_ENABLE_IPV6 else if (a->sa_funcs == &inet6_sockaddr_funcs) len = sizeof(GSockAddrInet6); #endif else if (a->sa_funcs == &unix_sockaddr_funcs) len = sizeof(GSockAddrUnix); else g_assert_not_reached(); return len; } syslog-ng-syslog-ng-4.4.0/lib/gsockaddr.h000066400000000000000000000106141450431004300202350ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef G_SOCKADDR_H_INCLUDED #define G_SOCKADDR_H_INCLUDED #include "syslog-ng.h" #include "atomic.h" #include #include #include #include /* sockaddr public interface */ #define MAX_SOCKADDR_STRING 64 #define GSA_FULL 0 #define GSA_ADDRESS_ONLY 1 typedef struct _GSockAddrFuncs GSockAddrFuncs; typedef struct _GSockAddr { GAtomicCounter refcnt; guint32 flags; GSockAddrFuncs *sa_funcs; int salen; struct sockaddr sa; } GSockAddr; struct _GSockAddrFuncs { GIOStatus (*bind_prepare)(gint sock, GSockAddr *addr); GIOStatus (*bind)(int sock, GSockAddr *addr); gchar *(*format)(GSockAddr *addr, gchar *text, gulong n, gint format); guint16 (*get_port) (GSockAddr *addr); void (*set_port) (GSockAddr *addr, guint16 port); }; gchar *g_sockaddr_format(GSockAddr *a, gchar *text, gulong n, gint format); guint16 g_sockaddr_get_port(GSockAddr *a); void g_sockaddr_set_port(GSockAddr *a, guint16 port); guint8 *g_sockaddr_get_address(GSockAddr *self, guint8 *buffer, socklen_t buffer_size); gsize g_sockaddr_len(GSockAddr *a); GSockAddr *g_sockaddr_new(struct sockaddr *sa, int salen); GSockAddr *g_sockaddr_ref(GSockAddr *a); void g_sockaddr_unref(GSockAddr *a); static inline struct sockaddr * g_sockaddr_get_sa(GSockAddr *self) { return &self->sa; } gboolean g_sockaddr_inet_check(GSockAddr *a); GSockAddr *g_sockaddr_inet_new(const gchar *ip, guint16 port); GSockAddr *g_sockaddr_inet_new2(struct sockaddr_in *sin); static inline struct sockaddr_in * g_sockaddr_inet_get_sa(GSockAddr *s) { g_assert(g_sockaddr_inet_check(s)); return (struct sockaddr_in *) g_sockaddr_get_sa(s); } /** * g_sockaddr_inet_get_address: * @s: GSockAddrInet instance * * This GSockAddrInet specific function returns the address part of the * address. **/ static inline struct in_addr g_sockaddr_inet_get_address(GSockAddr *s) { return g_sockaddr_inet_get_sa(s)->sin_addr; } /** * g_sockaddr_inet_set_address: * @s: GSockAddrInet instance * @addr: new address * * This GSockAddrInet specific function returns the address part of the * address. **/ static inline void g_sockaddr_inet_set_address(GSockAddr *s, struct in_addr addr) { g_sockaddr_inet_get_sa(s)->sin_addr = addr; } #if SYSLOG_NG_ENABLE_IPV6 gboolean g_sockaddr_inet6_check(GSockAddr *a); GSockAddr *g_sockaddr_inet6_new(const gchar *ip, guint16 port); GSockAddr *g_sockaddr_inet6_new2(struct sockaddr_in6 *sin6); static inline struct sockaddr_in6 * g_sockaddr_inet6_get_sa(GSockAddr *s) { g_assert(g_sockaddr_inet6_check(s)); return (struct sockaddr_in6 *) g_sockaddr_get_sa(s); } /** * g_sockaddr_inet6_get_address: * @s: GSockAddrInet instance * * This GSockAddrInet specific function returns the address part of the * address. **/ static inline struct in6_addr * g_sockaddr_inet6_get_address(GSockAddr *s) { return &g_sockaddr_inet6_get_sa(s)->sin6_addr; } /** * g_sockaddr_inet6_set_address: * @s: GSockAddrInet6 instance * @addr: new address * * This GSockAddrInet specific function sets the address part of the * address. **/ static inline void g_sockaddr_inet6_set_address(GSockAddr *s, struct in6_addr *addr) { g_sockaddr_inet6_get_sa(s)->sin6_addr = *addr; } #endif GSockAddr *g_sockaddr_inet_or_inet6_new(const gchar *name, guint16 port); GSockAddr *g_sockaddr_unix_new(const gchar *name); GSockAddr *g_sockaddr_unix_new2(struct sockaddr_un *s_un, int sunlen); #endif syslog-ng-syslog-ng-4.4.0/lib/gsocket.c000066400000000000000000000103761450431004300177330ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "gsocket.h" #include #include /** * g_inet_ntoa: * @buf: store result in this buffer * @bufsize: the available space in buf * @a: address to convert. * * Thread friendly version of inet_ntoa(), converts an IP address to * human readable form. Returns: the address of buf **/ gchar * g_inet_ntoa(char *buf, size_t bufsize, struct in_addr a) { unsigned int ip = ntohl(a.s_addr); g_snprintf(buf, bufsize, "%d.%d.%d.%d", (ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16, (ip & 0x0000ff00) >> 8, (ip & 0x000000ff)); return buf; } gint g_inet_aton(const char *buf, struct in_addr *a) { return inet_aton(buf, a); } /** * g_bind: * @fd: fd to bind * @addr: address to bind to * * A thin interface around bind() using a GSockAddr structure for * socket address. It enables the NET_BIND_SERVICE capability (should be * in the permitted set. **/ GIOStatus g_bind(int fd, GSockAddr *addr) { GIOStatus rc; if (addr->sa_funcs && addr->sa_funcs->bind_prepare) addr->sa_funcs->bind_prepare(fd, addr); if (addr->sa_funcs && addr->sa_funcs->bind) rc = addr->sa_funcs->bind(fd, addr); else { if (addr && bind(fd, &addr->sa, addr->salen) < 0) { return G_IO_STATUS_ERROR; } rc = G_IO_STATUS_NORMAL; } return rc; } /** * g_accept: * @fd: accept connection on this socket * @newfd: fd of the accepted connection * @addr: store the address of the client here * * Accept a connection on the given fd, returning the newfd and the * address of the client in a Zorp SockAddr structure. * * Returns: glib style I/O error **/ GIOStatus g_accept(int fd, int *newfd, GSockAddr **addr) { char sabuf[1024]; socklen_t salen = sizeof(sabuf); do { *newfd = accept(fd, (struct sockaddr *) sabuf, &salen); } while (*newfd == -1 && errno == EINTR); if (*newfd != -1) { *addr = g_sockaddr_new((struct sockaddr *) sabuf, salen); } else if (errno == EAGAIN) { return G_IO_STATUS_AGAIN; } else { return G_IO_STATUS_ERROR; } return G_IO_STATUS_NORMAL; } /** * g_connect: * @fd: socket to connect * @remote: remote address * * Connect a socket using Zorp style GSockAddr structure. * * Returns: glib style I/O error **/ GIOStatus g_connect(int fd, GSockAddr *remote) { int rc; do { rc = connect(fd, &remote->sa, remote->salen); } while (rc == -1 && errno == EINTR); if (rc == -1) { if (errno == EAGAIN) return G_IO_STATUS_AGAIN; else return G_IO_STATUS_ERROR; } else { return G_IO_STATUS_NORMAL; } } GSockAddr * g_socket_get_peer_name(gint fd) { GSockAddr *result = NULL; struct sockaddr_storage addr; socklen_t len = sizeof(addr); if (getpeername(fd, (struct sockaddr *)&addr, &len) == 0) { result = g_sockaddr_new((struct sockaddr *)&addr, len); } return result; } GSockAddr * g_socket_get_local_name(gint fd) { GSockAddr *result = NULL; struct sockaddr_storage addr; socklen_t len = sizeof(addr); if (getsockname(fd, (struct sockaddr *)&addr, &len) == 0) { result = g_sockaddr_new((struct sockaddr *)&addr, len); } return result; } syslog-ng-syslog-ng-4.4.0/lib/gsocket.h000066400000000000000000000027021450431004300177320ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef G_SOCKET_H_INCLUDED #define G_SOCKET_H_INCLUDED #include "syslog-ng.h" #include "gsockaddr.h" GIOStatus g_bind(int fd, GSockAddr *addr); GIOStatus g_accept(int fd, int *newfd, GSockAddr **addr); GIOStatus g_connect(int fd, GSockAddr *remote); gchar *g_inet_ntoa(char *buf, size_t bufsize, struct in_addr a); gint g_inet_aton(const char *buf, struct in_addr *a); GSockAddr *g_socket_get_peer_name(gint fd); GSockAddr *g_socket_get_local_name(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/healthcheck/000077500000000000000000000000001450431004300203645ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/healthcheck/CMakeLists.txt000066400000000000000000000005011450431004300231200ustar00rootroot00000000000000set(HEALTHCHECK_HEADERS healthcheck/healthcheck.h healthcheck/healthcheck-control.h healthcheck/healthcheck-stats.h healthcheck/stopwatch.h PARENT_SCOPE) set(HEALTHCHECK_SOURCES healthcheck/healthcheck.c healthcheck/healthcheck-control.c healthcheck/healthcheck-stats.c PARENT_SCOPE) syslog-ng-syslog-ng-4.4.0/lib/healthcheck/Makefile.am000066400000000000000000000006341450431004300224230ustar00rootroot00000000000000healthcheckincludedir = ${pkgincludedir}/healthcheck EXTRA_DIST += \ lib/healthcheck/CMakeLists.txt healthcheckinclude_HEADERS = \ lib/healthcheck/healthcheck.h \ lib/healthcheck/healthcheck-control.h \ lib/healthcheck/healthcheck-stats.h \ lib/healthcheck/stopwatch.h healthcheck_sources = \ lib/healthcheck/healthcheck.c \ lib/healthcheck/healthcheck-control.c \ lib/healthcheck/healthcheck-stats.c syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck-control.c000066400000000000000000000067141450431004300244610ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "healthcheck-control.h" #include "healthcheck.h" #include "control/control.h" #include "control/control-connection.h" #include "control/control-commands.h" #include "stats/stats-prometheus.h" #include "afinter.h" static inline void _append_internal_src_queue_metrics(AFInterMetrics metrics, GString *reply) { gchar double_buf[G_ASCII_DTOSTR_BUF_SIZE]; gdouble queued = (gint) stats_counter_get(metrics.queued); gsize queue_capacity = stats_counter_get(metrics.queue_capacity); gdouble internal_queue_usage = 1; if (queue_capacity != 0) internal_queue_usage = queued / queue_capacity; g_string_append_printf(reply, PROMETHEUS_METRIC_PREFIX "internal_events_queue_usage_ratio %s\n", g_ascii_dtostr(double_buf, G_N_ELEMENTS(double_buf), internal_queue_usage)); } static void _send_healthcheck_reply(HealthCheckResult result, gpointer c) { ControlConnection *cc = (ControlConnection *) c; gchar double_buf[G_ASCII_DTOSTR_BUF_SIZE]; gdouble io_worker_latency = result.io_worker_latency / 1e9; gdouble mainloop_io_worker_roundtrip_latency = result.mainloop_io_worker_roundtrip_latency / 1e9; GString *reply = g_string_new("OK "); g_string_append_printf(reply, PROMETHEUS_METRIC_PREFIX "io_worker_latency_seconds %s\n", g_ascii_dtostr(double_buf, G_N_ELEMENTS(double_buf), io_worker_latency)); g_string_append_printf(reply, PROMETHEUS_METRIC_PREFIX "mainloop_io_worker_roundtrip_latency_seconds %s\n", g_ascii_dtostr(double_buf, G_N_ELEMENTS(double_buf), mainloop_io_worker_roundtrip_latency)); AFInterMetrics internal_src_metrics = afinter_get_metrics(); if (internal_src_metrics.queued) _append_internal_src_queue_metrics(internal_src_metrics, reply); control_connection_send_reply(cc, reply); control_connection_unref(cc); } static void control_connection_healthcheck(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { HealthCheck *hc = healthcheck_new(); if (!healthcheck_run(hc, _send_healthcheck_reply, control_connection_ref(cc))) { GString *reply = g_string_new("FAIL Another healthcheck command is already running"); control_connection_send_reply(cc, reply); control_connection_unref(cc); } healthcheck_unref(hc); } void healthcheck_register_control_commands(void) { control_register_command("HEALTHCHECK", control_connection_healthcheck, NULL, FALSE); } syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck-control.h000066400000000000000000000021571450431004300244630ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HEALTHCHECK_CONTROL_H #define HEALTHCHECK_CONTROL_H #include "syslog-ng.h" void healthcheck_register_control_commands(void); #endif syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck-stats.c000066400000000000000000000121151450431004300241270ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "healthcheck-stats.h" #include "healthcheck.h" #include "stats/stats-cluster-single.h" #include "stats/stats-registry.h" #include "stats/stats-counter.h" #include "apphook.h" #include "cfg.h" #include "mainloop.h" #include "timeutils/misc.h" #include typedef struct _HealthCheckStats { HealthCheckStatsOptions options; struct iv_timer timer; StatsCounterItem *io_worker_latency; StatsCounterItem *mainloop_io_worker_roundtrip_latency; } HealthCheckStats; static HealthCheckStats healthcheck_stats; static void healthcheck_stats_update(HealthCheckResult result, gpointer c) { HealthCheckStats *self = (HealthCheckStats *) c; stats_counter_set(self->io_worker_latency, result.io_worker_latency); stats_counter_set(self->mainloop_io_worker_roundtrip_latency, result.mainloop_io_worker_roundtrip_latency); } static void healthcheck_stats_timer_start(HealthCheckStats *self) { iv_validate_now(); self->timer.expires = iv_now; timespec_add_msec(&self->timer.expires, self->options.freq * 1000); iv_timer_register(&self->timer); } static void healthcheck_stats_timer_stop(HealthCheckStats *self) { if (self->timer.handler && iv_timer_registered(&self->timer)) iv_timer_unregister(&self->timer); } static void healthcheck_stats_run(gpointer c) { HealthCheckStats *self = (HealthCheckStats *) c; HealthCheck *hc = healthcheck_new(); healthcheck_run(hc, healthcheck_stats_update, self); healthcheck_unref(hc); if (self->options.freq > 0) healthcheck_stats_timer_start(self); } static void _register_counters(HealthCheckStats *self) { StatsClusterKey sc_key_io_worker_latency, sc_key_mainloop_iow_rt_latency; stats_cluster_single_key_set(&sc_key_io_worker_latency, "io_worker_latency_seconds", NULL, 0); stats_cluster_single_key_add_unit(&sc_key_io_worker_latency, SCU_NANOSECONDS); stats_cluster_single_key_set(&sc_key_mainloop_iow_rt_latency, "mainloop_io_worker_roundtrip_latency_seconds", NULL, 0); stats_cluster_single_key_add_unit(&sc_key_mainloop_iow_rt_latency, SCU_NANOSECONDS); stats_lock(); stats_register_counter(1, &sc_key_io_worker_latency, SC_TYPE_SINGLE_VALUE, &self->io_worker_latency); stats_register_counter(1, &sc_key_mainloop_iow_rt_latency, SC_TYPE_SINGLE_VALUE, &self->mainloop_io_worker_roundtrip_latency); stats_unlock(); } static void _unregister_counters(HealthCheckStats *self) { StatsClusterKey sc_key_io_worker_latency, sc_key_mainloop_iow_rt_latency; stats_cluster_single_key_set(&sc_key_io_worker_latency, "io_worker_latency_seconds", NULL, 0); stats_cluster_single_key_set(&sc_key_mainloop_iow_rt_latency, "mainloop_io_worker_roundtrip_latency_seconds", NULL, 0); stats_lock(); stats_unregister_counter(&sc_key_io_worker_latency, SC_TYPE_SINGLE_VALUE, &self->io_worker_latency); stats_unregister_counter(&sc_key_mainloop_iow_rt_latency, SC_TYPE_SINGLE_VALUE, &self->mainloop_io_worker_roundtrip_latency); stats_unlock(); } void healthcheck_stats_init(HealthCheckStatsOptions *options) { healthcheck_stats.options = *options; _register_counters(&healthcheck_stats); healthcheck_stats_timer_stop(&healthcheck_stats); IV_TIMER_INIT(&healthcheck_stats.timer); healthcheck_stats.timer.handler = healthcheck_stats_run; healthcheck_stats.timer.cookie = &healthcheck_stats; if (healthcheck_stats.mainloop_io_worker_roundtrip_latency) healthcheck_stats_run(&healthcheck_stats); } void healthcheck_stats_deinit(void) { healthcheck_stats_timer_stop(&healthcheck_stats); _unregister_counters(&healthcheck_stats); } static inline void _init(gint type, gpointer c) { MainLoop *main_loop = main_loop_get_instance(); GlobalConfig *cfg = main_loop_get_current_config(main_loop); if (!cfg) return; healthcheck_stats_init(&cfg->healthcheck_options); } static inline void _deinit(gint type, gpointer c) { healthcheck_stats_deinit(); } void healthcheck_stats_global_init(void) { register_application_hook(AH_CONFIG_CHANGED, _init, NULL, AHM_RUN_REPEAT); register_application_hook(AH_CONFIG_STOPPED, _deinit, NULL, AHM_RUN_REPEAT); } syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck-stats.h000066400000000000000000000026171450431004300241420ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HEALTHCHECK_STATS_H #define HEALTHCHECK_STATS_H #include "syslog-ng.h" typedef struct _HealthCheckStatsOptions { gint freq; } HealthCheckStatsOptions; static inline void healthcheck_stats_options_defaults(HealthCheckStatsOptions *options) { options->freq = 300; } void healthcheck_stats_init(HealthCheckStatsOptions *options); void healthcheck_stats_deinit(void); void healthcheck_stats_global_init(void); #endif syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck.c000066400000000000000000000077351450431004300230070ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "healthcheck.h" #include "atomic.h" #include "mainloop-io-worker.h" #include "stopwatch.h" struct _HealthCheck { GAtomicCounter ref_cnt; gboolean running; HealthCheckResult result; HealthCheckCompletionCB completion; gpointer user_data; struct { MainLoopIOWorkerJob job; Stopwatch stopwatch; } io_worker_latency; }; static void healthcheck_incomplete(HealthCheck *self) { self->running = FALSE; self->completion = NULL; self->user_data = NULL; healthcheck_unref(self); } static void healthcheck_complete(HealthCheck *self) { self->running = FALSE; self->completion(self->result, self->user_data); self->completion = NULL; self->user_data = NULL; healthcheck_unref(self); } static inline gboolean _start_io_worker_latency(HealthCheck *self) { stopwatch_start(&self->io_worker_latency.stopwatch); if (!main_loop_io_worker_job_submit(&self->io_worker_latency.job, NULL)) { /* currently, the IO worker check is our only health check */ healthcheck_incomplete(self); return FALSE; } return TRUE; } static gboolean _start_health_checks(HealthCheck *self) { g_assert(!self->running); self->running = TRUE; return _start_io_worker_latency(self); } gboolean healthcheck_run(HealthCheck *self, HealthCheckCompletionCB completion, gpointer user_data) { if (self->running || !completion) return FALSE; self->completion = completion; self->user_data = user_data; self->result = (HealthCheckResult) { 0 }; healthcheck_ref(self); return _start_health_checks(self); } static void _io_worker_latency(gpointer s, gpointer arg) { HealthCheck *self = (HealthCheck *) s; self->result.io_worker_latency = stopwatch_get_elapsed_nsec(&self->io_worker_latency.stopwatch); } static void _io_worker_latency_finished(gpointer s, gpointer arg) { HealthCheck *self = (HealthCheck *) s; self->result.mainloop_io_worker_roundtrip_latency = stopwatch_get_elapsed_nsec(&self->io_worker_latency.stopwatch); /* currently, the IO worker check is our only health check */ healthcheck_complete(self); } static void healthcheck_free(HealthCheck *self) { g_assert(!self->running); g_free(self); } HealthCheck * healthcheck_ref(HealthCheck *self) { if (!self) return NULL; g_atomic_counter_inc(&self->ref_cnt); return self; } void healthcheck_unref(HealthCheck *self) { if (!self) return; if (g_atomic_counter_dec_and_test(&self->ref_cnt)) healthcheck_free(self); } HealthCheck * healthcheck_new(void) { HealthCheck *self = g_new0(HealthCheck, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->running = FALSE; main_loop_io_worker_job_init(&self->io_worker_latency.job); self->io_worker_latency.job.user_data = self; self->io_worker_latency.job.work = _io_worker_latency; self->io_worker_latency.job.completion = _io_worker_latency_finished; self->io_worker_latency.job.engage = (void (*)(gpointer)) healthcheck_ref; self->io_worker_latency.job.release = (void (*)(gpointer)) healthcheck_unref; return self; } syslog-ng-syslog-ng-4.4.0/lib/healthcheck/healthcheck.h000066400000000000000000000030121450431004300227740ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HEALTHCHECK_H #define HEALTHCHECK_H #include "syslog-ng.h" typedef struct _HealthCheck HealthCheck; typedef struct _HealthCheckResult { guint64 io_worker_latency; guint64 mainloop_io_worker_roundtrip_latency; } HealthCheckResult; typedef void(*HealthCheckCompletionCB)(HealthCheckResult, gpointer); HealthCheck *healthcheck_new(void); HealthCheck *healthcheck_ref(HealthCheck *self); void healthcheck_unref(HealthCheck *self); gboolean healthcheck_run(HealthCheck *self, HealthCheckCompletionCB completion, gpointer user_data); #endif syslog-ng-syslog-ng-4.4.0/lib/healthcheck/stopwatch.h000066400000000000000000000030101450431004300225430ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STOPWATCH_H #define STOPWATCH_H #include "syslog-ng.h" #include "compat/time.h" typedef struct _Stopwatch { struct timespec start_time; } Stopwatch; static inline void stopwatch_start(Stopwatch *self) { clock_gettime(CLOCK_MONOTONIC, &self->start_time); } static inline guint64 stopwatch_get_elapsed_nsec(Stopwatch *self) { struct timespec stop_time; clock_gettime(CLOCK_MONOTONIC, &stop_time); return (stop_time.tv_sec - self->start_time.tv_sec) * 1000000000 + (stop_time.tv_nsec - self->start_time.tv_nsec); } #endif syslog-ng-syslog-ng-4.4.0/lib/host-id.c000066400000000000000000000055351450431004300176440ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "host-id.h" #include "str-format.h" #include "messages.h" #include guint32 global_host_id = 0; static guint32 _create_host_id(void) { union { unsigned char _raw[sizeof(guint32)]; guint32 id; } host_id; RAND_bytes(host_id._raw, sizeof(host_id._raw)); return host_id.id; } static gboolean _load_host_id_from_legacy_persist_entry(PersistState *state, guint32 *host_id) { gsize size; guint8 version; PersistEntryHandle handle = persist_state_lookup_entry(state, HOST_ID_LEGACY_PERSIST_KEY, &size, &version); if (!handle) return FALSE; guint32 *mapped_hostid = persist_state_map_entry(state, handle); *host_id = *mapped_hostid; persist_state_unmap_entry(state, handle); return TRUE; } gboolean host_id_init(PersistState *state) { gsize size; guint8 version; PersistEntryHandle handle; HostIdState *host_id_state; gboolean host_id_found = TRUE; guint32 legacy_hostid = 0; handle = persist_state_lookup_entry(state, HOST_ID_PERSIST_KEY, &size, &version); if (handle == 0) { host_id_found = FALSE; handle = persist_state_alloc_entry(state, HOST_ID_PERSIST_KEY, sizeof(HostIdState)); if (handle == 0) { msg_error("host-id: could not allocate persist state"); return FALSE; } } host_id_state = persist_state_map_entry(state, handle); if (!host_id_found) { if (_load_host_id_from_legacy_persist_entry(state, &legacy_hostid)) { host_id_state->host_id = legacy_hostid; } else { host_id_state->host_id = _create_host_id(); } } global_host_id = host_id_state->host_id; persist_state_unmap_entry(state, handle); return TRUE; } guint32 host_id_get(void) { return global_host_id; } void host_id_append_formatted_id(GString *str, guint32 id) { format_uint32_padded(str, 8, '0', 16, id); } syslog-ng-syslog-ng-4.4.0/lib/host-id.h000066400000000000000000000026371450431004300176510ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HOST_ID_H #define HOST_ID_H #include "persist-state.h" #include "persistable-state-header.h" #define HOST_ID_PERSIST_KEY "host_id" #define HOST_ID_LEGACY_PERSIST_KEY "hostid" typedef struct _HostIdState { PersistableStateHeader header; guint32 host_id; } HostIdState; gboolean host_id_init(PersistState *state); void host_id_deinit(void); guint32 host_id_get(void); void host_id_append_formatted_id(GString *str, guint32 id); #endif syslog-ng-syslog-ng-4.4.0/lib/host-resolve.c000066400000000000000000000320121450431004300207150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "host-resolve.h" #include "hostname.h" #include "dnscache.h" #include "messages.h" #include "cfg.h" #include "tls-support.h" #include "compat/socket.h" #include "apphook.h" #include #include #include #include #include #ifndef AI_V4MAPPED #define AI_V4MAPPED 0 #endif #if !defined(SYSLOG_NG_HAVE_GETADDRINFO) || !defined(SYSLOG_NG_HAVE_GETNAMEINFO) G_LOCK_DEFINE_STATIC(resolv_lock); #endif TLS_BLOCK_START { gchar hostname_buffer[256]; } TLS_BLOCK_END; #define hostname_buffer __tls_deref(hostname_buffer) static void normalize_hostname(gchar *result, gsize result_size, const gchar *hostname) { gsize i; for (i = 0; hostname[i] && i < (result_size - 1); i++) { result[i] = g_ascii_tolower(hostname[i]); } result[i] = '\0'; /* the closing \0 is not copied by the previous loop */ } static const gchar * bounce_to_hostname_buffer(const gchar *hname) { if (hname != hostname_buffer) g_strlcpy(hostname_buffer, hname, sizeof(hostname_buffer)); return hostname_buffer; } static const gchar * hostname_apply_options(gssize result_len_orig, gsize *result_len, const gchar *hname, const HostResolveOptions *host_resolve_options) { if (host_resolve_options->normalize_hostnames) { normalize_hostname(hostname_buffer, sizeof(hostname_buffer), hname); hname = hostname_buffer; } if (result_len_orig >= 0) *result_len = result_len_orig; else *result_len = strlen(hname); return hname; } static const gchar * hostname_apply_options_fqdn(gssize result_len_orig, gsize *result_len, const gchar *hname, gboolean positive, const HostResolveOptions *host_resolve_options) { if (positive && !host_resolve_options->use_fqdn) { /* we only truncate hostnames if they were positive * matches (e.g. real hostnames and not IP * addresses) */ hname = bounce_to_hostname_buffer(hname); convert_hostname_to_short_hostname(hostname_buffer, sizeof(hostname_buffer)); result_len_orig = -1; } return hostname_apply_options(result_len_orig, result_len, hname, host_resolve_options); } /**************************************************************************** * Convert a GSockAddr instance to a hostname ****************************************************************************/ static gboolean is_wildcard_hostname(const gchar *name) { return !name || name[0] == 0; } static gboolean resolve_wildcard_hostname_to_sockaddr(GSockAddr **addr, gint family, const gchar *name) { struct sockaddr_storage ss; /* return the wildcard address that can be used as a bind address */ memset(&ss, 0, sizeof(ss)); ss.ss_family = family; switch (family) { case AF_INET: *addr = g_sockaddr_inet_new2(((struct sockaddr_in *) &ss)); break; #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: *addr = g_sockaddr_inet6_new2((struct sockaddr_in6 *) &ss); break; #endif default: g_assert_not_reached(); break; } return TRUE; } #ifdef SYSLOG_NG_HAVE_GETADDRINFO static gboolean _getaddrinfo_to_sockaddr(GSockAddr **addr, gint family, const gchar *name, gint ai_flags, gint *result) { struct addrinfo hints; struct addrinfo *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = 0; hints.ai_protocol = 0; hints.ai_flags = ai_flags; *result = getaddrinfo(name, NULL, &hints, &res); if (*result == 0) { /* we only use the first entry in the returned list */ switch (family) { case AF_INET: *addr = g_sockaddr_inet_new2(((struct sockaddr_in *) res->ai_addr)); break; #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: *addr = g_sockaddr_inet6_new2((struct sockaddr_in6 *) res->ai_addr); break; #endif default: g_assert_not_reached(); break; } freeaddrinfo(res); return TRUE; } return FALSE; } static gboolean resolve_hostname_to_sockaddr_using_getaddrinfo(GSockAddr **addr, gint family, const gchar *name) { gint result; if (!_getaddrinfo_to_sockaddr(addr, family, name, AI_NUMERICHOST, &result) && !_getaddrinfo_to_sockaddr(addr, family, name, AI_V4MAPPED | AI_ADDRCONFIG, &result) && !_getaddrinfo_to_sockaddr(addr, family, name, AI_V4MAPPED, &result)) { msg_error("Error resolving hostname with getaddrinfo()", evt_tag_str("host", name), evt_tag_int("error", result), evt_tag_str("error_str", gai_strerror(result))); return FALSE; } return TRUE; } #else static gboolean resolve_hostname_to_sockaddr_using_gethostbyname(GSockAddr **addr, gint family, const gchar *name) { struct hostent *he; G_LOCK(resolv_lock); he = gethostbyname(name); if (he) { switch (family) { case AF_INET: { struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr = *(struct in_addr *) he->h_addr; sin.sin_port = htons(0); *addr = g_sockaddr_inet_new2(&sin); break; } default: g_assert_not_reached(); break; } } else { msg_error("Error resolving hostname with gethostbyname()", evt_tag_str("host", name)); } G_UNLOCK(resolv_lock); return he != NULL; } #endif static inline void _attempt_to_invalidate_iv_now(void) { if (iv_inited()) iv_invalidate_now(); } gboolean resolve_hostname_to_sockaddr(GSockAddr **addr, gint family, const gchar *name) { gboolean result; if (is_wildcard_hostname(name)) return resolve_wildcard_hostname_to_sockaddr(addr, family, name); #ifdef SYSLOG_NG_HAVE_GETADDRINFO result = resolve_hostname_to_sockaddr_using_getaddrinfo(addr, family, name); #else result = resolve_hostname_to_sockaddr_using_gethostbyname(addr, family, name); #endif _attempt_to_invalidate_iv_now(); return result; } /**************************************************************************** * Convert a hostname to a GSockAddr instance ****************************************************************************/ static gboolean is_sockaddr_local(GSockAddr *saddr) { return !saddr || (saddr->sa.sa_family != AF_INET && saddr->sa.sa_family != AF_INET6); } static const gchar * resolve_sockaddr_to_local_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options) { const gchar *hname; if (host_resolve_options->use_fqdn) hname = get_local_hostname_fqdn(); else hname = get_local_hostname_short(); return hostname_apply_options(-1, result_len, hname, host_resolve_options); } #ifdef SYSLOG_NG_HAVE_GETNAMEINFO static const gchar * resolve_address_using_getnameinfo(GSockAddr *saddr, gchar *buf, gsize buf_len) { if (getnameinfo(&saddr->sa, saddr->salen, buf, buf_len, NULL, 0, NI_NAMEREQD) == 0) return buf; return NULL; } #else static const gchar * resolve_address_using_gethostbyaddr(GSockAddr *saddr, gchar *buf, gsize buf_len) { const gchar *result = NULL; struct hostent *hp; void *addr; socklen_t addr_len G_GNUC_UNUSED; g_assert(saddr->sa.sa_family == AF_INET); addr = &((struct sockaddr_in *) &saddr->sa)->sin_addr; addr_len = sizeof(struct in_addr); G_LOCK(resolv_lock); hp = gethostbyaddr(addr, addr_len, saddr->sa.sa_family); if (hp && hp->h_name) { strncpy(buf, hp->h_name, buf_len); buf[buf_len - 1] = 0; result = buf; } G_UNLOCK(resolv_lock); return result; } #endif static void * sockaddr_to_dnscache_key(GSockAddr *saddr) { if (saddr->sa.sa_family == AF_INET) return &((struct sockaddr_in *) &saddr->sa)->sin_addr; #if SYSLOG_NG_ENABLE_IPV6 else if (saddr->sa.sa_family == AF_INET6) return &((struct sockaddr_in6 *) &saddr->sa)->sin6_addr; #endif else { msg_warning("Socket address is neither IPv4 nor IPv6", evt_tag_int("sa_family", saddr->sa.sa_family)); return NULL; } } static const gchar * resolve_sockaddr_to_inet_or_inet6_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options) { const gchar *hname; gsize hname_len; gboolean positive; void *dnscache_key; dnscache_key = sockaddr_to_dnscache_key(saddr); hname = NULL; positive = FALSE; if (host_resolve_options->use_dns_cache) { if (dns_caching_lookup(saddr->sa.sa_family, dnscache_key, (const gchar **) &hname, &hname_len, &positive)) return hostname_apply_options_fqdn(hname_len, result_len, hname, positive, host_resolve_options); } if (!hname && host_resolve_options->use_dns && host_resolve_options->use_dns != 2) { #ifdef SYSLOG_NG_HAVE_GETNAMEINFO hname = resolve_address_using_getnameinfo(saddr, hostname_buffer, sizeof(hostname_buffer)); #else hname = resolve_address_using_gethostbyaddr(saddr, hostname_buffer, sizeof(hostname_buffer)); #endif positive = (hname != NULL); } if (!hname) { hname = g_sockaddr_format(saddr, hostname_buffer, sizeof(hostname_buffer), GSA_ADDRESS_ONLY); positive = FALSE; } if (host_resolve_options->use_dns_cache) dns_caching_store(saddr->sa.sa_family, dnscache_key, hname, positive); return hostname_apply_options_fqdn(-1, result_len, hname, positive, host_resolve_options); } const gchar * resolve_sockaddr_to_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options) { const gchar *res; if (is_sockaddr_local(saddr)) res = resolve_sockaddr_to_local_hostname(result_len, saddr, host_resolve_options); else res = resolve_sockaddr_to_inet_or_inet6_hostname(result_len, saddr, host_resolve_options); _attempt_to_invalidate_iv_now(); return res; } /**************************************************************************** * Convert a hostname to a hostname with options applied. ****************************************************************************/ const gchar * resolve_hostname_to_hostname(gsize *result_len, const gchar *hname, HostResolveOptions *host_resolve_options) { hname = bounce_to_hostname_buffer(hname); if (host_resolve_options->use_fqdn) convert_hostname_to_fqdn(hostname_buffer, sizeof(hostname_buffer)); else convert_hostname_to_short_hostname(hostname_buffer, sizeof(hostname_buffer)); const gchar *res = hostname_apply_options(-1, result_len, hname, host_resolve_options); _attempt_to_invalidate_iv_now(); return res; } /**************************************************************************** * HostResolveOptions ****************************************************************************/ void host_resolve_options_defaults(HostResolveOptions *options) { options->use_dns = -1; options->use_fqdn = -1; options->use_dns_cache = -1; options->normalize_hostnames = -1; } void host_resolve_options_global_defaults(HostResolveOptions *options) { options->use_fqdn = FALSE; options->use_dns = TRUE; options->use_dns_cache = TRUE; options->normalize_hostnames = FALSE; } static void _init_options(HostResolveOptions *options) { if (options->use_dns == 0) { if (options->use_dns_cache != 0) { msg_warning("WARNING: With use-dns(no), dns-cache() will be forced to 'no' too!"); } options->use_dns_cache = 0; } } void host_resolve_options_init_globals(HostResolveOptions *options) { _init_options(options); } void host_resolve_options_init(HostResolveOptions *options, HostResolveOptions *global_options) { if (options->use_dns == -1) options->use_dns = global_options->use_dns; if (options->use_fqdn == -1) options->use_fqdn = global_options->use_fqdn; if (options->use_dns_cache == -1) options->use_dns_cache = global_options->use_dns_cache; if (options->normalize_hostnames == -1) options->normalize_hostnames = global_options->normalize_hostnames; _init_options(options); } void host_resolve_options_destroy(HostResolveOptions *options) { } static void _reinit_resolver(gint type, gpointer user_data) { res_init(); } void host_resolve_global_init(void) { register_application_hook(AH_CONFIG_STOPPED, _reinit_resolver, NULL, AHM_RUN_REPEAT); } syslog-ng-syslog-ng-4.4.0/lib/host-resolve.h000066400000000000000000000037231450431004300207310ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HOST_RESOLVE_H_INCLUDED #define HOST_RESOLVE_H_INCLUDED 1 #include "syslog-ng.h" #include "gsockaddr.h" typedef struct _HostResolveOptions { gboolean use_dns; gboolean use_fqdn; gboolean use_dns_cache; gboolean normalize_hostnames; } HostResolveOptions; /* name resolution */ const gchar *resolve_sockaddr_to_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options); gboolean resolve_hostname_to_sockaddr(GSockAddr **addr, gint family, const gchar *name); const gchar *resolve_hostname_to_hostname(gsize *result_len, const gchar *hostname, HostResolveOptions *options); void host_resolve_options_defaults(HostResolveOptions *options); void host_resolve_options_global_defaults(HostResolveOptions *options); void host_resolve_options_init_globals(HostResolveOptions *options); void host_resolve_options_init(HostResolveOptions *options, HostResolveOptions *global_options); void host_resolve_options_destroy(HostResolveOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/hostname-unix.c000066400000000000000000000040411450431004300210630ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* NOTE: this file is included directly into hostname.c so the set of * includes here only add system dependent headers and not the full set */ #include static struct hostent * _resolve_localhost_from_dns(void) { gchar *local_host; struct hostent *host; local_host = get_local_hostname_from_system(); host = gethostbyname(local_host); g_free(local_host); return host; } static const gchar * _extract_fqdn_from_hostent(struct hostent *host) { gint i; if (is_hostname_fqdn(host->h_name)) return host->h_name; for (i = 0; host->h_aliases[i]; i++) { if (is_hostname_fqdn(host->h_aliases[i])) return host->h_aliases[i]; } return NULL; } /* * NOTE: this function is not thread safe because it uses the non-reentrant * resolver functions. This is not a problem as it is only called once * during initialization when a single thread is active. */ gchar * get_local_fqdn_hostname_from_dns(void) { struct hostent *hostent; hostent = _resolve_localhost_from_dns(); if (hostent) return g_strdup(_extract_fqdn_from_hostent(hostent)); return NULL; } syslog-ng-syslog-ng-4.4.0/lib/hostname.c000066400000000000000000000114271450431004300201100ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "hostname.h" #include "cfg.h" #include "gsockaddr.h" #include "messages.h" #include "dnscache.h" #include #include #include static gchar local_hostname_fqdn[256]; static gchar local_hostname_short[256]; static gchar local_domain[256]; static gboolean local_domain_overridden; static gchar * get_local_hostname_from_system(void) { gchar hostname[256]; gethostname(hostname, sizeof(hostname) - 1); hostname[sizeof(hostname) - 1] = '\0'; return g_strdup(hostname); } static gboolean is_hostname_fqdn(const gchar *hostname) { return strchr(hostname, '.') != NULL; } static const gchar * extract_domain_from_fqdn(const gchar *hostname) { const gchar *dot = strchr(hostname, '.'); if (dot) return dot + 1; return NULL; } #include "hostname-unix.c" static void validate_hostname_cache(void) { g_assert(local_hostname_fqdn[0] != 0); } const gchar * get_local_hostname_fqdn(void) { validate_hostname_cache(); return local_hostname_fqdn; } const gchar * get_local_hostname_short(void) { validate_hostname_cache(); return local_hostname_short; } gchar * convert_hostname_to_fqdn(gchar *hostname, gsize hostname_len) { gchar *end; /* we only change the hostname if domain_override is set. If it is unset, * our best guess is what we got as input. */ if (local_domain_overridden) convert_hostname_to_short_hostname(hostname, hostname_len); if (local_domain_overridden || (!is_hostname_fqdn(hostname) && local_domain[0])) { end = hostname + strlen(hostname); if (end < hostname + hostname_len) { *end = '.'; end++; } strncpy(end, local_domain, hostname_len - (end - hostname)); hostname[hostname_len - 1] = 0; } return hostname; } gchar * convert_hostname_to_short_hostname(gchar *hostname, gsize hostname_len) { gchar *p; p = strchr(hostname, '.'); if (p) *p = '\0'; return hostname; } static void detect_local_fqdn_hostname(void) { gchar *hostname; hostname = get_local_hostname_from_system(); if (!is_hostname_fqdn(hostname)) { /* not fully qualified, resolve it using DNS or /etc/hosts */ g_free(hostname); hostname = get_local_fqdn_hostname_from_dns(); if (!hostname) { msg_verbose("Unable to detect fully qualified hostname for localhost, use_fqdn() will use the short hostname"); hostname = get_local_hostname_from_system(); if (!hostname[0]) { msg_error("Could not resolve local hostname either from the DNS nor gethostname(), assuming localhost"); hostname = g_strdup("localhost"); } } } g_strlcpy(local_hostname_fqdn, hostname, sizeof(local_hostname_fqdn)); g_free(hostname); } static void detect_local_domain(void) { const gchar *domain = extract_domain_from_fqdn(local_hostname_fqdn); if (domain) g_strlcpy(local_domain, domain, sizeof(local_domain)); else local_domain[0] = 0; } static void detect_local_short_hostname(void) { g_strlcpy(local_hostname_short, local_hostname_fqdn, sizeof(local_hostname_short)); convert_hostname_to_short_hostname(local_hostname_short, sizeof(local_hostname_short)); } static void set_domain_override(const gchar *domain_override) { if (domain_override) { g_strlcpy(local_domain, domain_override, sizeof(local_domain)); local_domain_overridden = TRUE; } else local_domain_overridden = FALSE; convert_hostname_to_fqdn(local_hostname_fqdn, sizeof(local_hostname_fqdn)); } void hostname_reinit(const gchar *domain_override) { detect_local_fqdn_hostname(); detect_local_domain(); detect_local_short_hostname(); set_domain_override(domain_override); } void hostname_global_init(void) { hostname_reinit(NULL); } void hostname_global_deinit(void) { } syslog-ng-syslog-ng-4.4.0/lib/hostname.h000066400000000000000000000026001450431004300201060ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef HOSTNAME_H_INCLUDED #define HOSTNAME_H_INCLUDED #include "syslog-ng.h" gchar *convert_hostname_to_fqdn(gchar *hostname, gsize hostname_len); gchar *convert_hostname_to_short_hostname(gchar *hostname, gsize hostname_len); const gchar *get_local_hostname_fqdn(void); const gchar *get_local_hostname_short(void); void hostname_reinit(const gchar *custom_domain); void hostname_global_init(void); void hostname_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/ivykis/000077500000000000000000000000001450431004300174375ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/list-adt.h000066400000000000000000000040551450431004300200170ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIST_ADT_H_INCLUDED #define LIST_ADT_H_INCLUDED #include typedef struct _List List; typedef void (*list_foreach_fn)(gconstpointer list_data, gpointer user_data); struct _List { void (*append)(List *self, gconstpointer item); void (*foreach)(List *self, list_foreach_fn foreach_fn, gpointer user_data); gboolean (*is_empty)(List *self); void (*remove_all)(List *self); void (*free_fn)(List *self); }; static inline void list_append(List *self, gconstpointer item) { g_assert(self->append); self->append(self, item); } static inline void list_foreach(List *self, list_foreach_fn foreach_fn, gpointer user_data) { g_assert(self->foreach); self->foreach(self, foreach_fn, user_data); } static inline gboolean list_is_empty(List *self) { g_assert(self->is_empty); return self->is_empty(self); } static inline void list_remove_all(List *self) { g_assert(self->remove_all); self->remove_all(self); } static inline void list_free(List *self) { if (self->free_fn) self->free_fn(self); g_free(self); } #endif syslog-ng-syslog-ng-4.4.0/lib/logmatcher.c000066400000000000000000000651101450431004300204150ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmatcher.h" #include "messages.h" #include "cfg.h" #include "str-utils.h" #include "scratch-buffers.h" #include "compat/string.h" #include "compat/pcre.h" static void log_matcher_store_pattern(LogMatcher *self, const gchar *pattern) { g_free(self->pattern); self->pattern = g_strdup(pattern); } static void log_matcher_free_method(LogMatcher *self) { g_free(self->pattern); } static void log_matcher_init(LogMatcher *self, const LogMatcherOptions *options) { self->ref_cnt = 1; self->flags = options->flags; self->free_fn = log_matcher_free_method; } typedef struct _LogMatcherString { LogMatcher super; gint pattern_len; } LogMatcherString; static gboolean log_matcher_string_compile(LogMatcher *s, const gchar *pattern, GError **error) { LogMatcherString *self = (LogMatcherString *) s; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); log_matcher_store_pattern(s, pattern); self->pattern_len = strlen(pattern); return TRUE; } static const gchar * log_matcher_string_match_string(LogMatcherString *self, const gchar *value, gsize value_len) { const gchar *result = NULL; gboolean match = FALSE; const gchar *pattern = self->super.pattern; if (self->pattern_len > value_len) return NULL; if (G_LIKELY((self->super.flags & (LMF_SUBSTRING + LMF_PREFIX)) == 0)) { if (self->super.flags & LMF_ICASE) match = strncasecmp(value, pattern, value_len) == 0; else match = strncmp(value, pattern, value_len) == 0; } else if (self->super.flags & LMF_PREFIX) { if (self->super.flags & LMF_ICASE) match = strncasecmp(value, pattern, MIN(value_len, self->pattern_len)) == 0; else match = strncmp(value, pattern, MIN(value_len, self->pattern_len)) == 0; } else if (self->super.flags & LMF_SUBSTRING) { if (self->super.flags & LMF_ICASE) { gchar *buf; gchar *res; APPEND_ZERO(buf, value, value_len); res = strcasestr(buf, pattern); if (res) result = value + (res - buf); } else { result = g_strstr_len(value, value_len, pattern); } } if (match && !result) result = value; return result; } static gboolean log_matcher_string_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len) { LogMatcherString *self = (LogMatcherString *) s; return log_matcher_string_match_string(self, value, value_len) != NULL; } static gchar * log_matcher_string_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { LogMatcherString *self = (LogMatcherString *) s; GString *new_value = NULL; gsize current_ofs = 0; gboolean first_round = TRUE; if (value_len < 0) value_len = strlen(value); const gchar *match; do { if (current_ofs == value_len) break; match = log_matcher_string_match_string(self, value + current_ofs, value_len - current_ofs); if (match != NULL) { /* start_ofs & end_ofs are relative to the original string */ gsize start_ofs = match - value; gsize end_ofs = start_ofs + self->pattern_len; if (start_ofs == end_ofs && !first_round) { start_ofs++; end_ofs++; } if ((s->flags & LMF_STORE_MATCHES)) log_msg_clear_matches(msg); if (!new_value) new_value = g_string_sized_new(value_len); g_string_append_len(new_value, value + current_ofs, start_ofs - current_ofs); log_template_append_format(replacement, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, new_value); current_ofs = end_ofs; if ((self->super.flags & LMF_GLOBAL) == 0) { g_string_append_len(new_value, value + current_ofs, value_len - current_ofs); break; } } else { if (new_value) { /* no more matches, append the end of the string */ g_string_append_len(new_value, value + current_ofs, value_len - current_ofs); } } first_round = FALSE; } while (match && (self->super.flags & LMF_GLOBAL)); if (new_value) { if (new_length) *new_length = new_value->len; return g_string_free(new_value, FALSE); } return NULL; } LogMatcher * log_matcher_string_new(const LogMatcherOptions *options) { LogMatcherString *self = g_new0(LogMatcherString, 1); log_matcher_init(&self->super, options); self->super.compile = log_matcher_string_compile; self->super.match = log_matcher_string_match; self->super.replace = log_matcher_string_replace; return &self->super; } typedef struct _LogMatcherGlob { LogMatcher super; GPatternSpec *pattern; } LogMatcherGlob; static gboolean log_matcher_glob_compile(LogMatcher *s, const gchar *pattern, GError **error) { LogMatcherGlob *self = (LogMatcherGlob *)s; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); log_matcher_store_pattern(s, pattern); self->pattern = g_pattern_spec_new(pattern); return TRUE; } /* GPattern only works with utf8 strings, if the input is not utf8, we risk * a crash */ static gboolean log_matcher_glob_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len) { LogMatcherGlob *self = (LogMatcherGlob *) s; if (G_LIKELY((msg->flags & LF_UTF8) || g_utf8_validate(value, value_len, NULL))) { static gboolean warned = FALSE; gchar *buf; if (G_UNLIKELY(!warned && (msg->flags & LF_UTF8) == 0)) { msg_warning("Input is valid utf8, but the log message is not tagged as such, this performs worse than enabling validate-utf8 flag on input", evt_tag_mem("value", value, value_len)); warned = TRUE; } APPEND_ZERO(buf, value, value_len); return g_pattern_match(self->pattern, value_len, buf, NULL); } else { msg_warning("Input is not valid utf8, glob match requires utf8 input, thus it never matches in this case", evt_tag_mem("value", value, value_len)); } return FALSE; } static void log_matcher_glob_free(LogMatcher *s) { LogMatcherGlob *self = (LogMatcherGlob *)s; g_pattern_spec_free(self->pattern); log_matcher_free_method(s); } LogMatcher * log_matcher_glob_new(const LogMatcherOptions *options) { LogMatcherGlob *self = g_new0(LogMatcherGlob, 1); log_matcher_init(&self->super, options); self->super.compile = log_matcher_glob_compile; self->super.match = log_matcher_glob_match; self->super.replace = NULL; self->super.free_fn = log_matcher_glob_free; return &self->super; } /* libpcre support */ typedef struct _LogMatcherPcreRe { LogMatcher super; pcre2_code *pattern; gint match_options; gchar *nv_prefix; gint nv_prefix_len; } LogMatcherPcreRe; static gboolean _compile_pcre2_regexp(LogMatcherPcreRe *self, const gchar *re, GError **error) { gint rc; gint flags = 0; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (self->super.flags & LMF_ICASE) flags |= PCRE2_CASELESS; if (self->super.flags & LMF_NEWLINE) { if (!PCRE2_NEWLINE_ANYCRLF) msg_warning("syslog-ng was compiled against an old PCRE which doesn't support the 'newline' flag"); flags |= PCRE2_NEWLINE_ANYCRLF; } if (self->super.flags & LMF_UTF8) { gint support; flags |= PCRE2_UTF | PCRE2_NO_UTF_CHECK; self->match_options |= PCRE2_NO_UTF_CHECK; pcre2_config(PCRE2_CONFIG_UNICODE, &support); if (!support) { g_set_error(error, LOG_TEMPLATE_ERROR, 0, "PCRE library is compiled without unicode support and utf8 flag was present"); return FALSE; } } if (self->super.flags & LMF_DUPNAMES) { if (!PCRE2_DUPNAMES) msg_warning("syslog-ng was compiled against an old PCRE which doesn't support the 'dupnames' flag"); flags |= PCRE2_DUPNAMES; } /* compile the regexp */ PCRE2_SIZE error_offset; self->pattern = pcre2_compile((PCRE2_SPTR) re, PCRE2_ZERO_TERMINATED, flags, &rc, &error_offset, NULL); if (!self->pattern) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); g_set_error(error, LOG_TEMPLATE_ERROR, 0, "Failed to compile PCRE expression >>>%s<<< `%s' at character %d", re, error_message, (gint) error_offset); return FALSE; } return TRUE; } static gboolean _jit_pcre2_regexp(LogMatcherPcreRe *self, const gchar *re, GError **error) { if ((self->super.flags & LMF_DISABLE_JIT)) return TRUE; /* optimize regexp */ gint rc = pcre2_jit_compile(self->pattern, PCRE2_JIT_COMPLETE); if (rc < 0) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); msg_warning("Failed to JIT compile regular expression, you might want to use flags(disable-jit)", evt_tag_str("regexp", re), evt_tag_str("error", (gchar *) error_message)); } return TRUE; } static gboolean log_matcher_pcre_re_compile(LogMatcher *s, const gchar *re, GError **error) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); log_matcher_store_pattern(s, re); if (!_compile_pcre2_regexp(self, re, error)) return FALSE; if (!_jit_pcre2_regexp(self, re, error)) return FALSE; return TRUE; } typedef struct _LogMatcherPcreMatchResult { NVHandle source_handle; const gchar *source_value; gssize source_value_len; pcre2_match_data *match_data; } LogMatcherPcreMatchResult; static inline void log_matcher_pcre_re_save_source_value_to_avoid_clobbering(LogMatcherPcreMatchResult *result) { GString *source_value_scratch = scratch_buffers_alloc(); g_string_assign_len(source_value_scratch, result->source_value, result->source_value_len); result->source_value = source_value_scratch->str; /* source_value_scratch will be freed automatically by the scratch-buffers GC */ } static inline void log_matcher_pcre_re_feed_value(LogMatcherPcreRe *self, LogMessage *msg, NVHandle target_handle, LogMatcherPcreMatchResult *result, gint begin_index, gint end_index) { gboolean indirect = result->source_handle != LM_V_NONE && log_msg_is_handle_settable_with_an_indirect_value(target_handle) && log_msg_is_handle_referencable_from_an_indirect_value(result->source_handle); if (target_handle == result->source_handle) { /* we are clobbering our input at this point, e.g. we are setting the * name-value pair that we use as input. And we use a borrowed * reference so that we avoid copying. This means that if * target_handle == source_handle we would implicitly overwrite the * memory area that "value" points to (to add to the injury and to * make it less appearent, this is not always the case: it does not * happen if the new value does not fit the old NVEntry). */ log_matcher_pcre_re_save_source_value_to_avoid_clobbering(result); } if (indirect) log_msg_set_value_indirect(msg, target_handle, result->source_handle, begin_index, end_index - begin_index); else log_msg_set_value(msg, target_handle, &result->source_value[begin_index], end_index - begin_index); } static void log_matcher_pcre_re_feed_backrefs(LogMatcherPcreRe *self, LogMessage *msg, LogMatcherPcreMatchResult *result) { gint i; guint32 num_matches = pcre2_get_ovector_count(result->match_data); PCRE2_SIZE *matches = pcre2_get_ovector_pointer(result->match_data); for (i = 0; i < (LOGMSG_MAX_MATCHES) && i < num_matches; i++) { gint begin_index = matches[2 * i]; gint end_index = matches[2 * i + 1]; if (begin_index < 0 || end_index < 0) continue; log_matcher_pcre_re_feed_value(self, msg, log_msg_get_match_handle(i), result, begin_index, end_index); } if (log_msg_is_handle_match(result->source_handle) && log_msg_get_match_index(result->source_handle) >= num_matches) { log_matcher_pcre_re_save_source_value_to_avoid_clobbering(result); } log_msg_truncate_matches(msg, num_matches); } static void log_matcher_pcre_re_feed_named_substrings(LogMatcherPcreRe *self, LogMessage *msg, LogMatcherPcreMatchResult *result) { gchar *name_table = NULL; gint i = 0; guint32 namecount = 0; guint32 name_entry_size = 0; pcre2_pattern_info(self->pattern, PCRE2_INFO_NAMECOUNT, &namecount); if (namecount > 0) { PCRE2_SIZE *matches = pcre2_get_ovector_pointer(result->match_data); gchar *tabptr; /* Before we can access the substrings, we must extract the table for translating names to numbers, and the size of each entry in the table. */ pcre2_pattern_info(self->pattern, PCRE2_INFO_NAMETABLE, &name_table); pcre2_pattern_info(self->pattern, PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size); /* Now we can scan the table and, for each entry, print the number, the name, and the substring itself. */ GString *formatted_name = scratch_buffers_alloc(); g_string_assign_len(formatted_name, self->nv_prefix, self->nv_prefix_len); tabptr = name_table; for (i = 0; i < namecount; i++, tabptr += name_entry_size) { int n = (tabptr[0] << 8) | tabptr[1]; gint begin_index = matches[2 * n]; gint end_index = matches[2 * n + 1]; const gchar *namedgroup_name = tabptr + 2; if (begin_index < 0 || end_index < 0) continue; g_string_truncate(formatted_name, self->nv_prefix_len); g_string_append(formatted_name, namedgroup_name); log_matcher_pcre_re_feed_value(self, msg, log_msg_get_value_handle(formatted_name->str), result, begin_index, end_index); } } } static gboolean log_matcher_pcre_re_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; LogMatcherPcreMatchResult result; gint rc; gboolean res = TRUE; if (value_len == -1) value_len = strlen(value); result.match_data = pcre2_match_data_create_from_pattern(self->pattern, NULL); result.source_value = value; result.source_value_len = value_len; result.source_handle = value_handle; rc = pcre2_match(self->pattern, (PCRE2_SPTR) result.source_value, (PCRE2_SIZE) result.source_value_len, (PCRE2_SIZE) 0, self->match_options, result.match_data, NULL); if (rc < 0) { switch (rc) { case PCRE2_ERROR_NOMATCH: break; default: /* Handle other special cases */ msg_error("Error while matching regexp", evt_tag_int("error_code", rc)); break; } res = FALSE; } else if (rc == 0) { msg_error("Error while storing matching substrings, more than 256 capture groups encountered"); } else { if ((s->flags & LMF_STORE_MATCHES)) { log_matcher_pcre_re_feed_backrefs(self, msg, &result); log_matcher_pcre_re_feed_named_substrings(self, msg, &result); } } pcre2_match_data_free(result.match_data); return res; } static gchar * log_matcher_pcre_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; LogMatcherPcreMatchResult result; GString *new_value = NULL; gint rc; gint start_offset, last_offset; gint options; gboolean last_match_was_empty; result.match_data = pcre2_match_data_create_from_pattern(self->pattern, NULL); PCRE2_SIZE *matches = pcre2_get_ovector_pointer(result.match_data); /* we need zero initialized offsets for the last match as the * algorithm tries uses that as the base position */ matches[0] = matches[1] = 0; if (value_len == -1) value_len = strlen(value); result.source_value = value; result.source_value_len = value_len; result.source_handle = value_handle; last_offset = start_offset = 0; last_match_was_empty = FALSE; do { /* loop over the string, replacing one occurrence at a time. */ /* NOTE: zero length matches need special care, as we could spin * forever otherwise (since the current position wouldn't be * advanced). * * A zero-length match can be as simple as "a*" which will be * returned unless PCRE2_NOTEMPTY is specified. * * By supporting zero-length matches, we basically make it * possible to insert replacement between each incoming * character. * * For example: * pattern: a* * replacement: # * input: message * result: #m#e#s#s#a#g#e# * * This mimics Perl behaviour. */ if (last_match_was_empty) { /* Otherwise, arrange to run another match at the same point * to see if a non-empty match can be found. */ options = PCRE2_NOTEMPTY | PCRE2_ANCHORED; } else { options = 0; } rc = pcre2_match(self->pattern, (PCRE2_SPTR) result.source_value, (PCRE2_SIZE) result.source_value_len, start_offset, (self->match_options | options), result.match_data, NULL); if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) { msg_error("Error while matching regexp", evt_tag_int("error_code", rc)); break; } else if (rc < 0) { if ((options & PCRE2_NOTEMPTY) == 0) { /* we didn't match, even when we permitted to match the * empty string. Nothing to find here, bail out */ break; } /* we didn't match, quite possibly because the empty match * was not permitted. Skip one character in order to avoid * infinite loop over the same zero-length match. */ start_offset = start_offset + 1; /* FIXME: handle complex sequences like utf8 and newline characters */ last_match_was_empty = FALSE; continue; } else if (rc == 0) { msg_error("Error while storing matching substrings, more than 256 capture groups encountered"); break; } else { log_matcher_pcre_re_feed_backrefs(self, msg, &result); log_matcher_pcre_re_feed_named_substrings(self, msg, &result); if (!new_value) new_value = g_string_sized_new(result.source_value_len); /* append non-matching portion */ g_string_append_len(new_value, &result.source_value[last_offset], matches[0] - last_offset); /* replacement */ log_template_append_format(replacement, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, new_value); last_match_was_empty = (matches[0] == matches[1]); start_offset = last_offset = matches[1]; } } while (self->super.flags & LMF_GLOBAL && start_offset < result.source_value_len); pcre2_match_data_free(result.match_data); if (new_value) { /* append the last literal */ g_string_append_len(new_value, &result.source_value[last_offset], result.source_value_len - last_offset); if (new_length) *new_length = new_value->len; return g_string_free(new_value, FALSE); } return NULL; } static void log_matcher_pcre_re_free(LogMatcher *s) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; pcre2_code_free(self->pattern); log_matcher_free_method(s); } LogMatcher * log_matcher_pcre_re_new(const LogMatcherOptions *options) { LogMatcherPcreRe *self = g_new0(LogMatcherPcreRe, 1); self->nv_prefix = NULL; self->nv_prefix_len = 0; log_matcher_init(&self->super, options); self->super.compile = log_matcher_pcre_re_compile; self->super.match = log_matcher_pcre_re_match; self->super.replace = log_matcher_pcre_re_replace; self->super.free_fn = log_matcher_pcre_re_free; return &self->super; } void log_matcher_pcre_set_nv_prefix(LogMatcher *s, const gchar *prefix) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; g_free(self->nv_prefix); if (prefix) { self->nv_prefix = g_strdup(prefix); self->nv_prefix_len = strlen(prefix); } else { self->nv_prefix = NULL; self->nv_prefix_len = 0; } } typedef LogMatcher *(*LogMatcherConstructFunc)(const LogMatcherOptions *options); gboolean log_matcher_match_value(LogMatcher *s, LogMessage *msg, gint value_handle) { NVTable *payload = nv_table_ref(msg->payload); gssize value_len; const gchar *value = log_msg_get_value(msg, value_handle, &value_len); APPEND_ZERO(value, value, value_len); gboolean result = log_matcher_match(s, msg, value_handle, value, value_len); nv_table_unref(payload); return result; } gboolean log_matcher_match_buffer(LogMatcher *s, LogMessage *msg, const gchar *value, gssize value_len) { return log_matcher_match(s, msg, LM_V_NONE, value, value_len); } gboolean log_matcher_match_template(LogMatcher *s, LogMessage *msg, LogTemplate *template, LogTemplateEvalOptions *options) { gboolean result; if (log_template_is_literal_string(template)) { gssize len; const gchar *value = log_template_get_literal_value(template, &len); result = log_matcher_match_buffer(s, msg, value, len); } else if (log_template_is_trivial(template)) { NVHandle handle = log_template_get_trivial_value_handle(template); g_assert(handle != LM_V_NONE); result = log_matcher_match_value(s, msg, handle); } else { GString *buffer = scratch_buffers_alloc(); log_template_format(template, msg, options, buffer); result = log_matcher_match_buffer(s, msg, buffer->str, buffer->len); } return result; } struct { const gchar *name; LogMatcherConstructFunc construct; } matcher_types[] = { { "pcre", log_matcher_pcre_re_new }, { "string", log_matcher_string_new }, { "glob", log_matcher_glob_new }, { NULL, NULL }, }; static LogMatcherConstructFunc log_matcher_lookup_construct(const gchar *type) { gint i; for (i = 0; matcher_types[i].name; i++) { if (strcmp(matcher_types[i].name, type) == 0) return matcher_types[i].construct; } return NULL; } LogMatcher * log_matcher_new(const LogMatcherOptions *options) { LogMatcherConstructFunc construct; construct = log_matcher_lookup_construct(options->type); return construct(options); } LogMatcher * log_matcher_ref(LogMatcher *s) { s->ref_cnt++; return s; } void log_matcher_unref(LogMatcher *s) { if (--s->ref_cnt == 0) { if (s->free_fn) s->free_fn(s); g_free(s); } } gboolean log_matcher_options_set_type(LogMatcherOptions *options, const gchar *type) { LogMatcherConstructFunc construct; if (strcmp(type, "posix") == 0) { msg_warning_once("WARNING: syslog-ng dropped support for POSIX regexp implementations in " VERSION_3_14 " in favour of PCRE, which should be upward compatible. All 'posix' regexps are " "automatically switched to 'pcre'. Please ensure that your regexps work with PCRE and " "specify type('pcre') explicitly or increase @version to remove this warning"); type = "pcre"; } construct = log_matcher_lookup_construct(type); if (!construct) return FALSE; if (options->type) g_free(options->type); options->type = g_strdup(type); return TRUE; } CfgFlagHandler log_matcher_flag_handlers[] = { /* NOTE: underscores are automatically converted to dashes */ { "global", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_GLOBAL }, { "icase", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_ICASE }, { "ignore-case", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_ICASE }, { "newline", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_NEWLINE }, { "unicode", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_UTF8 }, { "utf8", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_UTF8 }, { "store-matches", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_STORE_MATCHES }, { "substring", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_SUBSTRING }, { "prefix", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_PREFIX }, { "disable-jit", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_DISABLE_JIT }, { "dupnames", CFH_SET, offsetof(LogMatcherOptions, flags), LMF_DUPNAMES }, { NULL }, }; gboolean log_matcher_options_process_flag(LogMatcherOptions *self, const gchar *flag) { return cfg_process_flag(log_matcher_flag_handlers, self, flag); } void log_matcher_options_defaults(LogMatcherOptions *options) { options->flags = 0; options->type = NULL; } void log_matcher_options_init(LogMatcherOptions *options) { if (!options->type) { const gchar *default_matcher = "pcre"; if (!log_matcher_options_set_type(options, default_matcher)) g_assert_not_reached(); } } void log_matcher_options_destroy(LogMatcherOptions *options) { if (options->type) g_free(options->type); } GQuark log_matcher_error_quark(void) { return g_quark_from_static_string("log-matcher-error-quark"); } syslog-ng-syslog-ng-4.4.0/lib/logmatcher.h000066400000000000000000000104161450431004300204210ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGMATCHER_H_INCLUDED #define LOGMATCHER_H_INCLUDED #include "logmsg/logmsg.h" #include "template/templates.h" #define LOG_MATCHER_ERROR log_template_error_quark() GQuark log_matcher_error_quark(void); enum { /* use global search/replace */ LMF_GLOBAL = 0x0001, LMF_ICASE = 0x0002, LMF_MATCH_ONLY = 0x0004, /* POSIX + PCRE common flags */ LMF_NEWLINE= 0x0008, LMF_UTF8 = 0x0010, LMF_STORE_MATCHES = 0x0020, LMF_DISABLE_JIT = 0x0040, /* string flags */ LMF_SUBSTRING = 0x0080, LMF_PREFIX = 0x0100, /* advanced LIBPCRE flags */ LMF_DUPNAMES = 0x00080000, }; typedef struct _LogMatcherOptions { gint flags; gchar *type; } LogMatcherOptions; typedef struct _LogMatcher LogMatcher; struct _LogMatcher { gint ref_cnt; gint flags; gchar *pattern; gboolean (*compile)(LogMatcher *s, const gchar *re, GError **error); /* value_len can be -1 to indicate unknown length */ gboolean (*match)(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len); /* value_len can be -1 to indicate unknown length, new_length can be returned as -1 to indicate unknown length */ gchar *(*replace)(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length); void (*free_fn)(LogMatcher *s); }; static inline gboolean log_matcher_compile(LogMatcher *s, const gchar *re, GError **error) { return s->compile(s, re, error); } static inline gboolean log_matcher_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len) { return s->match(s, msg, value_handle, value, value_len); } gboolean log_matcher_match_value(LogMatcher *s, LogMessage *msg, gint value_handle); gboolean log_matcher_match_buffer(LogMatcher *s, LogMessage *msg, const gchar *value, gssize value_len); gboolean log_matcher_match_template(LogMatcher *s, LogMessage *msg, LogTemplate *template, LogTemplateEvalOptions *options); static inline gchar * log_matcher_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { if (s->replace) return s->replace(s, msg, value_handle, value, value_len, replacement, new_length); return NULL; } static inline void log_matcher_set_flags(LogMatcher *s, gint flags) { s->flags = flags; } static inline gboolean log_matcher_is_replace_supported(LogMatcher *s) { return s->replace != NULL; } LogMatcher *log_matcher_pcre_re_new(const LogMatcherOptions *options); LogMatcher *log_matcher_string_new(const LogMatcherOptions *options); LogMatcher *log_matcher_glob_new(const LogMatcherOptions *options); LogMatcher *log_matcher_new(const LogMatcherOptions *options); LogMatcher *log_matcher_ref(LogMatcher *s); void log_matcher_unref(LogMatcher *s); gboolean log_matcher_options_set_type(LogMatcherOptions *options, const gchar *type); gboolean log_matcher_options_process_flag(LogMatcherOptions *self, const gchar *flag); void log_matcher_options_defaults(LogMatcherOptions *options); void log_matcher_options_init(LogMatcherOptions *options); void log_matcher_options_destroy(LogMatcherOptions *options); void log_matcher_pcre_set_nv_prefix(LogMatcher *s, const gchar *prefix); #endif syslog-ng-syslog-ng-4.4.0/lib/logmpx.c000066400000000000000000000156611450431004300176040ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmpx.h" #include "cfg-walker.h" void log_multiplexer_add_next_hop(LogMultiplexer *self, LogPipe *next_hop) { g_ptr_array_add(self->next_hops, next_hop); } void log_multiplexer_disable_delivery_propagation(LogMultiplexer *self) { self->delivery_propagation = FALSE; } static gboolean log_multiplexer_init(LogPipe *s) { LogMultiplexer *self = (LogMultiplexer *) s; gint i; for (i = 0; i < self->next_hops->len; i++) { LogPipe *branch_head = g_ptr_array_index(self->next_hops, i); LogPipe *p; for (p = branch_head; p; p = p->pipe_next) { branch_head->flags |= (p->flags & PIF_BRANCH_PROPERTIES); } if (branch_head->flags & PIF_BRANCH_FALLBACK) { self->fallback_exists = TRUE; } } return TRUE; } static gboolean log_multiplexer_deinit(LogPipe *self) { return TRUE; } static gboolean _has_multiple_arcs(LogMultiplexer *self) { gint num_arcs = self->next_hops->len + (self->super.pipe_next ? 1 : 0); return num_arcs > 1; } static void log_multiplexer_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogMultiplexer *self = (LogMultiplexer *) s; gint i; gboolean matched; LogPathOptions local_options; gboolean delivered = FALSE; gint fallback; log_path_options_push_junction(&local_options, &matched, path_options); if (_has_multiple_arcs(self)) { log_msg_write_protect(msg); } for (fallback = 0; (fallback == 0) || (fallback == 1 && self->fallback_exists && !delivered); fallback++) { for (i = 0; i < self->next_hops->len; i++) { LogPipe *next_hop = g_ptr_array_index(self->next_hops, i); if (G_UNLIKELY(fallback == 0 && (next_hop->flags & PIF_BRANCH_FALLBACK) != 0)) { continue; } else if (G_UNLIKELY(fallback && (next_hop->flags & PIF_BRANCH_FALLBACK) == 0)) { continue; } matched = TRUE; log_msg_add_ack(msg, &local_options); log_pipe_queue(next_hop, log_msg_ref(msg), &local_options); if (matched) { delivered = TRUE; if (G_UNLIKELY(next_hop->flags & PIF_BRANCH_FINAL)) break; } } } /* NOTE: non of our multiplexed next-hops delivered this message, let's * propagate this result. But only if we don't have a "next". If we do, * that would be responsible for doing the same, for instance if it is a * filter. * * There are three distinct cases where LogMultiplexer is used: * * 1) at the tail of a LogSource, where the multiplexer is used to * dispatch messages along all log statements that reference the * specific source. In this case pipe_next is NULL, only next_hops are * used to connect parallel branches * * 2) as the head element of a junction, in this case pipe_next is NULL, * next_hops contain the branches of the junction. Subsequent LogPipes * in the current sequence are attached at the "join_pipe" which is * connected to all parallel branches of the junction. * * 3) when we connect the logpath to destinations. In this case * next_hops contain the destinations we want to deliver to. pipe_next * is used to continue along the current logpath. * * Conceptually, the matched value we propagate to our parent logpath * determines if our parent considers this message matched or not matched * by this element. * * - If we did match (e.g. delivered == TRUE), nothing is to be done. * * - If we did not match (e.g. delivered == FALSE), we may need to * propagate this result to our parent by setting * (*path_options->matched) to FALSE. * * In the cases of 1) and 2) we perform a filtering function and we want * to tell our parent that we did NOT match so it can attempt another * route. We need to set matched to FALSE; * * In the case of 3) we dispatched to one or more destinations and even if * those destinations drop our message on the floor, we are not interested. * "matched" will be determined by all filtering elements on the log * path and we are not one of them. * * We differentiate between 1, 2 and 3 based on the value of * self->delivery_propagation which is set during compilation. If * delivery_propagation is not set, we are just here for dispatching to * destinations (e.g. we need to ignore their outcome), otherwise we * perform a filtering function, which means we need to push our filtering * responsibility to the next pipe element. * */ if (self->delivery_propagation) { if (!delivered && path_options->matched) *path_options->matched = FALSE; } log_pipe_forward_msg(s, msg, path_options); } static void log_multiplexer_free(LogPipe *s) { LogMultiplexer *self = (LogMultiplexer *) s; g_ptr_array_free(self->next_hops, TRUE); log_pipe_free_method(s); } static void _append(LogPipe *to, gpointer *user_data) { LogPipe *from = user_data[0]; GList **list = user_data[1]; Arc *arc = arc_new(from, to, ARC_TYPE_NEXT_HOP); *list = g_list_append(*list, arc); } static GList * _arcs(LogPipe *s) { LogMultiplexer *self = (LogMultiplexer *)s; GList *list = NULL; g_ptr_array_foreach(self->next_hops, (GFunc)_append, (gpointer[2]) { self, &list }); if (s->pipe_next) list = g_list_append(list, arc_new((LogPipe *)self, s->pipe_next, ARC_TYPE_PIPE_NEXT)); return list; }; LogMultiplexer * log_multiplexer_new(GlobalConfig *cfg) { LogMultiplexer *self = g_new0(LogMultiplexer, 1); log_pipe_init_instance(&self->super, cfg); self->super.init = log_multiplexer_init; self->super.deinit = log_multiplexer_deinit; self->super.queue = log_multiplexer_queue; self->super.free_fn = log_multiplexer_free; self->next_hops = g_ptr_array_new(); self->super.arcs = _arcs; self->delivery_propagation = TRUE; log_pipe_add_info(&self->super, "multiplexer"); return self; } syslog-ng-syslog-ng-4.4.0/lib/logmpx.h000066400000000000000000000034231450431004300176020ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGMPX_H_INCLUDED #define LOGMPX_H_INCLUDED #include "logpipe.h" /** * This class encapsulates a fork of the message pipe-line. It receives * messages via its queue() method and forwards them to its list of * next_hops in addition to the standard pipe_next next-hop already provided * by LogPipe. * * This object is used for example for each source to send messages to all * log pipelines that refer to the source. **/ typedef struct _LogMultiplexer { LogPipe super; GPtrArray *next_hops; gboolean fallback_exists; gboolean delivery_propagation; } LogMultiplexer; void log_multiplexer_add_next_hop(LogMultiplexer *self, LogPipe *next_hop); void log_multiplexer_disable_delivery_propagation(LogMultiplexer *self); LogMultiplexer *log_multiplexer_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/000077500000000000000000000000001450431004300174115ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logmsg/CMakeLists.txt000066400000000000000000000015141450431004300221520ustar00rootroot00000000000000set(LOGMSG_HEADERS logmsg/gsockaddr-serialize.h logmsg/logmsg.h logmsg/logmsg-serialize.h logmsg/logmsg-serialize-fixup.h logmsg/nvhandle-descriptors.h logmsg/nvtable.h logmsg/nvtable-serialize.h logmsg/nvtable-serialize-endianutils.h logmsg/nvtable-serialize-legacy.h logmsg/tags-serialize.h logmsg/timestamp-serialize.h logmsg/tags.h logmsg/type-hinting.h PARENT_SCOPE) set(LOGMSG_SOURCES logmsg/gsockaddr-serialize.c logmsg/logmsg.c logmsg/logmsg-serialize.c logmsg/logmsg-serialize-fixup.c logmsg/nvhandle-descriptors.c logmsg/nvtable.c logmsg/nvtable-serialize.c logmsg/nvtable-serialize-legacy.c logmsg/tags-serialize.c logmsg/timestamp-serialize.c logmsg/tags.c logmsg/type-hinting.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/logmsg/Makefile.am000066400000000000000000000023641450431004300214520ustar00rootroot00000000000000logmsgincludedir = ${pkgincludedir}/logmsg EXTRA_DIST += lib/logmsg/CMakeLists.txt logmsginclude_HEADERS = \ lib/logmsg/gsockaddr-serialize.h \ lib/logmsg/logmsg.h \ lib/logmsg/serialization.h \ lib/logmsg/logmsg-serialize.h \ lib/logmsg/logmsg-serialize-fixup.h \ lib/logmsg/nvhandle-descriptors.h \ lib/logmsg/nvtable.h \ lib/logmsg/nvtable-serialize.h \ lib/logmsg/nvtable-serialize-legacy.h \ lib/logmsg/nvtable-serialize-endianutils.h \ lib/logmsg/tags-serialize.h \ lib/logmsg/timestamp-serialize.h \ lib/logmsg/tags.h \ lib/logmsg/type-hinting.h logmsg_sources = \ lib/logmsg/gsockaddr-serialize.c \ lib/logmsg/logmsg.c \ lib/logmsg/logmsg-serialize.c \ lib/logmsg/logmsg-serialize-fixup.c \ lib/logmsg/nvhandle-descriptors.c \ lib/logmsg/nvtable.c \ lib/logmsg/nvtable-serialize.c \ lib/logmsg/nvtable-serialize-legacy.c \ lib/logmsg/tags-serialize.c \ lib/logmsg/timestamp-serialize.c \ lib/logmsg/tags.c \ lib/logmsg/type-hinting.c include lib/logmsg/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/logmsg/gsockaddr-serialize.c000066400000000000000000000072301450431004300235050ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "gsockaddr-serialize.h" #include static gboolean _serialize_ipv4(GSockAddr *addr, SerializeArchive *sa) { struct in_addr ina; ina = g_sockaddr_inet_get_address(addr); return serialize_write_blob(sa, (gchar *) &ina, sizeof(ina)) && serialize_write_uint16(sa, htons(g_sockaddr_get_port(addr))); } #if SYSLOG_NG_ENABLE_IPV6 static gboolean _serialize_ipv6(GSockAddr *addr, SerializeArchive *sa) { struct in6_addr *in6a; in6a = g_sockaddr_inet6_get_address(addr); return serialize_write_blob(sa, (gchar *) in6a, sizeof(*in6a)) && serialize_write_uint16(sa, htons(g_sockaddr_get_port(addr))); } #endif gboolean g_sockaddr_serialize(SerializeArchive *sa, GSockAddr *addr) { if (!addr) { return serialize_write_uint16(sa, 0); } gboolean result = serialize_write_uint16(sa, addr->sa.sa_family); switch (addr->sa.sa_family) { case AF_INET: { result &= _serialize_ipv4(addr, sa); break; } #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: { result &= _serialize_ipv6(addr, sa); break; } #endif case AF_UNIX: { break; } default: { result = FALSE; break; } } return result; } static gboolean _deserialize_ipv4(SerializeArchive *sa, GSockAddr **addr) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (!serialize_read_blob(sa, (gchar *) &sin.sin_addr, sizeof(sin.sin_addr)) || !serialize_read_uint16(sa, &sin.sin_port)) return FALSE; *addr = g_sockaddr_inet_new2(&sin); return TRUE; } #if SYSLOG_NG_ENABLE_IPV6 static gboolean _deserialize_ipv6(SerializeArchive *sa, GSockAddr **addr) { gboolean result = FALSE; struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; if (serialize_read_blob(sa, (gchar *) &sin6.sin6_addr, sizeof(sin6.sin6_addr)) && serialize_read_uint16(sa, &sin6.sin6_port)) { *addr = g_sockaddr_inet6_new2(&sin6); result = TRUE; } return result; } #endif gboolean g_sockaddr_deserialize(SerializeArchive *sa, GSockAddr **addr) { guint16 family; gboolean result = TRUE; if (!serialize_read_uint16(sa, &family)) return FALSE; switch (family) { case 0: /* special case, no address was stored */ *addr = NULL; break; case AF_INET: { result = _deserialize_ipv4(sa, addr); break; } #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: { result = _deserialize_ipv6(sa, addr); break; } #endif case AF_UNIX: *addr = g_sockaddr_unix_new(NULL); break; default: result = FALSE; break; } return result; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/gsockaddr-serialize.h000066400000000000000000000024051450431004300235110ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef G_SOCKADDR_SERIALIZE_H #define G_SOCKADDR_SERIALIZE_H #include "gsockaddr.h" #include "serialize.h" gboolean g_sockaddr_serialize(SerializeArchive *sa, GSockAddr *addr); gboolean g_sockaddr_deserialize(SerializeArchive *sa, GSockAddr **addr); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg-serialize-fixup.c000066400000000000000000000252601450431004300241700ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 2016 Balázs Scheidler * Copyright (c) 2012-2015 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmsg-serialize-fixup.h" #include "nvtable-serialize.h" #include /* NOTE: this enum matches the legacy type values used by db-parser() 3.35 * and below. With the PR that introduces generic typing, db-parser() is * converted to use the new values, so 3.36 onwards we will never produce * these values again by newly serialized LogMessage instances. * * When reading the old format however, we need to convert from the old to * the new for which we are using this enum and the * log_msg_map_legacy_dbparser_type_to_generic_type() function below. */ enum { LEGACY_DBPARSER_TYPE_STRING, LEGACY_DBPARSER_TYPE_QSTRING, LEGACY_DBPARSER_TYPE_ESTRING, LEGACY_DBPARSER_TYPE_IPV4, LEGACY_DBPARSER_TYPE_NUMBER, LEGACY_DBPARSER_TYPE_ANYSTRING, LEGACY_DBPARSER_TYPE_IPV6, LEGACY_DBPARSER_TYPE_IP, LEGACY_DBPARSER_TYPE_FLOAT, LEGACY_DBPARSER_TYPE_SET, LEGACY_DBPARSER_TYPE_MACADDR, LEGACY_DBPARSER_TYPE_PCRE, LEGACY_DBPARSER_TYPE_EMAIL, LEGACY_DBPARSER_TYPE_HOSTNAME, LEGACY_DBPARSER_TYPE_LLADDR, LEGACY_DBPARSER_TYPE_NLSTRING, LEGACY_DBPARSER_TYPE_OPTIONALSET, }; static LogMessageValueType log_msg_map_legacy_dbparser_type_to_generic_type(guint8 dbparser_type) { switch (dbparser_type) { case LEGACY_DBPARSER_TYPE_NUMBER: return LM_VT_INTEGER; case LEGACY_DBPARSER_TYPE_FLOAT: return LM_VT_DOUBLE; case LEGACY_DBPARSER_TYPE_STRING: case LEGACY_DBPARSER_TYPE_QSTRING: case LEGACY_DBPARSER_TYPE_ESTRING: case LEGACY_DBPARSER_TYPE_ANYSTRING: case LEGACY_DBPARSER_TYPE_SET: case LEGACY_DBPARSER_TYPE_OPTIONALSET: case LEGACY_DBPARSER_TYPE_PCRE: case LEGACY_DBPARSER_TYPE_EMAIL: case LEGACY_DBPARSER_TYPE_HOSTNAME: case LEGACY_DBPARSER_TYPE_NLSTRING: case LEGACY_DBPARSER_TYPE_IPV4: case LEGACY_DBPARSER_TYPE_IPV6: case LEGACY_DBPARSER_TYPE_IP: case LEGACY_DBPARSER_TYPE_LLADDR: case LEGACY_DBPARSER_TYPE_MACADDR: default: return LM_VT_STRING; } } /********************************************************************** * This chunk of code fixes up the NVHandle values scattered in a * deserialized NVTable. * * The reason they need fixing is that NVHandles are allocated dynamically * when they are first used in a syslog-ng process. As the serialized * representation of a LogMessage can be read back by another syslog-ng * process, its idea of the name-value pair handle might be different. * * This means that we need to iterate through the struct and change the * handle values. This is not even a simple operation as handles are embedded * in various locations * - in the index table, an array sorted by handle * - as indirect values that refer to other values * - the SDATA handles array that ensures that SDATA values are ordered * the same way they were received. * **********************************************************************/ static gint _index_entry_cmp(const void *a, const void *b) { NVIndexEntry *entry_a = (NVIndexEntry *) a; NVIndexEntry *entry_b = (NVIndexEntry *) b; NVHandle handle_a = entry_a->handle; NVHandle handle_b = entry_b->handle; if (handle_a < handle_b) return -1; else if (handle_a == handle_b) return 0; else return 1; } static void _copy_updated_sdata_handles(LogMessageSerializationState *state) { memcpy(state->msg->sdata, state->updated_sdata_handles, sizeof(state->msg->sdata[0]) * state->msg->num_sdata); } static void _sort_updated_index(LogMessageSerializationState *state) { NVTable *self = state->nvtable; qsort(state->updated_index, self->index_size, sizeof(NVIndexEntry), _index_entry_cmp); } static void _copy_updated_index(LogMessageSerializationState *state) { NVTable *self = state->nvtable; memmove(nv_table_get_index(self), state->updated_index, sizeof(NVIndexEntry) * self->index_size); } static void _fixup_sdata_handle(LogMessageSerializationState *state, NVHandle old_handle, NVHandle new_handle) { LogMessage *msg = state->msg; gint i; if (msg->sdata) { for (i = 0; i < msg->num_sdata; i++) { if (msg->sdata[i] == old_handle) { state->updated_sdata_handles[i] = new_handle; break; } } } } static void _fixup_handle_in_index_entry(LogMessageSerializationState *state, NVIndexEntry *index_entry, NVHandle new_handle) { gint index_slot = index_entry - nv_table_get_index(state->nvtable); NVIndexEntry *new_index_entry = &state->updated_index[index_slot]; new_index_entry->ofs = index_entry->ofs; new_index_entry->handle = new_handle; } static inline gboolean _is_static_entry(NVEntry *entry) { return entry->name_len == 0; } static gboolean _old_handle_has_the_same_name(NVHandle old_handle, NVEntry *entry) { gssize old_handle_name_len = 0; const gchar *old_handle_name = log_msg_get_value_name(old_handle, &old_handle_name_len); if (!old_handle_name) return FALSE; if (old_handle_name_len != entry->name_len) return FALSE; return memcmp(nv_entry_get_name(entry), old_handle_name, old_handle_name_len) == 0; } static NVHandle _allocate_handle_for_entry_name(NVHandle old_handle, NVEntry *entry) { if (_is_static_entry(entry)) return old_handle; if (_old_handle_has_the_same_name(old_handle, entry)) return old_handle; return log_msg_get_value_handle(nv_entry_get_name(entry)); } static NVHandle _allocate_handle_of_referenced_entry(NVTable *self, NVHandle ref_handle) { NVEntry *ref_entry = nv_table_get_entry(self, ref_handle, NULL, NULL); return _allocate_handle_for_entry_name(ref_handle, ref_entry); } static gboolean _is_indirect(NVEntry *entry) { return entry && entry->indirect; } static void _fixup_handle_in_indirect_entry(NVTable *self, NVEntry *entry) { entry->vindirect.handle = _allocate_handle_of_referenced_entry(self, entry->vindirect.handle); } static gboolean _validate_entry(LogMessageSerializationState *state, NVEntry *entry) { NVTable *nvtable = state->nvtable; /* check alignment */ if ((GPOINTER_TO_UINT(entry) & 0x3) != 0) return FALSE; /* entry points above the start of the NVTable */ if ((guint8 *)(entry) < (guint8 *)(nvtable)) return FALSE; /* entry header is inside the allocated NVTable */ if ((guint8 *)entry + NV_ENTRY_DIRECT_HDR > (guint8 *)nvtable + nvtable->size) return FALSE; /* entry as a whole is inside the allocated NVTable */ if ((guint8 *)entry + entry->alloc_len > ((guint8 *)nvtable + nvtable->size)) return FALSE; if (!entry->indirect) { if (entry->alloc_len < NV_ENTRY_DIRECT_HDR + entry->name_len + 1 + entry->vdirect.value_len + 1) return FALSE; } else { if (entry->alloc_len < NV_ENTRY_INDIRECT_HDR + entry->name_len + 1) return FALSE; } return TRUE; } static gboolean _update_entry(LogMessageSerializationState *state, NVEntry *entry) { if ((state->nvtable_flags & NVT_SUPPORTS_UNSET) == 0) { /* if this was serialized with a syslog-ng that didn't support unset or types, make sure that: * 1) only the bits that were present in that version might be set * 2) the rest of the bits are cleared * * This is needed as earlier syslog-ng versions unfortunately didn't * set the flags to 0, so it might contain garbage. Anything that is * past NVT_SUPPORTS_UNSET however sets these bits to zero to make * adding new flags easier. */ entry->flags = entry->flags & NVENTRY_FLAGS_DEFINED_IN_LEGACY_FORMATS; } if (!entry->type_present) { entry->type_present = TRUE; if (entry->indirect) { entry->type = log_msg_map_legacy_dbparser_type_to_generic_type(entry->vindirect.__deprecated_type_field); entry->vindirect.__deprecated_type_field = 0; } else entry->type = LM_VT_STRING; } if (entry->type_present && entry->type == __COMPAT_LM_VT_INT32) entry->type = LM_VT_INTEGER; return TRUE; } static gboolean _fixup_entry(NVHandle old_handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data) { LogMessageSerializationState *state = (LogMessageSerializationState *) user_data; NVTable *self = state->nvtable; NVHandle new_handle; if (!_validate_entry(state, entry) || !_update_entry(state, entry)) { /* this return of TRUE indicates failure, as it terminates the foreach loop */ return TRUE; } new_handle = _allocate_handle_for_entry_name(old_handle, entry); if (index_entry) _fixup_handle_in_index_entry(state, index_entry, new_handle); if (log_msg_is_handle_sdata(new_handle)) _fixup_sdata_handle(state, old_handle, new_handle); if (!state->handle_changed) state->handle_changed = (new_handle != old_handle); if (_is_indirect(entry)) _fixup_handle_in_indirect_entry(self, entry); return FALSE; } gboolean log_msg_fixup_handles_after_deserialization(LogMessageSerializationState *state) { LogMessage *msg = state->msg; NVTable *nvtable = state->nvtable; NVHandle _updated_sdata_handles[msg->num_sdata]; NVIndexEntry _updated_index[nvtable->index_size]; /* NOTE: we are allocating these arrays as auto variables on the stack, so * we can use some stack space here. However, num_sdata is guint8, * index_size is guint16 */ state->updated_sdata_handles = _updated_sdata_handles; state->updated_index = _updated_index; state->handle_changed = FALSE; if (nv_table_foreach_entry(nvtable, _fixup_entry, state)) { /* foreach_entry() returns TRUE if the callback returned failure */ return FALSE; } if (state->handle_changed) { _copy_updated_sdata_handles(state); _sort_updated_index(state); _copy_updated_index(state); } return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg-serialize-fixup.h000066400000000000000000000023001450431004300241630ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _LOGMSG_SERIALIZE_FIXUP_H_INCLUDED #define _LOGMSG_SERIALIZE_FIXUP_H_INCLUDED #include "logmsg/serialization.h" gboolean log_msg_fixup_handles_after_deserialization(LogMessageSerializationState *state); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg-serialize.c000066400000000000000000000333441450431004300230410ustar00rootroot00000000000000/* * Copyright (c) 2010-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmsg/logmsg-serialize.h" #include "logmsg/logmsg-serialize-fixup.h" #include "logmsg/nvtable-serialize.h" #include "logmsg/nvtable-serialize-legacy.h" #include "logmsg/gsockaddr-serialize.h" #include "logmsg/timestamp-serialize.h" #include "logmsg/tags-serialize.h" #include "messages.h" #include #define OLD_LMM_REF_MATCH 0x0001 static void _setup_ts_processed(UnixTime *timestamps, const UnixTime *processed) { if (processed != NULL) timestamps[LM_TS_PROCESSED] = *processed; else if (!unix_time_is_set(×tamps[LM_TS_PROCESSED])) timestamps[LM_TS_PROCESSED] = timestamps[LM_TS_RECVD]; } static void nv_table_serialize_with_compaction(LogMessageSerializationState *state, NVTable *old) { NVTable *payload; payload = nv_table_compact(old); nv_table_serialize(state, payload); nv_table_unref(payload); }; static gboolean _serialize_message(LogMessageSerializationState *state) { LogMessage *msg = state->msg; SerializeArchive *sa = state->sa; UnixTime timestamps[LM_TS_MAX]; memcpy(×tamps, msg->timestamps, LM_TS_MAX*sizeof(UnixTime)); _setup_ts_processed(timestamps, state->processed); serialize_write_uint8(sa, state->version); serialize_write_uint64(sa, msg->rcptid); g_assert(sizeof(msg->flags) == 4); serialize_write_uint32(sa, msg->flags & ~LF_STATE_MASK); serialize_write_uint16(sa, msg->pri); g_sockaddr_serialize(sa, msg->saddr); timestamp_serialize(sa, timestamps); serialize_write_uint32(sa, msg->host_id); tags_serialize(msg, sa); serialize_write_uint8(sa, msg->initial_parse); serialize_write_uint8(sa, msg->num_matches); serialize_write_uint8(sa, msg->num_sdata); serialize_write_uint8(sa, msg->alloc_sdata); serialize_write_uint32_array(sa, (guint32 *) msg->sdata, msg->num_sdata); if (state->flags & LMSF_COMPACTION) nv_table_serialize_with_compaction(state, msg->payload); else nv_table_serialize(state, msg->payload); return TRUE; } gboolean log_msg_serialize_with_ts_processed(LogMessage *self, SerializeArchive *sa, const UnixTime *processed, guint32 flags) { LogMessageSerializationState state = { 0 }; state.version = LGM_V26; state.msg = self; state.sa = sa; state.processed = processed; state.flags = flags; return _serialize_message(&state); } gboolean log_msg_serialize(LogMessage *self, SerializeArchive *sa, guint32 flags) { return log_msg_serialize_with_ts_processed(self, sa, NULL, flags); } static gboolean _deserialize_sdata(LogMessageSerializationState *state) { LogMessage *self = state->msg; SerializeArchive *sa = state->sa; if (!serialize_read_uint8(sa, &self->num_sdata)) return FALSE; if (!serialize_read_uint8(sa, &self->alloc_sdata)) return FALSE; g_assert(!self->sdata); self->sdata = (NVHandle *) g_malloc(sizeof(NVHandle)*self->alloc_sdata); if (state->version <= LGM_V20) return TRUE; if ((state->version < LGM_V26) && !serialize_read_uint16_array(sa, (guint32 *) self->sdata, self->num_sdata)) return FALSE; if ((state->version == LGM_V26) && !serialize_read_uint32_array(sa, (guint32 *) self->sdata, self->num_sdata)) return FALSE; return TRUE; } NVTable * _nv_table_deserialize_selector(LogMessageSerializationState *state) { if (state->version < LGM_V22) { state->nvtable = nv_table_deserialize_legacy(state->sa); return state->nvtable; } else if (state->version < LGM_V26) { state->nvtable = nv_table_deserialize_22(state->sa); return state->nvtable; } else if (state->version == LGM_V26) { return nv_table_deserialize(state); } return NULL; } static gboolean _deserialize_message_version_2x(LogMessageSerializationState *state) { g_assert(state->version >= LGM_V20); guint8 initial_parse = 0; LogMessage *msg = state->msg; SerializeArchive *sa = state->sa; if ((state->version > LGM_V22) && !serialize_read_uint64(sa, &msg->rcptid)) return FALSE; if (!serialize_read_uint32(sa, &msg->flags)) return FALSE; msg->flags |= LF_STATE_MASK; if (!serialize_read_uint16(sa, &msg->pri)) return FALSE; if (!g_sockaddr_deserialize(sa, &msg->saddr)) return FALSE; if (state->version < LGM_V24) { if (!timestamp_deserialize_legacy(sa, msg->timestamps)) return FALSE; msg->timestamps[LM_TS_PROCESSED] = msg->timestamps[LM_TS_RECVD]; } if ((state->version >= LGM_V24) && !timestamp_deserialize(sa, msg->timestamps)) return FALSE; if ((state->version >= LGM_V25) && (!serialize_read_uint32(sa, &msg->host_id))) return FALSE; if (!tags_deserialize(msg, sa)) return FALSE; if (!serialize_read_uint8(sa, &initial_parse)) return FALSE; msg->initial_parse=initial_parse; if (!serialize_read_uint8(sa, &msg->num_matches)) return FALSE; if (!_deserialize_sdata(state)) return FALSE; nv_table_unref(msg->payload); msg->payload = _nv_table_deserialize_selector(state); if (!msg->payload) return FALSE; if (!log_msg_fixup_handles_after_deserialization(state)) return FALSE; return TRUE; } static gboolean log_msg_read_tags(LogMessage *self, SerializeArchive *sa) { gchar *buf; gsize len; while (TRUE) { if (!serialize_read_cstring(sa, &buf, &len) || !buf) return FALSE; if (!buf[0]) { /* "" , empty string means: last tag */ g_free(buf); break; } log_msg_set_tag_by_name(self, buf); g_free(buf); } self->flags |= LF_STATE_OWN_TAGS; return TRUE; } /* Read the most common values (HOST, HOST_FROM, PROGRAM, MESSAGE) same for all version < 20 */ gboolean log_msg_read_common_values(LogMessage *self, SerializeArchive *sa) { gchar *host = NULL; gchar *host_from = NULL; gchar *program = NULL; gchar *message = NULL; gsize stored_len=0; if (!serialize_read_cstring(sa, &host, &stored_len)) return FALSE; log_msg_set_value(self, LM_V_HOST, host, stored_len); g_free(host); if (!serialize_read_cstring(sa, &host_from, &stored_len)) return FALSE; log_msg_set_value(self, LM_V_HOST_FROM, host_from, stored_len); g_free(host_from); if (!serialize_read_cstring(sa, &program, &stored_len)) return FALSE; log_msg_set_value(self, LM_V_PROGRAM, program, stored_len); g_free(program); if (!serialize_read_cstring(sa, &message, &stored_len)) return FALSE; log_msg_set_value(self, LM_V_MESSAGE, message, stored_len); g_free(message); return TRUE; } /* After the matches are read the details of those have to been read this process is same for version < 20 */ gboolean log_msg_read_matches_details(LogMessage *self, SerializeArchive *sa) { gint i; for (i = 0; i < self->num_matches; i++) { guint8 stored_flags; if (!serialize_read_uint8(sa, &stored_flags)) return FALSE; if (stored_flags & OLD_LMM_REF_MATCH) { guint8 type; guint16 ofs; guint16 len; guint8 builtin_value; guint8 LM_F_MAX = 8; if (!serialize_read_uint8(sa, &type) || !serialize_read_uint8(sa, &builtin_value) || builtin_value >= LM_F_MAX || !serialize_read_uint16(sa, &ofs) || !serialize_read_uint16(sa, &len)) return FALSE; log_msg_set_match_indirect_with_type(self, i, builtin_value, ofs, len, type); } else { gchar *match = NULL; gsize match_size; if (!serialize_read_cstring(sa, &match, &match_size)) return FALSE; log_msg_set_match(self, i, match, match_size); g_free(match); } } return TRUE; } static gboolean log_msg_read_values(LogMessage *self, SerializeArchive *sa) { gchar *name = NULL, *value = NULL; gboolean success = FALSE; if (!serialize_read_cstring(sa, &name, NULL) || !serialize_read_cstring(sa, &value, NULL)) goto error; while (name[0]) { log_msg_set_value(self, log_msg_get_value_handle(name), value, -1); name = value = NULL; if (!serialize_read_cstring(sa, &name, NULL) || !serialize_read_cstring(sa, &value, NULL)) goto error; } /* the terminating entries are not added to the hashtable, we need to free them */ success = TRUE; error: g_free(name); g_free(value); return success; } static gboolean log_msg_read_sd_param(SerializeArchive *sa, gchar *sd_element_name, LogMessage *self, gboolean *has_more) { gchar *name = NULL, *value = NULL; gsize name_len, value_len; gchar sd_param_name[256]= {0}; gboolean success = FALSE; if (!serialize_read_cstring(sa, &name, &name_len) || !serialize_read_cstring(sa, &value, &value_len)) goto error; if (name_len != 0 && value_len != 0) { gsize sd_element_name_len = g_strlcpy(sd_param_name, sd_element_name, sizeof(sd_param_name)); if (sd_element_name_len >= sizeof(sd_param_name)) goto error; g_strlcpy(sd_param_name + sd_element_name_len, name, sizeof(sd_param_name) - sd_element_name_len); log_msg_set_value(self, log_msg_get_value_handle(sd_param_name), value, value_len); *has_more = TRUE; } else { *has_more = FALSE; } success = TRUE; error: g_free(name); g_free(value); return success; } static gboolean log_msg_read_sd_element(SerializeArchive *sa, LogMessage *self, gboolean *has_more) { gchar *sd_id = NULL; gsize sd_id_len; gchar sd_element_root[66]= {0}; gboolean has_more_param = TRUE; if (!serialize_read_cstring(sa, &sd_id, &sd_id_len)) return FALSE; if (sd_id_len == 0) { *has_more=FALSE; g_free(sd_id); return TRUE; } strcpy(sd_element_root, logmsg_sd_prefix); /* sd_id + '.' + '\0' */ if (sd_id_len + 2 >= G_N_ELEMENTS(sd_element_root) - logmsg_sd_prefix_len) return FALSE; strncpy(sd_element_root + logmsg_sd_prefix_len, sd_id, sd_id_len); sd_element_root[logmsg_sd_prefix_len + sd_id_len]='.'; if (!log_msg_read_sd_param(sa, sd_element_root, self, &has_more_param)) goto error; while (has_more_param) { if (!log_msg_read_sd_param(sa, sd_element_root, self, &has_more_param)) goto error; } g_free(sd_id); *has_more = TRUE; return TRUE; error: g_free(sd_id); return FALSE; } static gboolean log_msg_read_sd_data(LogMessage *self, SerializeArchive *sa) { gboolean has_more_element = TRUE; if (!log_msg_read_sd_element(sa, self, &has_more_element)) goto error; while (has_more_element) { if (!log_msg_read_sd_element(sa, self, &has_more_element)) goto error; } return TRUE; error: return FALSE; } static gboolean _deserialize_message_version_1x(LogMessageSerializationState *state) { gsize stored_len; gchar *source, *pid; gchar *msgid; LogMessage *msg = state->msg; SerializeArchive *sa = state->sa; if(state->version == LGM_V10) { guint16 stored_flags16; if (!serialize_read_uint16(sa, &stored_flags16)) return FALSE; msg->flags = stored_flags16; } else { if (!serialize_read_uint32(sa, &msg->flags)) return FALSE; } msg->flags |= LF_STATE_MASK; if (!serialize_read_uint16(sa, &msg->pri)) return FALSE; if (!serialize_read_cstring(sa, &source, &stored_len)) return FALSE; log_msg_set_value(msg, LM_V_SOURCE, source, stored_len); g_free(source); if (!g_sockaddr_deserialize(sa, &msg->saddr)) return FALSE; if (!timestamp_deserialize_legacy(sa, msg->timestamps)) return FALSE; if(state->version == LGM_V12) { if (!log_msg_read_tags(msg, sa)) return FALSE; } if(!log_msg_read_common_values(msg, sa)) return FALSE; if (!serialize_read_cstring(sa, &pid, &stored_len)) return FALSE; log_msg_set_value(msg, LM_V_PID, pid, stored_len); g_free(pid); if (!serialize_read_cstring(sa, &msgid, &stored_len)) return FALSE; log_msg_set_value(msg, LM_V_MSGID, msgid, stored_len); g_free(msgid); if (!serialize_read_uint8(sa, &msg->num_matches)) return FALSE; if(!log_msg_read_matches_details(msg, sa)) return FALSE; if (!log_msg_read_values(msg, sa) || !log_msg_read_sd_data(msg, sa)) return FALSE; return TRUE; } static gboolean _check_msg_version(LogMessageSerializationState *state) { if (!serialize_read_uint8(state->sa, &state->version)) return FALSE; if (state->version < LGM_V10 || state->version > LGM_V26) { msg_error("Error deserializing log message, unsupported version", evt_tag_int("version", state->version)); return FALSE; } return TRUE; } gboolean log_msg_deserialize(LogMessage *self, SerializeArchive *sa) { LogMessageSerializationState state = { 0 }; state.sa = sa; state.msg = self; if (!_check_msg_version(&state)) { return FALSE; } if (state.version < LGM_V20) return _deserialize_message_version_1x(&state); return _deserialize_message_version_2x(&state); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg-serialize.h000066400000000000000000000045131450431004300230420ustar00rootroot00000000000000/* * Copyright (c) 2010-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGMSG_SERIALIZE_H #define LOGMSG_SERIALIZE_H #include "serialize.h" #include "timeutils/unixtime.h" /* * version info * 0 first introduced in syslog-ng-2.1 * 1 dropped self->date * 10 added support for values, * sd data, * syslog-protocol fields, * timestamps became 64 bits, * removed source group string * flags & pri became 16 bits * 11 flags became 32 bits * 12 store tags * 20 usage of the nvtable * 21 sdata serialization * 22 corrected nvtable serialization * 23 new RCTPID field (64 bits) * 24 new processed timestamp * 25 added hostid * 26 use 32 bit values nvtable */ enum _LogMessageVersion { LGM_V01 = 1, LGM_V10 = 10, LGM_V11 = 11, LGM_V12 = 12, LGM_V20 = 20, LGM_V21 = 21, LGM_V22 = 22, LGM_V23 = 23, LGM_V24 = 24, LGM_V25 = 25, LGM_V26 = 26 }; enum _LogMessageSerializationFlags { LMSF_COMPACTION = 0x0001, }; gboolean log_msg_deserialize(LogMessage *self, SerializeArchive *sa); gboolean log_msg_serialize_with_ts_processed(LogMessage *self, SerializeArchive *sa, const UnixTime *processed, guint32 flags); gboolean log_msg_serialize(LogMessage *self, SerializeArchive *sa, guint32 flags); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg.c000066400000000000000000001757541450431004300210700ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmsg/logmsg.h" #include "str-utils.h" #include "str-repr/encode.h" #include "messages.h" #include "logpipe.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include "logmsg/nvtable.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "template/templates.h" #include "tls-support.h" #include "compat/string.h" #include "rcptid.h" #include "template/macros.h" #include "host-id.h" #include "ack-tracker/ack_tracker.h" #include "apphook.h" #include #include #include #include #include #include #include #include /* * Reference/ACK counting for LogMessage structures * * Each LogMessage structure is allocated when received by a LogSource * instance, and then freed once all destinations finish with it. Since a * LogMessage is processed by different threads, reference counting must be * atomic. * * A similar counter is used to track when a given message is considered to * be delivered. In case flow-control is in use, the number of * to-be-expected ACKs are counted in an atomic variable. * * Code is written in a way, that it is explicitly mentioned whether a * function expects a reference (called "consuming" the ref), or whether it * gets a 'borrowed' reference (more common). Also, a function that returns * a LogMessage instance generally returns a reference too. * * Because of these rules, quite a number of refs/unrefs are being made * during the processing of a message, even though they wouldn't cause the * structure to be freed. Considering that ref/unref operations are * expensive atomic operations, these have a considerable overhead. * * The solution we employ in this module, is that we try to exploit the * fact, that each thread is usually working on a single LogMessage * instance, and once it is done with it, it fetches the next one, and so * on. In the LogReader/LogWriter cases, this usage pattern is quite * normal. * * Also, a quite similar usage pattern can be applied to the ACK counter * (the one which tracks how much flow-controlled destinations need to * confirm the deliver of the message). * * The solution implemented here is outlined below (and the same rules are * used for ACKs and REFs): * * - ACKs and REFs are put into the same 32 bit integer value, one half * is used for the ref counter, the other is used for the ACK counter * (see the macros LOGMSG_REFCACHE_ below) * * - The processing of a given message in a given thread is enclosed by * calls to log_msg_refcache_start() / log_msg_refcache_stop() * * - The calls to these functions is optional, if they are not called, * then normal atomic reference counting is performed * * - When refcache_start() is called, the atomic reference count is not * changed by log_msg_ref()/unref(). Rather, a per-thread variable is * used to count the _difference_ to the "would-be" value of the ref counter. * * - When refcache_stop() is called, the atomic reference counter is * updated as a single atomic operation. This means, that if a thread * calls refcache_start() early enough, then the ref/unref operations * performed by the given thread can be completely atomic-op free. * * - There's one catch: if the producer thread (e.g. LogReader), doesn't * add references to a consumer thread (e.g. LogWriter), and the * consumer doesn't use the refcache infrastructure, then the counters * could become negative (simply because the reader's real number of * references is not represented in the refcounter). This is solved by * adding a large-enough number (so called BIAS) to the ref counter in * refcache_start(), which ensures that all possible writers will see a * positive value. This is then subtracted in refcache_stop() the * same way as the other references. * * Since we use the same atomic variable to store two things, updating that * counter becomes somewhat more complicated, therefore a g_atomic_int_add() * doesn't suffice. We're using a CAS loop (compare-and-exchange) to do our * stuff, but that shouldn't have that much of an overhead. */ TLS_BLOCK_START { /* message that is being processed by the current thread. Its ack/ref changes are cached */ LogMessage *logmsg_current; /* whether the consumer is flow-controlled, (the producer always is) */ gboolean logmsg_cached_ack_needed; /* has to be signed as these can become negative */ /* number of cached refs by the current thread */ gint logmsg_cached_refs; /* number of cached acks by the current thread */ gint logmsg_cached_acks; /* abort flag in the current thread for acks */ gboolean logmsg_cached_abort; /* suspend flag in the current thread for acks */ gboolean logmsg_cached_suspend; } TLS_BLOCK_END; #define logmsg_current __tls_deref(logmsg_current) #define logmsg_cached_refs __tls_deref(logmsg_cached_refs) #define logmsg_cached_acks __tls_deref(logmsg_cached_acks) #define logmsg_cached_ack_needed __tls_deref(logmsg_cached_ack_needed) #define logmsg_cached_abort __tls_deref(logmsg_cached_abort) #define logmsg_cached_suspend __tls_deref(logmsg_cached_suspend) #define LOGMSG_REFCACHE_SUSPEND_SHIFT 31 /* number of bits to shift to get the SUSPEND flag */ #define LOGMSG_REFCACHE_SUSPEND_MASK 0x80000000 /* bit mask to extract the SUSPEND flag */ #define LOGMSG_REFCACHE_ABORT_SHIFT 30 /* number of bits to shift to get the ABORT flag */ #define LOGMSG_REFCACHE_ABORT_MASK 0x40000000 /* bit mask to extract the ABORT flag */ #define LOGMSG_REFCACHE_ACK_SHIFT 15 /* number of bits to shift to get the ACK counter */ #define LOGMSG_REFCACHE_ACK_MASK 0x3FFF8000 /* bit mask to extract the ACK counter */ #define LOGMSG_REFCACHE_REF_SHIFT 0 /* number of bits to shift to get the REF counter */ #define LOGMSG_REFCACHE_REF_MASK 0x00007FFF /* bit mask to extract the ACK counter */ #define LOGMSG_REFCACHE_BIAS 0x00002000 /* the BIAS we add to the ref counter in refcache_start */ #define LOGMSG_REFCACHE_REF_TO_VALUE(x) (((x) << LOGMSG_REFCACHE_REF_SHIFT) & LOGMSG_REFCACHE_REF_MASK) #define LOGMSG_REFCACHE_ACK_TO_VALUE(x) (((x) << LOGMSG_REFCACHE_ACK_SHIFT) & LOGMSG_REFCACHE_ACK_MASK) #define LOGMSG_REFCACHE_ABORT_TO_VALUE(x) (((x) << LOGMSG_REFCACHE_ABORT_SHIFT) & LOGMSG_REFCACHE_ABORT_MASK) #define LOGMSG_REFCACHE_SUSPEND_TO_VALUE(x) (((x) << LOGMSG_REFCACHE_SUSPEND_SHIFT) & LOGMSG_REFCACHE_SUSPEND_MASK) #define LOGMSG_REFCACHE_VALUE_TO_REF(x) (((x) & LOGMSG_REFCACHE_REF_MASK) >> LOGMSG_REFCACHE_REF_SHIFT) #define LOGMSG_REFCACHE_VALUE_TO_ACK(x) (((x) & LOGMSG_REFCACHE_ACK_MASK) >> LOGMSG_REFCACHE_ACK_SHIFT) #define LOGMSG_REFCACHE_VALUE_TO_ABORT(x) (((x) & LOGMSG_REFCACHE_ABORT_MASK) >> LOGMSG_REFCACHE_ABORT_SHIFT) #define LOGMSG_REFCACHE_VALUE_TO_SUSPEND(x) (((x) & LOGMSG_REFCACHE_SUSPEND_MASK) >> LOGMSG_REFCACHE_SUSPEND_SHIFT) /********************************************************************** * LogMessage **********************************************************************/ gboolean log_msg_is_handle_macro(NVHandle handle) { guint16 flags; flags = nv_registry_get_handle_flags(logmsg_registry, handle); return !!(flags & LM_VF_MACRO); } gboolean log_msg_is_handle_sdata(NVHandle handle) { guint16 flags; flags = nv_registry_get_handle_flags(logmsg_registry, handle); return !!(flags & LM_VF_SDATA); } gboolean log_msg_is_handle_match(NVHandle handle) { guint16 flags; flags = nv_registry_get_handle_flags(logmsg_registry, handle); return !!(flags & LM_VF_MATCH); } static inline gboolean log_msg_chk_flag(const LogMessage *self, gint32 flag) { return self->flags & flag; } static inline void log_msg_set_flag(LogMessage *self, gint32 flag) { self->flags |= flag; } static inline void log_msg_set_host_id(LogMessage *msg) { msg->host_id = host_id_get(); } /* the index matches the value id */ const gchar *builtin_value_names[] = { "HOST", "HOST_FROM", "MESSAGE", "PROGRAM", "PID", "MSGID", "SOURCE", "LEGACY_MSGHDR", "__RESERVED_LM_V_MAX", NULL, }; const gchar * log_msg_value_type_to_str(LogMessageValueType self) { g_assert(self <= LM_VT_NONE); static const gchar *as_str[] = { [LM_VT_STRING] = "string", [LM_VT_JSON] = "json", [LM_VT_BOOLEAN] = "boolean", [__COMPAT_LM_VT_INT32] = "compat-int32", [LM_VT_INTEGER] = "int", [LM_VT_DOUBLE] = "double", [LM_VT_DATETIME] = "datetime", [LM_VT_LIST] = "list", [LM_VT_NULL] = "null", [LM_VT_BYTES] = "bytes", [LM_VT_PROTOBUF] = "protobuf", [LM_VT_NONE] = "none", }; return as_str[self]; } gboolean log_msg_value_type_from_str(const gchar *in_str, LogMessageValueType *out_type) { if (strcmp(in_str, "string") == 0) *out_type = LM_VT_STRING; else if (strcmp(in_str, "json") == 0 || strcmp(in_str, "literal") == 0) *out_type = LM_VT_JSON; else if (strcmp(in_str, "boolean") == 0) *out_type = LM_VT_BOOLEAN; else if (strcmp(in_str, "int32") == 0 || strcmp(in_str, "int") == 0 || strcmp(in_str, "int64") == 0 || strcmp(in_str, "integer") == 0) *out_type = LM_VT_INTEGER; else if (strcmp(in_str, "double") == 0 || strcmp(in_str, "float") == 0) *out_type = LM_VT_DOUBLE; else if (strcmp(in_str, "datetime") == 0) *out_type = LM_VT_DATETIME; else if (strcmp(in_str, "list") == 0) *out_type = LM_VT_LIST; else if (strcmp(in_str, "null") == 0) *out_type = LM_VT_NULL; else if (strcmp(in_str, "bytes") == 0) *out_type = LM_VT_BYTES; else if (strcmp(in_str, "protobuf") == 0) *out_type = LM_VT_PROTOBUF; else if (strcmp(in_str, "none") == 0) *out_type = LM_VT_NONE; else return FALSE; return TRUE; }; static void __free_macro_value(void *val) { g_string_free((GString *) val, TRUE); } static NVHandle match_handles[256]; NVRegistry *logmsg_registry; const char logmsg_sd_prefix[] = ".SDATA."; const gint logmsg_sd_prefix_len = sizeof(logmsg_sd_prefix) - 1; gint logmsg_queue_node_max = 1; /* statistics */ static StatsCounterItem *count_msg_clones; static StatsCounterItem *count_payload_reallocs; static StatsCounterItem *count_sdata_updates; static StatsCounterItem *count_allocated_bytes; static GPrivate priv_macro_value = G_PRIVATE_INIT(__free_macro_value); void log_msg_write_protect(LogMessage *self) { self->write_protected = TRUE; } LogMessage * log_msg_make_writable(LogMessage **pself, const LogPathOptions *path_options) { if (log_msg_is_write_protected(*pself)) { LogMessage *new; new = log_msg_clone_cow(*pself, path_options); log_msg_unref(*pself); *pself = new; } return *pself; } static void log_msg_update_sdata_slow(LogMessage *self, NVHandle handle, const gchar *name, gssize name_len) { guint16 alloc_sdata; guint16 prefix_and_block_len; gint i; const gchar *dot; /* this was a structured data element, insert a ref to the sdata array */ stats_counter_inc(count_sdata_updates); if (self->num_sdata == 255) { msg_error("syslog-ng only supports 255 SD elements right now, just drop an email to the mailing list that it was not enough with your use-case so we can increase it"); return; } if (self->alloc_sdata <= self->num_sdata) { alloc_sdata = MAX(self->num_sdata + 1, STRICT_ROUND_TO_NEXT_EIGHT(self->num_sdata)); if (alloc_sdata > 255) alloc_sdata = 255; } else alloc_sdata = self->alloc_sdata; if (log_msg_chk_flag(self, LF_STATE_OWN_SDATA) && self->sdata) { if (self->alloc_sdata < alloc_sdata) { self->sdata = g_realloc(self->sdata, alloc_sdata * sizeof(self->sdata[0])); memset(&self->sdata[self->alloc_sdata], 0, (alloc_sdata - self->alloc_sdata) * sizeof(self->sdata[0])); } } else { NVHandle *sdata; sdata = g_malloc(alloc_sdata * sizeof(self->sdata[0])); if (self->num_sdata) memcpy(sdata, self->sdata, self->num_sdata * sizeof(self->sdata[0])); memset(&sdata[self->num_sdata], 0, sizeof(self->sdata[0]) * (self->alloc_sdata - self->num_sdata)); self->sdata = sdata; log_msg_set_flag(self, LF_STATE_OWN_SDATA); } guint16 old_alloc_sdata = self->alloc_sdata; self->alloc_sdata = alloc_sdata; if (self->sdata) { self->allocated_bytes += ((self->alloc_sdata - old_alloc_sdata) * sizeof(self->sdata[0])); stats_counter_add(count_allocated_bytes, (self->alloc_sdata - old_alloc_sdata) * sizeof(self->sdata[0])); } /* ok, we have our own SDATA array now which has at least one free slot */ if (!self->initial_parse) { dot = memrchr(name, '.', name_len); prefix_and_block_len = dot - name; for (i = self->num_sdata - 1; i >= 0; i--) { gssize sdata_name_len; const gchar *sdata_name; sdata_name_len = 0; sdata_name = log_msg_get_value_name(self->sdata[i], &sdata_name_len); if (sdata_name_len > prefix_and_block_len && strncmp(sdata_name, name, prefix_and_block_len) == 0) { /* ok we have found the last SDATA entry that has the same block */ break; } } i++; } else i = -1; if (i >= 0) { memmove(&self->sdata[i+1], &self->sdata[i], (self->num_sdata - i) * sizeof(self->sdata[0])); self->sdata[i] = handle; } else { self->sdata[self->num_sdata] = handle; } self->num_sdata++; } static inline void log_msg_update_sdata(LogMessage *self, NVHandle handle, const gchar *name, gssize name_len) { if (log_msg_is_handle_sdata(handle)) log_msg_update_sdata_slow(self, handle, name, name_len); } static inline void log_msg_update_num_matches(LogMessage *self, NVHandle handle) { if (log_msg_is_handle_match(handle)) { gint index_ = log_msg_get_match_index(handle); /* the whole between num_matches and the new index is emptied out to * avoid leaking of stale values */ for (gint i = self->num_matches; i < index_; i++) log_msg_unset_match(self, i); if (index_ >= self->num_matches) self->num_matches = index_ + 1; } } NVHandle log_msg_get_value_handle(const gchar *value_name) { NVHandle handle; handle = nv_registry_alloc_handle(logmsg_registry, value_name); /* check if name starts with sd_prefix and has at least one additional character */ if (strncmp(value_name, logmsg_sd_prefix, logmsg_sd_prefix_len) == 0 && value_name[6]) { nv_registry_set_handle_flags(logmsg_registry, handle, LM_VF_SDATA); } return handle; } gboolean log_msg_is_value_name_valid(const gchar *value) { if (strncmp(value, logmsg_sd_prefix, logmsg_sd_prefix_len) == 0) { const gchar *dot; int dot_found = 0; dot = strchr(value, '.'); while (dot && strlen(dot) > 1) { dot_found++; dot++; dot = strchr(dot, '.'); } return (dot_found >= 3); } else return TRUE; } const gchar * log_msg_get_macro_value(const LogMessage *self, gint id, gssize *value_len, LogMessageValueType *type) { GString *value; value = g_private_get(&priv_macro_value); if (!value) { value = g_string_sized_new(256); g_private_replace(&priv_macro_value, value); } g_string_truncate(value, 0); log_macro_expand_simple(id, self, value, type); if (value_len) *value_len = value->len; return value->str; } static void log_msg_init_queue_node(LogMessage *msg, LogMessageQueueNode *node, const LogPathOptions *path_options) { INIT_IV_LIST_HEAD(&node->list); node->ack_needed = path_options->ack_needed; node->flow_control_requested = path_options->flow_control_requested; node->msg = log_msg_ref(msg); } /* * Allocates a new LogMessageQueueNode instance to be enqueued in a * LogQueue. * * NOTE: Assumed to be running in the source thread, and that the same * LogMessage instance is only put into queue from the same thread (e.g. * the related fields are _NOT_ locked). */ LogMessageQueueNode * log_msg_alloc_queue_node(LogMessage *msg, const LogPathOptions *path_options) { LogMessageQueueNode *node; if (msg->cur_node < msg->num_nodes) { node = &msg->nodes[msg->cur_node++]; node->embedded = TRUE; } else { gint nodes = (volatile gint) logmsg_queue_node_max; /* this is a racy update, but it doesn't really hurt if we lose an * update or if we continue with a smaller value in parallel threads * for some time yet, since the smaller number only means that we * pre-allocate somewhat less LogMsgQueueNodes in the message * structure, but will be fine regardless (if we'd overflow the * pre-allocated space, we start allocating nodes dynamically from * heap. */ if (nodes < 32 && nodes <= msg->num_nodes) logmsg_queue_node_max = msg->num_nodes + 1; node = g_slice_new(LogMessageQueueNode); node->embedded = FALSE; } log_msg_init_queue_node(msg, node, path_options); return node; } LogMessageQueueNode * log_msg_alloc_dynamic_queue_node(LogMessage *msg, const LogPathOptions *path_options) { LogMessageQueueNode *node; node = g_slice_new(LogMessageQueueNode); node->embedded = FALSE; log_msg_init_queue_node(msg, node, path_options); return node; } void log_msg_free_queue_node(LogMessageQueueNode *node) { if (!node->embedded) g_slice_free(LogMessageQueueNode, node); } static gboolean _log_name_value_updates(LogMessage *self) { /* we don't log name value updates for internal messages that are * initialized at this point, as that may generate an endless recursion. * log_msg_new_internal() calling log_msg_set_value(), which in turn * generates an internal message, again calling log_msg_set_value() */ return (self->flags & LF_INTERNAL) == 0; } static inline gboolean _value_invalidates_legacy_header(NVHandle handle) { return handle == LM_V_PROGRAM || handle == LM_V_PID; } void log_msg_rename_value(LogMessage *self, NVHandle from, NVHandle to) { if (from == to) return; gssize value_len = 0; const gchar *value = log_msg_get_value_if_set(self, from, &value_len); if (!value) return; log_msg_set_value(self, to, value, value_len); log_msg_unset_value(self, from); } void log_msg_set_value_with_type(LogMessage *self, NVHandle handle, const gchar *value, gssize value_len, LogMessageValueType type) { const gchar *name; gssize name_len; gboolean new_entry = FALSE; g_assert(!log_msg_is_write_protected(self)); if (handle == LM_V_NONE) return; name_len = 0; name = log_msg_get_value_name(handle, &name_len); if (value_len < 0) value_len = strlen(value); if (_log_name_value_updates(self)) { msg_trace("Setting value", evt_tag_str("name", name), evt_tag_mem("value", value, value_len), evt_tag_str("type", log_msg_value_type_to_str(type)), evt_tag_msg_reference(self)); } if (!log_msg_chk_flag(self, LF_STATE_OWN_PAYLOAD)) { self->payload = nv_table_clone(self->payload, name_len + value_len + 2); log_msg_set_flag(self, LF_STATE_OWN_PAYLOAD); self->allocated_bytes += self->payload->size; stats_counter_add(count_allocated_bytes, self->payload->size); } /* we need a loop here as a single realloc may not be enough. Might help * if we pass how much bytes we need though. */ while (!nv_table_add_value(self->payload, handle, name, name_len, value, value_len, type, &new_entry)) { /* error allocating string in payload, reallocate */ guint32 old_size = self->payload->size; if (!nv_table_realloc(self->payload, &self->payload)) { /* can't grow the payload, it has reached the maximum size */ msg_info("Cannot store value for this log message, maximum size has been reached", evt_tag_int("maximum_payload", NV_TABLE_MAX_BYTES), evt_tag_str("name", name), evt_tag_printf("value", "%.32s%s", value, value_len > 32 ? "..." : "")); break; } guint32 new_size = self->payload->size; self->allocated_bytes += (new_size - old_size); stats_counter_add(count_allocated_bytes, new_size-old_size); stats_counter_inc(count_payload_reallocs); } if (new_entry) log_msg_update_sdata(self, handle, name, name_len); log_msg_update_num_matches(self, handle); if (_value_invalidates_legacy_header(handle)) log_msg_unset_value(self, LM_V_LEGACY_MSGHDR); } void log_msg_set_value(LogMessage *self, NVHandle handle, const gchar *value, gssize value_len) { log_msg_set_value_with_type(self, handle, value, value_len, LM_VT_STRING); } void log_msg_unset_value(LogMessage *self, NVHandle handle) { g_assert(!log_msg_is_write_protected(self)); if (!log_msg_chk_flag(self, LF_STATE_OWN_PAYLOAD)) { self->payload = nv_table_clone(self->payload, 0); log_msg_set_flag(self, LF_STATE_OWN_PAYLOAD); } while (!nv_table_unset_value(self->payload, handle)) { /* error allocating string in payload, reallocate */ guint32 old_size = self->payload->size; if (!nv_table_realloc(self->payload, &self->payload)) { /* can't grow the payload, it has reached the maximum size */ const gchar *name = log_msg_get_value_name(handle, NULL); msg_info("Cannot unset value for this log message, maximum size has been reached", evt_tag_int("maximum_payload", NV_TABLE_MAX_BYTES), evt_tag_str("name", name)); break; } guint32 new_size = self->payload->size; self->allocated_bytes += (new_size - old_size); stats_counter_add(count_allocated_bytes, new_size-old_size); stats_counter_inc(count_payload_reallocs); } if (_value_invalidates_legacy_header(handle)) log_msg_unset_value(self, LM_V_LEGACY_MSGHDR); } void log_msg_unset_value_by_name(LogMessage *self, const gchar *name) { log_msg_unset_value(self, log_msg_get_value_handle(name)); } void log_msg_set_value_indirect_with_type(LogMessage *self, NVHandle handle, NVHandle ref_handle, guint16 ofs, guint16 len, LogMessageValueType type) { const gchar *name; gssize name_len; gboolean new_entry = FALSE; g_assert(!log_msg_is_write_protected(self)); if (handle == LM_V_NONE) return; g_assert(handle >= LM_V_MAX); name_len = 0; name = log_msg_get_value_name(handle, &name_len); if (_log_name_value_updates(self)) { msg_trace("Setting indirect value", evt_tag_str("name", name), evt_tag_str("type", log_msg_value_type_to_str(type)), evt_tag_int("ref_handle", ref_handle), evt_tag_int("ofs", ofs), evt_tag_int("len", len), evt_tag_msg_reference(self)); } if (!log_msg_chk_flag(self, LF_STATE_OWN_PAYLOAD)) { self->payload = nv_table_clone(self->payload, name_len + 1); log_msg_set_flag(self, LF_STATE_OWN_PAYLOAD); } NVReferencedSlice referenced_slice = { .handle = ref_handle, .ofs = ofs, .len = len, }; while (!nv_table_add_value_indirect(self->payload, handle, name, name_len, &referenced_slice, type, &new_entry)) { /* error allocating string in payload, reallocate */ if (!nv_table_realloc(self->payload, &self->payload)) { /* error growing the payload, skip without storing the value */ msg_info("Cannot store referenced value for this log message, maximum size has been reached", evt_tag_str("name", name), evt_tag_str("ref-name", log_msg_get_value_name(ref_handle, NULL))); break; } stats_counter_inc(count_payload_reallocs); } if (new_entry) log_msg_update_sdata(self, handle, name, name_len); log_msg_update_num_matches(self, handle); } void log_msg_set_value_indirect(LogMessage *self, NVHandle handle, NVHandle ref_handle, guint16 ofs, guint16 len) { log_msg_set_value_indirect_with_type(self, handle, ref_handle, ofs, len, LM_VT_STRING); } gboolean log_msg_values_foreach(const LogMessage *self, NVTableForeachFunc func, gpointer user_data) { return nv_table_foreach(self->payload, logmsg_registry, func, user_data); } NVHandle log_msg_get_match_handle(gint index_) { if (index_ >= 0 && index_ < LOGMSG_MAX_MATCHES) return match_handles[index_]; return LM_V_NONE; } gint log_msg_get_match_index(NVHandle handle) { gint index_ = handle - match_handles[0]; g_assert(index_ >= 0 && index_ < LOGMSG_MAX_MATCHES); return index_; } void log_msg_set_match_with_type(LogMessage *self, gint index_, const gchar *value, gssize value_len, LogMessageValueType type) { if (index_ >= 0 && index_ < LOGMSG_MAX_MATCHES) log_msg_set_value_with_type(self, match_handles[index_], value, value_len, type); } void log_msg_set_match(LogMessage *self, gint index_, const gchar *value, gssize value_len) { log_msg_set_match_with_type(self, index_, value, value_len, LM_VT_STRING); } void log_msg_set_match_indirect_with_type(LogMessage *self, gint index_, NVHandle ref_handle, guint16 ofs, guint16 len, LogMessageValueType type) { if (index_ >= 0 && index_ < LOGMSG_MAX_MATCHES) log_msg_set_value_indirect_with_type(self, match_handles[index_], ref_handle, ofs, len, type); } void log_msg_set_match_indirect(LogMessage *self, gint index_, NVHandle ref_handle, guint16 ofs, guint16 len) { log_msg_set_match_indirect_with_type(self, index_, ref_handle, ofs, len, LM_VT_STRING); } const gchar * log_msg_get_match_if_set_with_type(const LogMessage *self, gint index_, gssize *value_len, LogMessageValueType *type) { if (index_ >= 0 && index_ < LOGMSG_MAX_MATCHES) return nv_table_get_value(self->payload, match_handles[index_], value_len, type); return NULL; } const gchar * log_msg_get_match_with_type(const LogMessage *self, gint index_, gssize *value_len, LogMessageValueType *type) { const gchar *result = log_msg_get_match_if_set_with_type(self, index_, value_len, type); if (result) return result; if (value_len) *value_len = 0; if (type) *type = LM_VT_NULL; return ""; } const gchar * log_msg_get_match(const LogMessage *self, gint index_, gssize *value_len) { return log_msg_get_match_with_type(self, index_, value_len, NULL); } void log_msg_unset_match(LogMessage *self, gint index_) { if (index_ >= 0 && index_ < LOGMSG_MAX_MATCHES) log_msg_unset_value(self, match_handles[index_]); } void log_msg_truncate_matches(LogMessage *self, gint n) { if (n < 0) n = 0; for (gint i = n; i < self->num_matches; i++) log_msg_unset_match(self, i); self->num_matches = n; } void log_msg_clear_matches(LogMessage *self) { log_msg_truncate_matches(self, 0); } #if GLIB_SIZEOF_LONG != GLIB_SIZEOF_VOID_P #error "The tags bit array assumes that long is the same size as the pointer" #endif #if GLIB_SIZEOF_LONG == 8 #define LOGMSG_TAGS_NDX_SHIFT 6 #define LOGMSG_TAGS_NDX_MASK 0x3F #define LOGMSG_TAGS_BITS 64 #elif GLIB_SIZEOF_LONG == 4 #define LOGMSG_TAGS_NDX_SHIFT 5 #define LOGMSG_TAGS_NDX_MASK 0x1F #define LOGMSG_TAGS_BITS 32 #else #error "Unsupported word length, only 32 or 64 bit platforms are supported" #endif static inline void log_msg_tags_foreach_item(const LogMessage *self, gint base, gulong item, LogMessageTagsForeachFunc callback, gpointer user_data) { gint i; for (i = 0; i < LOGMSG_TAGS_BITS; i++) { if (G_LIKELY(!item)) return; if (item & 1) { LogTagId id = (LogTagId) base + i; callback(self, id, log_tags_get_by_id(id), user_data); } item >>= 1; } } void log_msg_tags_foreach(const LogMessage *self, LogMessageTagsForeachFunc callback, gpointer user_data) { guint i; if (self->num_tags == 0) { log_msg_tags_foreach_item(self, 0, (gulong) self->tags, callback, user_data); } else { for (i = 0; i != self->num_tags; ++i) { log_msg_tags_foreach_item(self, i * LOGMSG_TAGS_BITS, self->tags[i], callback, user_data); } } } static inline void log_msg_set_bit(gulong *tags, gint index_, gboolean value) { if (value) tags[index_ >> LOGMSG_TAGS_NDX_SHIFT] |= ((gulong) (1UL << (index_ & LOGMSG_TAGS_NDX_MASK))); else tags[index_ >> LOGMSG_TAGS_NDX_SHIFT] &= ~((gulong) (1UL << (index_ & LOGMSG_TAGS_NDX_MASK))); } static inline gboolean log_msg_get_bit(gulong *tags, gint index_) { return !!(tags[index_ >> LOGMSG_TAGS_NDX_SHIFT] & ((gulong) (1UL << (index_ & LOGMSG_TAGS_NDX_MASK)))); } void log_msg_set_tag_by_id_onoff(LogMessage *self, LogTagId id, gboolean on) { gulong *old_tags; gint old_num_tags; gboolean inline_tags; g_assert(!log_msg_is_write_protected(self)); msg_trace("Setting tag", evt_tag_str("name", log_tags_get_by_id(id)), evt_tag_int("value", on), evt_tag_printf("msg", "%p", self)); if (!log_msg_chk_flag(self, LF_STATE_OWN_TAGS) && self->num_tags) { self->tags = g_memdup(self->tags, sizeof(self->tags[0]) * self->num_tags); } log_msg_set_flag(self, LF_STATE_OWN_TAGS); /* if num_tags is 0, it means that we use inline storage of tags */ inline_tags = self->num_tags == 0; if (inline_tags && id < LOGMSG_TAGS_BITS) { /* store this tag inline */ log_msg_set_bit((gulong *) &self->tags, id, on); } else { /* we can't put this tag inline, either because it is too large, or we don't have the inline space any more */ if ((self->num_tags * LOGMSG_TAGS_BITS) <= id) { if (G_UNLIKELY(8159 < id)) { msg_error("Maximum number of tags reached"); return; } old_num_tags = self->num_tags; self->num_tags = (id / LOGMSG_TAGS_BITS) + 1; old_tags = self->tags; if (old_num_tags) self->tags = g_realloc(self->tags, sizeof(self->tags[0]) * self->num_tags); else self->tags = g_malloc(sizeof(self->tags[0]) * self->num_tags); memset(&self->tags[old_num_tags], 0, (self->num_tags - old_num_tags) * sizeof(self->tags[0])); if (inline_tags) self->tags[0] = (gulong) old_tags; } log_msg_set_bit(self->tags, id, on); } if (on) { log_tags_inc_counter(id); } else { log_tags_dec_counter(id); } } void log_msg_set_tag_by_id(LogMessage *self, LogTagId id) { log_msg_set_tag_by_id_onoff(self, id, TRUE); } void log_msg_set_tag_by_name(LogMessage *self, const gchar *name) { log_msg_set_tag_by_id_onoff(self, log_tags_get_by_name(name), TRUE); } void log_msg_clear_tag_by_id(LogMessage *self, LogTagId id) { log_msg_set_tag_by_id_onoff(self, id, FALSE); } void log_msg_clear_tag_by_name(LogMessage *self, const gchar *name) { log_msg_set_tag_by_id_onoff(self, log_tags_get_by_name(name), FALSE); } gboolean log_msg_is_tag_by_id(LogMessage *self, LogTagId id) { if (G_UNLIKELY(8159 < id)) { msg_error("Invalid tag", evt_tag_int("id", (gint) id)); return FALSE; } if (self->num_tags == 0 && id < LOGMSG_TAGS_BITS) return log_msg_get_bit((gulong *) &self->tags, id); else if (id < self->num_tags * LOGMSG_TAGS_BITS) return log_msg_get_bit(self->tags, id); else return FALSE; } gboolean log_msg_is_tag_by_name(LogMessage *self, const gchar *name) { return log_msg_is_tag_by_id(self, log_tags_get_by_name(name)); } /* structured data elements */ static void log_msg_sdata_append_key_escaped(GString *result, const gchar *sstr, gssize len) { /* The specification does not have any way to escape keys. * The goal is to create syntactically valid structured data fields. */ const guchar *ustr = (const guchar *) sstr; for (gssize i = 0; i < len; i++) { if (!isascii(ustr[i]) || ustr[i] == '=' || ustr[i] == ' ' || ustr[i] == '[' || ustr[i] == ']' || ustr[i] == '"') { gchar hex_code[4]; g_sprintf(hex_code, "%%%02X", ustr[i]); g_string_append(result, hex_code); } else g_string_append_c(result, ustr[i]); } } static void log_msg_sdata_append_escaped(GString *result, const gchar *sstr, gssize len) { gint i; const guchar *ustr = (const guchar *) sstr; for (i = 0; i < len; i++) { if (ustr[i] == '"' || ustr[i] == '\\' || ustr[i] == ']') { g_string_append_c(result, '\\'); g_string_append_c(result, ustr[i]); } else g_string_append_c(result, ustr[i]); } } void log_msg_append_format_sdata(const LogMessage *self, GString *result, guint32 seq_num) { const gchar *value; const gchar *sdata_name, *sdata_elem, *sdata_param, *cur_elem = NULL, *dot; gssize sdata_name_len, sdata_elem_len, sdata_param_len, cur_elem_len = 0, len; gint i; static NVHandle meta_seqid = 0; gssize seqid_length; gboolean has_seq_num = FALSE; const gchar *seqid; if (!meta_seqid) meta_seqid = log_msg_get_value_handle(".SDATA.meta.sequenceId"); seqid = log_msg_get_value(self, meta_seqid, &seqid_length); APPEND_ZERO(seqid, seqid, seqid_length); if (seqid[0]) /* Message stores sequenceId */ has_seq_num = TRUE; else /* Message hasn't sequenceId */ has_seq_num = FALSE; for (i = 0; i < self->num_sdata; i++) { NVHandle handle = self->sdata[i]; guint16 handle_flags; gint sd_id_len; sdata_name_len = 0; sdata_name = log_msg_get_value_name(handle, &sdata_name_len); handle_flags = nv_registry_get_handle_flags(logmsg_registry, handle); value = log_msg_get_value_if_set(self, handle, &len); if (!value) continue; g_assert(handle_flags & LM_VF_SDATA); /* sdata_name always begins with .SDATA. */ g_assert(sdata_name_len > 6); sdata_elem = sdata_name + 7; sd_id_len = (handle_flags >> 8); if (sd_id_len) { dot = sdata_elem + sd_id_len; if (dot - sdata_name != sdata_name_len) { g_assert((dot - sdata_name < sdata_name_len) && *dot == '.'); } else { /* Standalone sdata e.g. [[UserData.updatelist@18372.4]] */ dot = NULL; } } else { dot = memrchr(sdata_elem, '.', sdata_name_len - 7); } if (G_LIKELY(dot)) { sdata_elem_len = dot - sdata_elem; sdata_param = dot + 1; sdata_param_len = sdata_name_len - (dot + 1 - sdata_name); } else { sdata_elem_len = sdata_name_len - 7; if (sdata_elem_len == 0) { sdata_elem = "none"; sdata_elem_len = 4; } sdata_param = ""; sdata_param_len = 0; } if (!cur_elem || sdata_elem_len != cur_elem_len || strncmp(cur_elem, sdata_elem, sdata_elem_len) != 0) { if (cur_elem) { /* close the previous block */ g_string_append_c(result, ']'); } /* the current SD block has changed, emit a start */ g_string_append_c(result, '['); log_msg_sdata_append_key_escaped(result, sdata_elem, sdata_elem_len); /* update cur_elem */ cur_elem = sdata_elem; cur_elem_len = sdata_elem_len; } /* if message hasn't sequenceId and the cur_elem is the meta block Append the sequenceId for the result if seq_num isn't 0 */ if (!has_seq_num && seq_num!=0 && strncmp(sdata_elem, "meta.", 5) == 0) { gchar sequence_id[16]; g_snprintf(sequence_id, sizeof(sequence_id), "%d", seq_num); g_string_append_c(result, ' '); g_string_append_len(result, "sequenceId=\"", 12); g_string_append_len(result, sequence_id, strlen(sequence_id)); g_string_append_c(result, '"'); has_seq_num = TRUE; } if (sdata_param_len) { if (value) { g_string_append_c(result, ' '); log_msg_sdata_append_key_escaped(result, sdata_param, sdata_param_len); g_string_append(result, "=\""); log_msg_sdata_append_escaped(result, value, len); g_string_append_c(result, '"'); } } } if (cur_elem) { g_string_append_c(result, ']'); } /* There was no meta block and if sequenceId must be added (seq_num!=0) create the whole meta block with sequenceId */ if (!has_seq_num && seq_num!=0) { gchar sequence_id[16]; g_snprintf(sequence_id, sizeof(sequence_id), "%d", seq_num); g_string_append_c(result, '['); g_string_append_len(result, "meta sequenceId=\"", 17); g_string_append_len(result, sequence_id, strlen(sequence_id)); g_string_append_len(result, "\"]", 2); } } void log_msg_format_sdata(const LogMessage *self, GString *result, guint32 seq_num) { g_string_truncate(result, 0); log_msg_append_format_sdata(self, result, seq_num); } gboolean log_msg_append_tags_callback(const LogMessage *self, LogTagId tag_id, const gchar *name, gpointer user_data) { GString *result = (GString *) ((gpointer *) user_data)[0]; gint original_length = GPOINTER_TO_UINT(((gpointer *) user_data)[1]); g_assert(result); if (result->len > original_length) g_string_append_c(result, ','); str_repr_encode_append(result, name, -1, ","); return TRUE; } void log_msg_format_tags(const LogMessage *self, GString *result) { gpointer args[] = { result, GUINT_TO_POINTER(result->len) }; log_msg_tags_foreach(self, log_msg_append_tags_callback, args); } void log_msg_format_matches(const LogMessage *self, GString *result) { gsize original_length = result->len; for (gint i = 1; i < self->num_matches; i++) { if (result->len > original_length) g_string_append_c(result, ','); gssize len; const gchar *m = log_msg_get_match(self, i, &len); str_repr_encode_append(result, m, len, ","); } } void log_msg_set_saddr(LogMessage *self, GSockAddr *saddr) { log_msg_set_saddr_ref(self, g_sockaddr_ref(saddr)); } void log_msg_set_saddr_ref(LogMessage *self, GSockAddr *saddr) { if (log_msg_chk_flag(self, LF_STATE_OWN_SADDR)) g_sockaddr_unref(self->saddr); self->saddr = saddr; self->flags |= LF_STATE_OWN_SADDR; } void log_msg_set_daddr(LogMessage *self, GSockAddr *daddr) { log_msg_set_daddr_ref(self, g_sockaddr_ref(daddr)); } void log_msg_set_daddr_ref(LogMessage *self, GSockAddr *daddr) { if (log_msg_chk_flag(self, LF_STATE_OWN_DADDR)) g_sockaddr_unref(self->daddr); self->daddr = daddr; self->flags |= LF_STATE_OWN_DADDR; } /** * log_msg_init: * @self: LogMessage instance * @saddr: sender address * * This function initializes a LogMessage instance without allocating it * first. It is used internally by the log_msg_new function. **/ static void log_msg_init(LogMessage *self) { GTimeVal tv; /* ref is set to 1, ack is set to 0 */ self->ack_and_ref_and_abort_and_suspended = LOGMSG_REFCACHE_REF_TO_VALUE(1); cached_g_current_time(&tv); self->timestamps[LM_TS_RECVD].ut_sec = tv.tv_sec; self->timestamps[LM_TS_RECVD].ut_usec = tv.tv_usec; self->timestamps[LM_TS_RECVD].ut_gmtoff = get_local_timezone_ofs(self->timestamps[LM_TS_RECVD].ut_sec); self->timestamps[LM_TS_STAMP] = self->timestamps[LM_TS_RECVD]; unix_time_unset(&self->timestamps[LM_TS_PROCESSED]); self->sdata = NULL; self->saddr = NULL; self->daddr = NULL; self->original = NULL; self->flags |= LF_STATE_OWN_MASK; self->pri = LOG_USER | LOG_NOTICE; self->rcptid = rcptid_generate_id(); log_msg_set_host_id(self); } void log_msg_clear(LogMessage *self) { if(log_msg_chk_flag(self, LF_STATE_OWN_PAYLOAD)) nv_table_unref(self->payload); self->payload = nv_table_new(LM_V_MAX, 16, 256); if (log_msg_chk_flag(self, LF_STATE_OWN_TAGS) && self->tags) { gboolean inline_tags = self->num_tags == 0; if (inline_tags) self->tags = NULL; else memset(self->tags, 0, self->num_tags * sizeof(self->tags[0])); } else { self->tags = NULL; self->num_tags = 0; } log_msg_clear_matches(self); if (!log_msg_chk_flag(self, LF_STATE_OWN_SDATA)) { self->sdata = NULL; self->alloc_sdata = 0; } self->num_sdata = 0; if (log_msg_chk_flag(self, LF_STATE_OWN_SADDR)) g_sockaddr_unref(self->saddr); self->saddr = NULL; if (log_msg_chk_flag(self, LF_STATE_OWN_DADDR)) g_sockaddr_unref(self->daddr); self->daddr = NULL; /* clear "local", "utf8", "internal", "mark" and similar flags, we start afresh */ self->flags = LF_STATE_OWN_MASK; } static inline LogMessage * log_msg_alloc(gsize payload_size) { LogMessage *msg; gsize payload_space = payload_size ? nv_table_get_alloc_size(LM_V_MAX, 16, payload_size) : 0; gsize alloc_size, payload_ofs = 0; /* NOTE: logmsg_node_max is updated from parallel threads without locking. */ gint nodes = (volatile gint) logmsg_queue_node_max; alloc_size = sizeof(LogMessage) + sizeof(LogMessageQueueNode) * nodes; /* align to 8 boundary */ if (payload_size) { alloc_size = (alloc_size + 7) & ~7; payload_ofs = alloc_size; alloc_size += payload_space; } msg = g_malloc(alloc_size); memset(msg, 0, sizeof(LogMessage)); if (payload_size) msg->payload = nv_table_init_borrowed(((gchar *) msg) + payload_ofs, payload_space, LM_V_MAX); msg->num_nodes = nodes; msg->allocated_bytes = alloc_size + payload_space; stats_counter_add(count_allocated_bytes, msg->allocated_bytes); return msg; } static gboolean _merge_value(NVHandle handle, const gchar *name, const gchar *value, gssize value_len, LogMessageValueType type, gpointer user_data) { LogMessage *msg = (LogMessage *) user_data; if (!nv_table_is_value_set(msg->payload, handle)) log_msg_set_value_with_type(msg, handle, value, value_len, type); return FALSE; } void log_msg_merge_context(LogMessage *self, LogMessage **context, gsize context_len) { gint i; for (i = context_len - 1; i >= 0; i--) { LogMessage *msg_to_be_merged = context[i]; log_msg_values_foreach(msg_to_be_merged, _merge_value, self); } } static void log_msg_clone_ack(LogMessage *msg, AckType ack_type) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; g_assert(msg->original); path_options.ack_needed = TRUE; log_msg_ack(msg->original, &path_options, ack_type); } /* * log_msg_clone_cow: * * Clone a copy-on-write (cow) copy of a log message. */ LogMessage * log_msg_clone_cow(LogMessage *msg, const LogPathOptions *path_options) { LogMessage *self = log_msg_alloc(0); gsize allocated_bytes = self->allocated_bytes; stats_counter_inc(count_msg_clones); log_msg_write_protect(msg); memcpy(self, msg, sizeof(*msg)); msg->allocated_bytes = allocated_bytes; msg_trace("Message was cloned", evt_tag_printf("original_msg", "%p", msg), evt_tag_msg_reference(self)); /* every field _must_ be initialized explicitly if its direct * copying would cause problems (like copying a pointer by value) */ /* reference the original message */ self->original = log_msg_ref(msg); self->ack_and_ref_and_abort_and_suspended = LOGMSG_REFCACHE_REF_TO_VALUE(1) + LOGMSG_REFCACHE_ACK_TO_VALUE( 0) + LOGMSG_REFCACHE_ABORT_TO_VALUE(0); self->cur_node = 0; self->write_protected = FALSE; log_msg_add_ack(self, path_options); if (!path_options->ack_needed) { self->ack_func = NULL; } else { self->ack_func = log_msg_clone_ack; } self->flags &= ~(LF_STATE_MASK - LF_STATE_CLONED_MASK); if (self->num_tags == 0) self->flags |= LF_STATE_OWN_TAGS; return self; } LogMessage * log_msg_sized_new(gsize payload_size) { LogMessage *self = log_msg_alloc(payload_size); log_msg_init(self); return self; } LogMessage * log_msg_new_empty(void) { return log_msg_sized_new(256); } /* This function creates a new log message that should be considered local */ LogMessage * log_msg_new_local(void) { LogMessage *self = log_msg_new_empty(); self->flags |= LF_LOCAL; return self; } /** * log_msg_new_internal: * @prio: message priority (LOG_*) * @msg: message text * @flags: parse flags (LP_*) * * This function creates a new log message for messages originating * internally to syslog-ng **/ LogMessage * log_msg_new_internal(gint prio, const gchar *msg) { gchar buf[32]; LogMessage *self; g_snprintf(buf, sizeof(buf), "%d", (int) getpid()); self = log_msg_new_local(); self->flags |= LF_INTERNAL; self->initial_parse = TRUE; log_msg_set_value(self, LM_V_PROGRAM, "syslog-ng", 9); log_msg_set_value(self, LM_V_PID, buf, -1); log_msg_set_value(self, LM_V_MESSAGE, msg, -1); self->initial_parse = FALSE; self->pri = prio; return self; } /** * log_msg_new_mark: * * This function returns a new MARK message. MARK messages have the LF_MARK * flag set. **/ LogMessage * log_msg_new_mark(void) { LogMessage *self = log_msg_new_local(); log_msg_set_value(self, LM_V_MESSAGE, "-- MARK --", 10); self->pri = LOG_SYSLOG | LOG_INFO; self->flags |= LF_MARK | LF_INTERNAL; return self; } /** * log_msg_free: * @self: LogMessage instance * * Frees a LogMessage instance. **/ static void log_msg_free(LogMessage *self) { if (log_msg_chk_flag(self, LF_STATE_OWN_PAYLOAD) && self->payload) nv_table_unref(self->payload); if (log_msg_chk_flag(self, LF_STATE_OWN_TAGS) && self->tags && self->num_tags > 0) g_free(self->tags); if (log_msg_chk_flag(self, LF_STATE_OWN_SDATA) && self->sdata) g_free(self->sdata); if (log_msg_chk_flag(self, LF_STATE_OWN_SADDR)) g_sockaddr_unref(self->saddr); if (log_msg_chk_flag(self, LF_STATE_OWN_DADDR)) g_sockaddr_unref(self->daddr); if (self->original) log_msg_unref(self->original); stats_counter_sub(count_allocated_bytes, self->allocated_bytes); g_free(self); } /** * log_msg_drop: * @msg: LogMessage instance * @path_options: path specific options * * This function is called whenever a destination driver feels that it is * unable to process this message. It acks and unrefs the message. **/ void log_msg_drop(LogMessage *msg, const LogPathOptions *path_options, AckType ack_type) { log_msg_ack(msg, path_options, ack_type); log_msg_unref(msg); } static AckType _ack_and_ref_and_abort_and_suspend_to_acktype(gint value) { AckType type = AT_PROCESSED; if (IS_SUSPENDFLAG_ON(LOGMSG_REFCACHE_VALUE_TO_SUSPEND(value))) type = AT_SUSPENDED; else if (IS_ABORTFLAG_ON(LOGMSG_REFCACHE_VALUE_TO_ABORT(value))) type = AT_ABORTED; return type; } /*************************************************************************************** * In order to read & understand this code, reading the comment on the top * of this file about ref/ack handling is strongly recommended. ***************************************************************************************/ /* Function to update the combined ACK (with the abort flag) and REF counter. */ static inline gint log_msg_update_ack_and_ref_and_abort_and_suspended(LogMessage *self, gint add_ref, gint add_ack, gint add_abort, gint add_suspend) { gint old_value, new_value; do { new_value = old_value = (volatile gint) self->ack_and_ref_and_abort_and_suspended; new_value = (new_value & ~LOGMSG_REFCACHE_REF_MASK) + LOGMSG_REFCACHE_REF_TO_VALUE( (LOGMSG_REFCACHE_VALUE_TO_REF( old_value) + add_ref)); new_value = (new_value & ~LOGMSG_REFCACHE_ACK_MASK) + LOGMSG_REFCACHE_ACK_TO_VALUE( (LOGMSG_REFCACHE_VALUE_TO_ACK( old_value) + add_ack)); new_value = (new_value & ~LOGMSG_REFCACHE_ABORT_MASK) + LOGMSG_REFCACHE_ABORT_TO_VALUE((LOGMSG_REFCACHE_VALUE_TO_ABORT( old_value) | add_abort)); new_value = (new_value & ~LOGMSG_REFCACHE_SUSPEND_MASK) + LOGMSG_REFCACHE_SUSPEND_TO_VALUE(( LOGMSG_REFCACHE_VALUE_TO_SUSPEND(old_value) | add_suspend)); } while (!g_atomic_int_compare_and_exchange(&self->ack_and_ref_and_abort_and_suspended, old_value, new_value)); return old_value; } /* Function to update the combined ACK (without abort) and REF counter. */ static inline gint log_msg_update_ack_and_ref(LogMessage *self, gint add_ref, gint add_ack) { return log_msg_update_ack_and_ref_and_abort_and_suspended(self, add_ref, add_ack, 0, 0); } /** * log_msg_ref: * @self: LogMessage instance * * Increment reference count of @self and return the new reference. **/ LogMessage * log_msg_ref(LogMessage *self) { gint old_value; if (G_LIKELY(logmsg_current == self)) { /* fastpath, @self is the current message, ref/unref processing is * delayed until log_msg_refcache_stop() is called */ logmsg_cached_refs++; return self; } /* slow path, refcache is not used, do the ordinary way */ old_value = log_msg_update_ack_and_ref(self, 1, 0); g_assert(LOGMSG_REFCACHE_VALUE_TO_REF(old_value) >= 1); return self; } /** * log_msg_unref: * @self: LogMessage instance * * Decrement reference count and free self if the reference count becomes 0. **/ void log_msg_unref(LogMessage *self) { gint old_value; if (G_LIKELY(logmsg_current == self)) { /* fastpath, @self is the current message, ref/unref processing is * delayed until log_msg_refcache_stop() is called */ logmsg_cached_refs--; return; } old_value = log_msg_update_ack_and_ref(self, -1, 0); g_assert(LOGMSG_REFCACHE_VALUE_TO_REF(old_value) >= 1); if (LOGMSG_REFCACHE_VALUE_TO_REF(old_value) == 1) { log_msg_free(self); } } /** * log_msg_add_ack: * @m: LogMessage instance * * This function increments the number of required acknowledges. **/ void log_msg_add_ack(LogMessage *self, const LogPathOptions *path_options) { if (path_options->ack_needed) { if (G_LIKELY(logmsg_current == self)) { /* fastpath, @self is the current message, add_ack/ack processing is * delayed until log_msg_refcache_stop() is called */ logmsg_cached_acks++; logmsg_cached_ack_needed = TRUE; return; } log_msg_update_ack_and_ref(self, 0, 1); } } /** * log_msg_ack: * @msg: LogMessage instance * @path_options: path specific options * @acked: TRUE: positive ack, FALSE: negative ACK * * Indicate that the message was processed successfully and the sender can * queue further messages. **/ void log_msg_ack(LogMessage *self, const LogPathOptions *path_options, AckType ack_type) { gint old_value; if (path_options->ack_needed) { if (G_LIKELY(logmsg_current == self)) { /* fastpath, @self is the current message, add_ack/ack processing is * delayed until log_msg_refcache_stop() is called */ logmsg_cached_acks--; logmsg_cached_abort |= IS_ACK_ABORTED(ack_type); logmsg_cached_suspend |= IS_ACK_SUSPENDED(ack_type); return; } old_value = log_msg_update_ack_and_ref_and_abort_and_suspended(self, 0, -1, IS_ACK_ABORTED(ack_type), IS_ACK_SUSPENDED(ack_type)); if (LOGMSG_REFCACHE_VALUE_TO_ACK(old_value) == 1) { if (ack_type == AT_SUSPENDED) self->ack_func(self, AT_SUSPENDED); else if (ack_type == AT_ABORTED) self->ack_func(self, AT_ABORTED); else self->ack_func(self, _ack_and_ref_and_abort_and_suspend_to_acktype(old_value)); } } } /* * Break out of an acknowledgement chain. The incoming message is * ACKed and a new path options structure is returned that can be used * to send to further consuming pipes. */ const LogPathOptions * log_msg_break_ack(LogMessage *msg, const LogPathOptions *path_options, LogPathOptions *local_options) { /* NOTE: in case the user requested flow control, we can't break the * ACK chain, as that would lead to early acks, that would cause * message loss */ g_assert(!path_options->flow_control_requested); log_msg_ack(msg, path_options, AT_PROCESSED); *local_options = *path_options; local_options->ack_needed = FALSE; return local_options; } /* * Start caching ref/unref/ack/add-ack operations in the current thread for * the message specified by @self. See the comment at the top of this file * for more information. * * This function is to be called by the producer thread (e.g. the one * that generates new messages). You should use * log_msg_refcache_start_consumer() in consumer threads instead. * * This function cannot be called for the same message from multiple * threads. * */ void log_msg_refcache_start_producer(LogMessage *self) { g_assert(logmsg_current == NULL); logmsg_current = self; /* we're the producer of said message, and thus we want to inhibit * freeing/acking it due to our cached refs, add a bias large enough * to cover any possible unrefs/acks of the consumer side */ /* we don't need to be thread-safe here, as a producer has just created this message and no parallel access is yet possible */ self->ack_and_ref_and_abort_and_suspended = (self->ack_and_ref_and_abort_and_suspended & ~LOGMSG_REFCACHE_REF_MASK) + LOGMSG_REFCACHE_REF_TO_VALUE((LOGMSG_REFCACHE_VALUE_TO_REF(self->ack_and_ref_and_abort_and_suspended) + LOGMSG_REFCACHE_BIAS)); self->ack_and_ref_and_abort_and_suspended = (self->ack_and_ref_and_abort_and_suspended & ~LOGMSG_REFCACHE_ACK_MASK) + LOGMSG_REFCACHE_ACK_TO_VALUE((LOGMSG_REFCACHE_VALUE_TO_ACK(self->ack_and_ref_and_abort_and_suspended) + LOGMSG_REFCACHE_BIAS)); logmsg_cached_refs = -LOGMSG_REFCACHE_BIAS; logmsg_cached_acks = -LOGMSG_REFCACHE_BIAS; logmsg_cached_abort = FALSE; logmsg_cached_suspend = FALSE; logmsg_cached_ack_needed = TRUE; } /* * Start caching ref/unref/ack/add-ack operations in the current thread for * the message specified by @self. See the comment at the top of this file * for more information. * * This function is to be called by the consumer threads (e.g. the * ones that consume messages). * * This function can be called from multiple consumer threads at the * same time, even for the same message. * */ void log_msg_refcache_start_consumer(LogMessage *self, const LogPathOptions *path_options) { g_assert(logmsg_current == NULL); logmsg_current = self; logmsg_cached_ack_needed = path_options->ack_needed; logmsg_cached_refs = 0; logmsg_cached_acks = 0; logmsg_cached_abort = FALSE; logmsg_cached_suspend = FALSE; } /* * Stop caching ref/unref/ack/add-ack operations in the current thread for * the message specified by the log_msg_refcache_start() function. * * See the comment at the top of this file for more information. */ void log_msg_refcache_stop(void) { gint old_value; gint current_cached_acks; gboolean current_cached_abort; gboolean current_cached_suspend; g_assert(logmsg_current != NULL); /* validate that we didn't overflow the counters: * * Both counters must be: * * - at least 1 smaller than the bias, rationale: * * - if we are caching "bias" number of refs, it may happen * that there are bias number of unrefs, potentially running * in consumer threads * * - if the potential unrefs is larger than the bias value, it may * happen that the producer sets the bias (trying to avoid * the freeing of the LogMessage), but still it gets freed. * * - not smaller than the "-bias" value, rationale: * - if we are caching "bias" number of unrefs the same can happen * as with the ref case. * */ g_assert((logmsg_cached_acks < LOGMSG_REFCACHE_BIAS - 1) && (logmsg_cached_acks >= -LOGMSG_REFCACHE_BIAS)); g_assert((logmsg_cached_refs < LOGMSG_REFCACHE_BIAS - 1) && (logmsg_cached_refs >= -LOGMSG_REFCACHE_BIAS)); /* * We fold the differences in ack/ref counts in three stages: * * 1) we take a ref of logmsg_current, this is needed so that the * message is not freed until we return from refcache_stop() * * 2) we add in all the diffs that were accumulated between * refcache_start and refcache_stop. This gets us a final value of the * ack counter, ref must be >= as we took a ref ourselves. * * 3) we call the ack handler if needed, this might change ref counters * recursively (but not ack counters as that already atomically * dropped to zero) * * 4) drop the ref we took in step 1) above * * 4) then we fold in the net ref results of the ack callback and * refcache_stop() combined. This either causes the LogMessage to be * freed (when we were the last), or it stays around because of other * refs. */ /* 1) take ref */ log_msg_ref(logmsg_current); /* 2) fold in ref/ack counter diffs into the atomic value */ current_cached_acks = logmsg_cached_acks; logmsg_cached_acks = 0; current_cached_abort = logmsg_cached_abort; logmsg_cached_abort = FALSE; current_cached_suspend = logmsg_cached_suspend; logmsg_cached_suspend = FALSE; old_value = log_msg_update_ack_and_ref_and_abort_and_suspended(logmsg_current, 0, current_cached_acks, current_cached_abort, current_cached_suspend); if ((LOGMSG_REFCACHE_VALUE_TO_ACK(old_value) == -current_cached_acks) && logmsg_cached_ack_needed) { AckType ack_type_cumulated = _ack_and_ref_and_abort_and_suspend_to_acktype(old_value); if (current_cached_suspend) ack_type_cumulated = AT_SUSPENDED; else if (current_cached_abort) ack_type_cumulated = AT_ABORTED; /* 3) call the ack handler */ logmsg_current->ack_func(logmsg_current, ack_type_cumulated); /* the ack callback may not change the ack counters, it already * dropped to zero atomically, changing that again is an error */ g_assert(logmsg_cached_acks == 0); } /* 4) drop our own ref */ log_msg_unref(logmsg_current); /* 5) fold the combined result of our own ref/unref and ack handler's results */ old_value = log_msg_update_ack_and_ref(logmsg_current, logmsg_cached_refs, 0); if (LOGMSG_REFCACHE_VALUE_TO_REF(old_value) == -logmsg_cached_refs) log_msg_free(logmsg_current); logmsg_cached_refs = 0; logmsg_current = NULL; } void log_msg_registry_init(void) { gint i; logmsg_registry = nv_registry_new(builtin_value_names, NVHANDLE_MAX_VALUE); nv_registry_add_alias(logmsg_registry, LM_V_MESSAGE, "MSG"); nv_registry_add_alias(logmsg_registry, LM_V_MESSAGE, "MSGONLY"); nv_registry_add_alias(logmsg_registry, LM_V_HOST, "FULLHOST"); nv_registry_add_alias(logmsg_registry, LM_V_HOST_FROM, "FULLHOST_FROM"); for (i = 0; macros[i].name; i++) { if (nv_registry_get_handle(logmsg_registry, macros[i].name) == 0) { NVHandle handle; handle = nv_registry_alloc_handle(logmsg_registry, macros[i].name); nv_registry_set_handle_flags(logmsg_registry, handle, (macros[i].id << 8) + LM_VF_MACRO); } } /* register $0 - $255 in order */ for (i = 0; i < LOGMSG_MAX_MATCHES; i++) { gchar buf[8]; g_snprintf(buf, sizeof(buf), "%d", i); match_handles[i] = nv_registry_alloc_handle(logmsg_registry, buf); nv_registry_set_handle_flags(logmsg_registry, match_handles[i], (i << 8) + LM_VF_MATCH); } } void log_msg_registry_deinit(void) { nv_registry_free(logmsg_registry); logmsg_registry = NULL; } void log_msg_registry_foreach(GHFunc func, gpointer user_data) { nv_registry_foreach(logmsg_registry, func, user_data); } static void log_msg_register_stats(void) { stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "msg_clones", NULL ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &count_msg_clones); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "payload_reallocs", NULL ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &count_payload_reallocs); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "sdata_updates", NULL ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &count_sdata_updates); stats_cluster_single_key_set(&sc_key, "events_allocated_bytes", NULL, 0); stats_cluster_single_key_add_legacy_alias(&sc_key, SCS_GLOBAL, "msg_allocated_bytes", NULL); stats_register_counter(1, &sc_key, SC_TYPE_SINGLE_VALUE, &count_allocated_bytes); stats_unlock(); } void log_msg_global_init(void) { log_msg_registry_init(); /* NOTE: we always initialize counters as they are on stats-level(0), * however we need to defer that as the stats subsystem may not be * operational yet */ register_application_hook(AH_RUNNING, (ApplicationHookFunc) log_msg_register_stats, NULL, AHM_RUN_ONCE); } const gchar * log_msg_get_handle_name(NVHandle handle, gssize *length) { return nv_registry_get_handle_name(logmsg_registry, handle, length); } void log_msg_global_deinit(void) { log_msg_registry_deinit(); } gint log_msg_lookup_time_stamp_name(const gchar *name) { if (strcmp(name, "stamp") == 0) return LM_TS_STAMP; else if (strcmp(name, "recvd") == 0) return LM_TS_RECVD; return -1; } gssize log_msg_get_size(LogMessage *self) { if (!self) return 0; return sizeof(LogMessage) + // msg.static fields + self->alloc_sdata * sizeof(self->sdata[0]) + g_sockaddr_len(self->saddr) + g_sockaddr_len(self->daddr) + ((self->num_tags) ? sizeof(self->tags[0]) * self->num_tags : 0) + nv_table_get_memory_consumption(self->payload); // msg.payload (nvtable) } #ifdef __linux__ const gchar * __log_msg_get_value(const LogMessage *self, NVHandle handle, gssize *value_len) __attribute__((alias("log_msg_get_value"))); const gchar * __log_msg_get_value_by_name(const LogMessage *self, const gchar *name, gssize *value_len) __attribute__((alias("log_msg_get_value_by_name"))); void __log_msg_set_value_by_name(LogMessage *self, const gchar *name, const gchar *value, gssize length) __attribute__((alias("log_msg_set_value_by_name"))); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/logmsg.h000066400000000000000000000465241450431004300210650ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGMSG_H_INCLUDED #define LOGMSG_H_INCLUDED #include "syslog-ng.h" #include "gsockaddr.h" #include "atomic.h" #include "serialize.h" #include "timeutils/unixtime.h" #include "logmsg/nvtable.h" #include "logmsg/tags.h" #include "messages.h" #include #include #include #include #include typedef enum { AT_UNDEFINED, AT_PROCESSED, AT_ABORTED, AT_SUSPENDED } AckType; #define IS_ACK_ABORTED(x) ((x) == AT_ABORTED ? 1 : 0) #define IS_ABORTFLAG_ON(x) ((x) == 1 ? TRUE : FALSE) #define IS_ACK_SUSPENDED(x) ((x) == AT_SUSPENDED ? 1 : 0) #define IS_SUSPENDFLAG_ON(x) ((x) == 1 ? TRUE : FALSE) #define STRICT_ROUND_TO_NEXT_EIGHT(x) ((x + 8) & ~7) typedef struct _LogPathOptions LogPathOptions; typedef void (*LMAckFunc)(LogMessage *lm, AckType ack_type); #define LOGMSG_MAX_MATCHES 256 typedef enum { LM_TS_STAMP = 0, LM_TS_RECVD = 1, LM_TS_PROCESSED = 2, LM_TS_MAX } LogMessageTimeStamp; /* builtin values */ enum { LM_V_NONE, LM_V_HOST, LM_V_HOST_FROM, LM_V_MESSAGE, LM_V_PROGRAM, LM_V_PID, LM_V_MSGID, LM_V_SOURCE, LM_V_LEGACY_MSGHDR, /* NOTE: this is used as the number of "statically" allocated elements in * an NVTable. NVTable may impose restrictions on this value (for * instance had to be an even number earlier). So be sure to validate * whether LM_V_MAX would fit NVTable if you add further enums here. */ LM_V_MAX, }; enum { LM_VF_SDATA = 0x0001, LM_VF_MATCH = 0x0002, LM_VF_MACRO = 0x0004, }; enum { /* these flags also matter when the message is serialized */ LF_OLD_UNPARSED = 0x0001, /* message payload is guaranteed to be valid utf8 */ LF_UTF8 = 0x0001, /* message was generated from within syslog-ng, doesn't matter if it came from the internal() source */ LF_INTERNAL = 0x0002, /* message was received on a local transport, e.g. it was generated on the local machine */ LF_LOCAL = 0x0004, /* message is a MARK mode */ LF_MARK = 0x0008, /* state flags that only matter during syslog-ng runtime and never * when a message is serialized */ LF_STATE_MASK = 0xFFF0, LF_STATE_OWN_PAYLOAD = 0x0010, LF_STATE_OWN_SADDR = 0x0020, LF_STATE_OWN_DADDR = 0x0040, LF_STATE_OWN_TAGS = 0x0080, LF_STATE_OWN_SDATA = 0x0100, LF_STATE_OWN_MASK = 0x01F0, /* part of the state that is kept across clones */ LF_STATE_CLONED_MASK = 0xFE00, LF_STATE_TRACING = 0x0200, LF_CHAINED_HOSTNAME = 0x00010000, /* NOTE: this flag is now unused. The original intent was to save whether * LEGACY_MSGHDR was saved by the parser code. Now we simply check * whether the length of ${LEGACY_MSGHDR} is non-zero. This used to be a * slow operation (when name-value pairs were stored in a hashtable), now * it is much faster. Also, this makes it possible to reproduce a message * entirely based on name-value pairs. Without this change, even if * LEGACY_MSGHDR was transferred (e.g. ewmm), the other side couldn't * reproduce the original message, as this flag was not transferred. * * The flag remains here for documentation, and also because it is serialized in disk-buffers */ __UNUSED_LF_LEGACY_MSGHDR = 0x00020000, }; typedef NVType LogMessageValueType; enum _LogMessageValueType { /* Everything is represented as a string, formatted in a type specific * automatically parseable format. * * Please note that these values are part of the serialized LogMessage * format, so changing these would cause incompatibilities in type * recognition. Add new types at the end. */ LM_VT_STRING = 0, LM_VT_JSON = 1, LM_VT_BOOLEAN = 2, __COMPAT_LM_VT_INT32 = 3, __COMPAT_LM_VT_INT64 = 4, LM_VT_INTEGER = 4, /* equals to LM_VT_INT64 */ LM_VT_DOUBLE = 5, LM_VT_DATETIME = 6, LM_VT_LIST = 7, LM_VT_NULL = 8, LM_VT_BYTES = 9, LM_VT_PROTOBUF = 10, /* extremal value to indicate "unset" state. * * NOTE: THIS IS NOT THE DEFAULT for actual values even if type is * unspecified, those cases default to LM_VT_STRING. */ LM_VT_NONE = 255 }; const gchar *log_msg_value_type_to_str(LogMessageValueType self); gboolean log_msg_value_type_from_str(const gchar *in_str, LogMessageValueType *out_type); typedef struct _LogMessageQueueNode { struct iv_list_head list; LogMessage *msg; guint ack_needed:1, embedded:1, flow_control_requested:1; } LogMessageQueueNode; /* NOTE: the members are ordered according to the presumed use frequency. * The structure itself is 2 cachelines, the border is right after the "msg" * member */ struct _LogMessage { /* if you change any of the fields here, be sure to adjust * log_msg_clone_cow() as well to initialize fields properly */ /* ack_and_ref_and_abort_and_suspended is a 32 bit integer that is accessed in an atomic way. * The upper half contains the ACK count (and the abort flag), the lower half * the REF count. It is not a GAtomicCounter as due to ref/ack caching it has * a lot of magic behind its implementation. See the logmsg.c file, around * log_msg_ref/unref. */ /* FIXME: the structure has holes, but right now it's 1 byte short to make * it smaller (it is possible to create a 7 byte contiguos block but 8 * byte alignment is needed. Let's check this with the inline-tags stuff */ gint ack_and_ref_and_abort_and_suspended; /* NOTE: in theory this should be a size_t (or gsize), however that takes * 8 bytes, and it's highly unlikely that we'd be using more than 4GB for * a LogMessage */ guint allocated_bytes; guint32 recvd_rawmsg_size; AckRecord *ack_record; LMAckFunc ack_func; LogMessage *original; /* message parts */ /* the contents of the members below is directly copied into another * LogMessage with pointer values. To change any of the fields please use * log_msg_set_*() functions, which will handle borrowed data members * correctly. */ /* ==== start of directly copied part ==== */ UnixTime timestamps[LM_TS_MAX]; gulong *tags; NVHandle *sdata; GSockAddr *saddr; GSockAddr *daddr; NVTable *payload; guint32 flags; guint16 pri; guint8 initial_parse:1, recursed:1, /* NOTE: proto is just 6 bits wide, but with that it fills a hole * not taking any tolls on the structure size. Realistically, we'd * be storing IPPROTO_UDP and TCP in there, which fits the 6 bits. * This is closely related to saddr/daddr and indicates the IP * protocol that was used to deliver the datagram carrying this * LogMessage. */ proto:6; guint8 num_matches; guint32 host_id; guint64 rcptid; guint8 num_tags; guint8 alloc_sdata; guint8 num_sdata; /* ==== end of directly copied part ==== */ guint8 num_nodes; guint8 cur_node; guint8 write_protected; /* preallocated LogQueueNodes used to insert this message into a LogQueue */ LogMessageQueueNode nodes[0]; /* a preallocated space for the initial NVTable (payload) may follow */ }; extern NVRegistry *logmsg_registry; extern const char logmsg_sd_prefix[]; extern const gint logmsg_sd_prefix_len; extern gint logmsg_node_max; LogMessage *log_msg_ref(LogMessage *m); void log_msg_unref(LogMessage *m); void log_msg_write_protect(LogMessage *m); static inline gboolean log_msg_is_write_protected(const LogMessage *self) { return self->write_protected; } LogMessage *log_msg_clone_cow(LogMessage *msg, const LogPathOptions *path_options); LogMessage *log_msg_make_writable(LogMessage **pmsg, const LogPathOptions *path_options); gboolean log_msg_write(LogMessage *self, SerializeArchive *sa); gboolean log_msg_read(LogMessage *self, SerializeArchive *sa); /* generic values that encapsulate log message fields, dynamic values and structured data */ NVHandle log_msg_get_value_handle(const gchar *value_name); gboolean log_msg_is_value_name_valid(const gchar *value); gboolean log_msg_is_handle_macro(NVHandle handle); gboolean log_msg_is_handle_sdata(NVHandle handle); gboolean log_msg_is_handle_match(NVHandle handle); /* * This macros allows the caching of a NVHandle (e.g. the numeric * identifier of a name-value pair) in a static variable. This simplifies * call sites by * 1) not needed an extra initialization step to look up the handle, _or_ * 2) not having to open code a similar caching mechanism. * * NOTE: that the check itself is racy and there might be two threads * executing the if() at the same time, and if they do they would _both_ * perform log_msg_get_value_handle(). The reason is that this is not a * problem is that the handles are constant within the same execution, so * both the winner and loser of the race would eventually set the cache to * the right value. And albeit this 2nd lookup is unnecessary, this would * happen only a limited number of times (until the variables becomes * visible for all CPUs), from which point on there's no race. */ #define LOG_MSG_GET_VALUE_HANDLE_STATIC(name) \ ({ \ static NVHandle __log_msg_value_handle = 0; \ \ if (G_UNLIKELY(!__log_msg_value_handle)) \ __log_msg_value_handle = log_msg_get_value_handle(name); \ __log_msg_value_handle; \ }) static inline gboolean log_msg_is_handle_referencable_from_an_indirect_value(NVHandle handle) { if (handle == LM_V_NONE) return FALSE; /* macro values should not be referenced as they are dynamic, store the actual value instead */ if (log_msg_is_handle_macro(handle)) return FALSE; /* matches are pretty temporary, so we should not reference them, as the * next matching operation would overwrite them anyway */ if (log_msg_is_handle_match(handle)) return FALSE; return TRUE; } static inline gboolean log_msg_is_handle_settable_with_an_indirect_value(NVHandle handle) { return (handle >= LM_V_MAX); } const gchar *log_msg_get_macro_value(const LogMessage *self, gint id, gssize *value_len, LogMessageValueType *type); const gchar *log_msg_get_match_with_type(const LogMessage *self, gint index_, gssize *value_len, LogMessageValueType *type); const gchar *log_msg_get_match_if_set_with_type(const LogMessage *self, gint index_, gssize *value_len, LogMessageValueType *type); static inline const gchar * log_msg_get_value_if_set_with_type(const LogMessage *self, NVHandle handle, gssize *value_len, LogMessageValueType *type) { guint16 flags; flags = nv_registry_get_handle_flags(logmsg_registry, handle); if (G_UNLIKELY((flags & LM_VF_MACRO))) return log_msg_get_macro_value(self, flags >> 8, value_len, type); else return nv_table_get_value(self->payload, handle, value_len, type); } static inline const gchar * log_msg_get_value_with_type(const LogMessage *self, NVHandle handle, gssize *value_len, LogMessageValueType *type) { const gchar *result = log_msg_get_value_if_set_with_type(self, handle, value_len, type); if (result) return result; if (type) *type = LM_VT_NULL; if (value_len) *value_len = 0; return ""; } static inline const gchar * log_msg_get_value(const LogMessage *self, NVHandle handle, gssize *value_len) { return log_msg_get_value_with_type(self, handle, value_len, NULL); } static inline const gchar * log_msg_get_value_if_set(const LogMessage *self, NVHandle handle, gssize *value_len) { return log_msg_get_value_if_set_with_type(self, handle, value_len, NULL); } static inline const gchar * log_msg_get_value_by_name(const LogMessage *self, const gchar *name, gssize *value_len) { NVHandle handle = log_msg_get_value_handle(name); return log_msg_get_value(self, handle, value_len); } static inline const gchar * log_msg_get_value_by_name_with_type(const LogMessage *self, const gchar *name, gssize *value_len, LogMessageValueType *type) { NVHandle handle = log_msg_get_value_handle(name); return log_msg_get_value_with_type(self, handle, value_len, type); } static inline const gchar * log_msg_get_value_name(NVHandle handle, gssize *name_len) { return nv_registry_get_handle_name(logmsg_registry, handle, name_len); } typedef gboolean (*LogMessageTagsForeachFunc)(const LogMessage *self, LogTagId tag_id, const gchar *name, gpointer user_data); void log_msg_set_value(LogMessage *self, NVHandle handle, const gchar *new_value, gssize length); void log_msg_set_value_with_type(LogMessage *self, NVHandle handle, const gchar *value, gssize value_len, LogMessageValueType type); void log_msg_set_value_indirect(LogMessage *self, NVHandle handle, NVHandle ref_handle, guint16 ofs, guint16 len); void log_msg_set_value_indirect_with_type(LogMessage *self, NVHandle handle, NVHandle ref_handle, guint16 ofs, guint16 len, LogMessageValueType type); void log_msg_unset_value(LogMessage *self, NVHandle handle); void log_msg_unset_value_by_name(LogMessage *self, const gchar *name); gboolean log_msg_values_foreach(const LogMessage *self, NVTableForeachFunc func, gpointer user_data); NVHandle log_msg_get_match_handle(gint index_); gint log_msg_get_match_index(NVHandle handle); void log_msg_set_match(LogMessage *self, gint index, const gchar *value, gssize value_len); void log_msg_set_match_with_type(LogMessage *self, gint index, const gchar *value, gssize value_len, LogMessageValueType type); void log_msg_set_match_indirect(LogMessage *self, gint index, NVHandle ref_handle, guint16 ofs, guint16 len); void log_msg_set_match_indirect_with_type(LogMessage *self, gint index, NVHandle ref_handle, guint16 ofs, guint16 len, LogMessageValueType type); void log_msg_unset_match(LogMessage *self, gint index_); const gchar *log_msg_get_match_with_type(const LogMessage *self, gint index_, gssize *value_len, LogMessageValueType *type); const gchar *log_msg_get_match(const LogMessage *self, gint index_, gssize *value_len); void log_msg_clear_matches(LogMessage *self); void log_msg_truncate_matches(LogMessage *self, gint n); static inline void log_msg_set_value_by_name_with_type(LogMessage *self, const gchar *name, const gchar *value, gssize length, LogMessageValueType type) { NVHandle handle = log_msg_get_value_handle(name); log_msg_set_value_with_type(self, handle, value, length, type); } static inline void log_msg_set_value_by_name(LogMessage *self, const gchar *name, const gchar *value, gssize length) { log_msg_set_value_by_name_with_type(self, name, value, length, LM_VT_STRING); } void log_msg_rename_value(LogMessage *self, NVHandle from, NVHandle to); void log_msg_append_format_sdata(const LogMessage *self, GString *result, guint32 seq_num); void log_msg_format_sdata(const LogMessage *self, GString *result, guint32 seq_num); void log_msg_set_tag_by_id_onoff(LogMessage *self, LogTagId id, gboolean on); void log_msg_set_tag_by_id(LogMessage *self, LogTagId id); void log_msg_set_tag_by_name(LogMessage *self, const gchar *name); void log_msg_clear_tag_by_id(LogMessage *self, LogTagId id); void log_msg_clear_tag_by_name(LogMessage *self, const gchar *name); gboolean log_msg_is_tag_by_id(LogMessage *self, LogTagId id); gboolean log_msg_is_tag_by_name(LogMessage *self, const gchar *name); void log_msg_tags_foreach(const LogMessage *self, LogMessageTagsForeachFunc callback, gpointer user_data); void log_msg_format_tags(const LogMessage *self, GString *result); void log_msg_format_matches(const LogMessage *self, GString *result); static inline void log_msg_set_recvd_rawmsg_size(LogMessage *self, guint32 size) { self->recvd_rawmsg_size = size; } void log_msg_set_saddr(LogMessage *self, GSockAddr *saddr); void log_msg_set_saddr_ref(LogMessage *self, GSockAddr *saddr); void log_msg_set_daddr(LogMessage *self, GSockAddr *daddr); void log_msg_set_daddr_ref(LogMessage *self, GSockAddr *daddr); LogMessageQueueNode *log_msg_alloc_queue_node(LogMessage *msg, const LogPathOptions *path_options); LogMessageQueueNode *log_msg_alloc_dynamic_queue_node(LogMessage *msg, const LogPathOptions *path_options); void log_msg_free_queue_node(LogMessageQueueNode *node); void log_msg_clear(LogMessage *self); void log_msg_merge_context(LogMessage *self, LogMessage **context, gsize context_len); LogMessage *log_msg_sized_new(gsize payload_size); LogMessage *log_msg_new_mark(void); LogMessage *log_msg_new_internal(gint prio, const gchar *msg); LogMessage *log_msg_new_empty(void); LogMessage *log_msg_new_local(void); void log_msg_add_ack(LogMessage *msg, const LogPathOptions *path_options); void log_msg_ack(LogMessage *msg, const LogPathOptions *path_options, AckType ack_type); void log_msg_drop(LogMessage *msg, const LogPathOptions *path_options, AckType ack_type); const LogPathOptions *log_msg_break_ack(LogMessage *msg, const LogPathOptions *path_options, LogPathOptions *local_options); void log_msg_refcache_start_producer(LogMessage *self); void log_msg_refcache_start_consumer(LogMessage *self, const LogPathOptions *path_options); void log_msg_refcache_stop(void); void log_msg_registry_init(void); void log_msg_registry_deinit(void); void log_msg_global_init(void); void log_msg_global_deinit(void); void log_msg_stats_global_init(void); void log_msg_registry_foreach(GHFunc func, gpointer user_data); gint log_msg_lookup_time_stamp_name(const gchar *name); gssize log_msg_get_size(LogMessage *self); #define evt_tag_msg_reference(msg) \ evt_tag_printf("msg", "%p", (msg)), \ evt_tag_printf("rcptid", "%" G_GUINT64_FORMAT, (msg)->rcptid) static inline EVTTAG * evt_tag_msg_value(const gchar *name, LogMessage *msg, NVHandle value_handle) { gssize value_len; const gchar *value = log_msg_get_value(msg, value_handle, &value_len); return evt_tag_mem(name, value, value_len); } static inline EVTTAG * evt_tag_msg_value_name(const gchar *name, NVHandle value_handle) { const gchar *value_name = log_msg_get_value_name(value_handle, NULL); return evt_tag_str(name, value_name); } #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvhandle-descriptors.c000066400000000000000000000043351450431004300237200ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "string.h" #include "nvhandle-descriptors.h" #include "syslog-ng.h" NVHandleDescArray * nvhandle_desc_array_new(guint reserved_size) { NVHandleDescArray *self = g_new0(NVHandleDescArray, 1); self->data = g_new0(NVHandleDesc, reserved_size); self->allocated_len = reserved_size; self->old_buffers = g_ptr_array_new_with_free_func(g_free); return self; } void nvhandle_desc_array_free(NVHandleDescArray *self) { for (gint i=0; i < self->len; ++i) { NVHandleDesc *handle = (NVHandleDesc *)&self->data[i]; nvhandle_desc_free(handle); } g_free(self->data); g_ptr_array_free(self->old_buffers, TRUE); g_free(self); } static void nvhandle_desc_array_expand(NVHandleDescArray *self) { guint new_alloc = self->allocated_len * 2; NVHandleDesc *new_data = g_new(NVHandleDesc, new_alloc); g_assert(new_data); memcpy(new_data, self->data, self->len * sizeof(NVHandleDesc)); g_ptr_array_add(self->old_buffers, self->data); self->data = new_data; self->allocated_len = new_alloc; } void nvhandle_desc_array_append(NVHandleDescArray *self, NVHandleDesc *desc) { if (self->len == self->allocated_len) nvhandle_desc_array_expand(self); self->data[self->len] = *desc; self->len++; } void nvhandle_desc_free(NVHandleDesc *self) { g_free(self->name); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvhandle-descriptors.h000066400000000000000000000032721450431004300237240ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef NVHANDLE_DESCRIPTORS_H_INCLUDED #define NVHANDLE_DESCRIPTORS_H_INCLUDED #include "syslog-ng.h" typedef struct _NVHandleDesc NVHandleDesc; struct _NVHandleDesc { gchar *name; guint16 flags; guint8 name_len; }; typedef struct { NVHandleDesc *data; guint len; guint allocated_len; GPtrArray *old_buffers; } NVHandleDescArray; #define NVHANDLE_DESC_ARRAY_INITIAL_SIZE 256 NVHandleDescArray *nvhandle_desc_array_new(guint reserved_size); void nvhandle_desc_array_free(NVHandleDescArray *self); void nvhandle_desc_array_append(NVHandleDescArray *self, NVHandleDesc *desc); #define nvhandle_desc_array_index(self, i) (((NVHandleDesc*) (self)->data) [(i)]) /* Does not free *self*. */ void nvhandle_desc_free(NVHandleDesc *self); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable-serialize-endianutils.h000066400000000000000000000063701450431004300255250ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2012-2015 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef NVTABLE_SERIALIZE_ENDIANUTILS_H_ #define NVTABLE_SERIALIZE_ENDIANUTILS_H_ static inline guint8 reverse(guint8 b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; b = (b & 0xAA) >> 1 | (b & 0x55) << 1; return b; } static inline void nv_table_swap_entry_flags(NVEntry *entry) { entry->flags = reverse(entry->flags); } static inline void nv_entry_swap_bytes(NVEntry *entry) { nv_table_swap_entry_flags(entry); entry->alloc_len = GUINT32_SWAP_LE_BE(entry->alloc_len); if (!entry->indirect) { entry->vdirect.value_len = GUINT32_SWAP_LE_BE(entry->vdirect.value_len); } else { entry->vindirect.handle = GUINT32_SWAP_LE_BE(entry->vindirect.handle); entry->vindirect.ofs = GUINT32_SWAP_LE_BE(entry->vindirect.ofs); entry->vindirect.len = GUINT32_SWAP_LE_BE(entry->vindirect.len); } } static inline void nv_table_dyn_value_swap_bytes(NVIndexEntry *self) { self->handle = GUINT32_SWAP_LE_BE(self->handle); self->ofs = GUINT32_SWAP_LE_BE(self->handle); }; static inline void nv_table_data_swap_bytes(NVTable *self) { NVIndexEntry *index_table; NVEntry *entry; gint i; for (i = 0; i < self->num_static_entries; i++) { entry = nv_table_get_entry_at_ofs(self, self->static_entries[i]); if (!entry) continue; nv_entry_swap_bytes(entry); } index_table = nv_table_get_index(self); for (i = 0; i < self->index_size; i++) { entry = nv_table_get_entry_at_ofs(self, index_table[i].ofs); if (!entry) continue; nv_entry_swap_bytes(entry); } } static inline void nv_table_struct_swap_bytes(NVTable *self) { guint16 i; NVIndexEntry *index_table; self->size = GUINT16_SWAP_LE_BE(self->size); self->used = GUINT16_SWAP_LE_BE(self->used); self->index_size = GUINT16_SWAP_LE_BE(self->index_size); for (i = 0; i < self->num_static_entries; i++) { self->static_entries[i] = GUINT16_SWAP_LE_BE(self->static_entries[i]); } index_table = nv_table_get_index(self); for (i = 0; i < self->index_size; i++) { nv_table_dyn_value_swap_bytes(&index_table[i]); } } #endif /* NVTABLE_SERIALIZE_ENDIANUTILS_H_ */ syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable-serialize-legacy.c000066400000000000000000000312301450431004300244360ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2012-2013 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "nvtable-serialize-legacy.h" #include "nvtable-serialize-endianutils.h" #include "nvtable-serialize.h" #include "syslog-ng.h" #include #define NV_TABLE_OLD_SCALE 2 #define NV_TABLE_MAGIC_V2 "NVT2" static const int NV_TABLE_HEADER_DIFF_V22_V26 = 4; static const int NV_TABLE_DYNVALUE_DIFF_V22_V26 = 4; static const int NV_TABLE_HANDLE_DIFF_V22_V26 = 2; static const int SIZE_DIFF_OF_OLD_NVENTRY_AND_NEW_NVENTRY = 12; #define NVT_SF_BE 0x1 typedef struct _OldNVEntry { /* negative offset, counting from string table top, e.g. start of the string is at @top + ofs */ union { struct { guint8 indirect:1, referenced:1; }; guint8 flags; }; guint8 name_len; guint16 alloc_len; union { struct { guint16 value_len; /* variable data, first the name of this entry, then the value, both are NUL terminated */ gchar data[0]; } vdirect; struct { guint16 handle; guint16 ofs; guint16 len; guint8 type; gchar name[0]; } vindirect; }; } OldNVEntry; typedef struct _OldNVTable { /* byte order indication, etc. */ guint16 size; guint16 used; guint16 num_dyn_entries; guint8 num_static_entries; guint8 ref_cnt; /* variable data, see memory layout in the comment above */ union { guint32 __dummy_for_alignment; guint16 static_entries[0]; gchar data[0]; }; } OldNVTable; static inline void _swap_old_entry_flags(OldNVEntry *entry) { entry->flags = reverse(entry->flags); } static void _old_entry_swap_bytes(OldNVEntry *entry) { _swap_old_entry_flags(entry); entry->alloc_len = GUINT16_SWAP_LE_BE(entry->alloc_len); if (!entry->indirect) { entry->vdirect.value_len = GUINT16_SWAP_LE_BE(entry->vdirect.value_len); } else { entry->vindirect.handle = GUINT16_SWAP_LE_BE(entry->vindirect.handle); entry->vindirect.ofs = GUINT16_SWAP_LE_BE(entry->vindirect.ofs); entry->vindirect.len = GUINT16_SWAP_LE_BE(entry->vindirect.len); } } static inline int _calculate_new_alloc_len(OldNVEntry *old_entry) { return (old_entry->alloc_len << NV_TABLE_OLD_SCALE) + SIZE_DIFF_OF_OLD_NVENTRY_AND_NEW_NVENTRY; } static inline guint32 _calculate_new_size(NVTable *self) { guint32 diff_of_old_used_and_new_used = (self->num_static_entries + self->index_size) * SIZE_DIFF_OF_OLD_NVENTRY_AND_NEW_NVENTRY; return self->size + NV_TABLE_HEADER_DIFF_V22_V26 + NV_TABLE_HANDLE_DIFF_V22_V26 * self->num_static_entries + NV_TABLE_DYNVALUE_DIFF_V22_V26 * self->index_size + diff_of_old_used_and_new_used; } static inline NVEntry * _deserialize_old_entry(GString *old_nvtable_payload, guint32 old_offset, gchar *payload_start, gboolean different_endianness) { OldNVEntry *old_entry = (OldNVEntry *) (old_nvtable_payload->str + old_nvtable_payload->len - old_offset); NVEntry *new_entry; if (different_endianness) _old_entry_swap_bytes(old_entry); new_entry = (NVEntry *) (payload_start - _calculate_new_alloc_len(old_entry)); new_entry->flags = old_entry->flags & NVENTRY_FLAGS_DEFINED_IN_LEGACY_FORMATS; new_entry->unset = FALSE; /* This old data format does not have "type_present" set, so leave it as * FALSE and "type" fields uninitialized. Initializing those would be * covered by log_msg_fixup_handles_after_deserialization() later. We * simply behave as if we deserialized an old, but not ancient (e.g. 16 * bit ofs) LogMessage. * */ new_entry->type_present = FALSE; new_entry->name_len = old_entry->name_len; new_entry->alloc_len = _calculate_new_alloc_len(old_entry); if (!new_entry->indirect) { new_entry->vdirect.value_len = old_entry->vdirect.value_len; memcpy(&new_entry->vdirect.data, &old_entry->vdirect.data, new_entry->name_len + new_entry->vdirect.value_len + 2); } else { new_entry->vindirect.handle = old_entry->vindirect.handle; new_entry->vindirect.__deprecated_type_field = old_entry->vindirect.type; /* */ new_entry->vindirect.ofs = old_entry->vindirect.ofs; new_entry->vindirect.len = old_entry->vindirect.len; memcpy(&new_entry->vindirect.name, &old_entry->vindirect.name, new_entry->name_len); } return new_entry; } static gboolean _deserialize_blob_v22(SerializeArchive *sa, NVTable *self, gchar *table_top, gboolean different_endianness) { GString *old_nvtable_payload; gchar *current_payload_pointer = table_top; int i; NVIndexEntry *dyn_entries; if (!self->used) return TRUE; old_nvtable_payload = g_string_sized_new(self->used); old_nvtable_payload->len = self->used; if (!serialize_read_blob(sa, old_nvtable_payload->str, self->used)) { g_string_free(old_nvtable_payload, TRUE); return FALSE; } /* * Iterate through all NVEntries and convert them. We should update * their offset, too. We do not need to iterate them in order, we * will simply copy them to the new place linearly. The only problem * is that the indirect/direct use-case should be resolved * correctly. */ for (i = 0; i < self->num_static_entries; i++) { guint32 old_entry_offset = self->static_entries[i]; if (old_entry_offset != 0) { NVEntry *new_entry = _deserialize_old_entry(old_nvtable_payload, old_entry_offset, current_payload_pointer, different_endianness); self->static_entries[i] = (guint32)(table_top - (gchar *)new_entry); current_payload_pointer = current_payload_pointer - new_entry->alloc_len; } } dyn_entries = nv_table_get_index(self); for (i = 0; i < self->index_size; i++) { NVIndexEntry *dynvalue = &dyn_entries[i]; guint32 old_entry_offset = dynvalue->ofs; NVEntry *new_entry = _deserialize_old_entry(old_nvtable_payload, old_entry_offset, current_payload_pointer, different_endianness); dynvalue->ofs = (guint32) (table_top - (gchar *) new_entry); current_payload_pointer = current_payload_pointer - new_entry->alloc_len; } self->used = table_top - current_payload_pointer; g_string_free(old_nvtable_payload, TRUE); return TRUE; } static inline void _convert_old_dyn_entry(NVIndexEntry *dyn_entry, guint32 old_dyn_entry) { dyn_entry->handle = old_dyn_entry >> 16; dyn_entry->ofs = (old_dyn_entry & 0xFFFF) << NV_TABLE_OLD_SCALE; }; static gboolean _deserialize_struct_22(SerializeArchive *sa, NVTable *res) { guint16 i; NVIndexEntry *dyn_entries; guint32 old_dyn_entry; guint16 old_static_entry; for (i = 0; i < res->num_static_entries; i++) { if (!serialize_read_uint16(sa, &old_static_entry)) return FALSE; res->static_entries[i] = old_static_entry << NV_TABLE_OLD_SCALE; } dyn_entries = nv_table_get_index(res); for (i = 0; i < res->index_size; i++) { if (!serialize_read_uint32(sa, &old_dyn_entry)) return FALSE; _convert_old_dyn_entry(&dyn_entries[i], old_dyn_entry); } return TRUE; } NVTable * nv_table_deserialize_22(SerializeArchive *sa) { guint16 old_res; guint32 magic = 0; guint8 flags = 0; NVTable *res = NULL; gboolean is_big_endian = (G_BYTE_ORDER == G_BIG_ENDIAN); gboolean different_endianness; if (!serialize_read_uint32(sa, &magic)) return NULL; if (!serialize_read_uint8(sa, &flags)) return NULL; if (!!(flags & NVT_SF_BE) != is_big_endian) { magic = GUINT32_SWAP_LE_BE(magic); } if (memcmp(&magic, NV_TABLE_MAGIC_V2, 4) != 0) return NULL; res = (NVTable *)g_malloc(sizeof(NVTable)); if (!serialize_read_uint16(sa, &old_res)) { g_free(res); return NULL; } res->size = old_res << NV_TABLE_OLD_SCALE; if (!serialize_read_uint16(sa, &old_res)) { g_free(res); return NULL; } res->used = old_res << NV_TABLE_OLD_SCALE; if (!serialize_read_uint16(sa, &res->index_size)) { g_free(res); return NULL; } if (!serialize_read_uint8(sa, &res->num_static_entries)) { g_free(res); return NULL; } res->size = _calculate_new_size(res); res = (NVTable *)g_realloc(res, res->size); if(!res) return NULL; res->ref_cnt = 1; res->borrowed = FALSE; if (!_deserialize_struct_22(sa, res)) { g_free(res); return NULL; } different_endianness = (is_big_endian != (flags & NVT_SF_BE)); if (!_deserialize_blob_v22(sa, res, nv_table_get_top(res), different_endianness)) { g_free(res); return NULL; } return res; } static inline guint32 _calculate_new_size_from_legacy_nvtable(OldNVTable *self) { return self->size + NV_TABLE_HEADER_DIFF_V22_V26 + NV_TABLE_HANDLE_DIFF_V22_V26 * self->num_static_entries + NV_TABLE_DYNVALUE_DIFF_V22_V26 * self->num_dyn_entries; } static inline guint32 *_get_legacy_dynamic_entries(OldNVTable *old) { return (guint32 *)(&(old->static_entries[old->num_static_entries])); } static NVTable * _create_new_nvtable_from_legacy_nvtable(OldNVTable *old) { NVTable *res = g_try_malloc(_calculate_new_size_from_legacy_nvtable(old)); NVIndexEntry *dyn_entries; guint32 *old_entries; int i; res->size = old->size << NV_TABLE_OLD_SCALE; res->used = old->used << NV_TABLE_OLD_SCALE; res->num_static_entries = old->num_static_entries; res->index_size = old->num_dyn_entries; for (i = 0; i < res->num_static_entries; i++) { res->static_entries[i] = old->static_entries[i] << NV_TABLE_OLD_SCALE; } old_entries = _get_legacy_dynamic_entries(old); dyn_entries = nv_table_get_index(res); for (i = 0; i < res->index_size; i++) { _convert_old_dyn_entry(&dyn_entries[i], old_entries[i]); } return res; }; static void _struct_swap_bytes_legacy(OldNVTable *self) { guint16 i; guint32 *dyn_entries; self->size = GUINT16_SWAP_LE_BE(self->size); self->used = GUINT16_SWAP_LE_BE(self->used); self->num_dyn_entries = GUINT16_SWAP_LE_BE(self->num_dyn_entries); for (i = 0; i < self->num_static_entries; i++) { self->static_entries[i] = GUINT16_SWAP_LE_BE(self->static_entries[i]); } dyn_entries = _get_legacy_dynamic_entries(self); for (i = 0; i < self->num_dyn_entries; i++) { dyn_entries[i] = GUINT32_SWAP_LE_BE(dyn_entries[i]); } } NVTable * nv_table_deserialize_legacy(SerializeArchive *sa) { OldNVTable *tmp; NVTable *res; guint32 header_len = 0; guint32 calculated_header_len = 0; guint32 calculated_used_len = 0; guint32 used_len = 0; gboolean swap_bytes = FALSE; if (!serialize_read_uint32(sa, &header_len)) return NULL; tmp = (OldNVTable *)g_try_malloc(header_len); if (!tmp) return NULL; if (!serialize_read_blob(sa, tmp, header_len)) { g_free(tmp); return NULL; } calculated_header_len = sizeof(OldNVTable) + tmp->num_static_entries * sizeof(tmp->static_entries[0]) + tmp->num_dyn_entries * sizeof(guint32); if (!serialize_read_uint32(sa, &used_len)) { g_free(tmp); return NULL; } calculated_used_len = tmp->used << NV_TABLE_OLD_SCALE; if (calculated_used_len != used_len || calculated_header_len != header_len) swap_bytes=TRUE; if (swap_bytes) _struct_swap_bytes_legacy(tmp); res = _create_new_nvtable_from_legacy_nvtable(tmp); if (!res) { g_free(tmp); return NULL; } g_free(tmp); res = (NVTable *)g_try_realloc(res, res->size); if (!res) return NULL; res->borrowed = FALSE; res->ref_cnt = 1; if (!_deserialize_blob_v22(sa, res, nv_table_get_top(res), swap_bytes)) { g_free(res); return NULL; } return res; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable-serialize-legacy.h000066400000000000000000000027541450431004300244540ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2012-2013 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef NVTABLE_SERIALIZE_LEGACY_H_ #define NVTABLE_SERIALIZE_LEGACY_H_ #include "nvtable.h" #include "serialize.h" /* * Contains the deserialization functions of old NVTable versions. * We should be able to deserialize all previous versions of NVTable or logmsg. */ NVTable *nv_table_deserialize_22(SerializeArchive *sa); NVTable *nv_table_deserialize_legacy(SerializeArchive *sa); #endif /* NVTABLE_SERIALIZE_LEGACY_H_ */ syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable-serialize.c000066400000000000000000000143411450431004300232000ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2012-2015 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmsg/nvtable-serialize.h" #include "logmsg/nvtable-serialize-endianutils.h" #include "logmsg/logmsg.h" #include "messages.h" #include #include typedef struct _NVTableMetaData { guint32 magic; guint8 flags; } NVTableMetaData; /********************************************************************** * deserialize an NVTable **********************************************************************/ static gboolean _deserialize_static_entries(SerializeArchive *sa, NVTable *res) { if (!serialize_read_uint32_array(sa, res->static_entries, res->num_static_entries)) return FALSE; return TRUE; } static gboolean _deserialize_dynamic_entries(SerializeArchive *sa, NVTable *res) { NVIndexEntry *index_table; index_table = nv_table_get_index(res); if (!serialize_read_uint32_array(sa, (guint32 *) index_table, res->index_size * 2)) return FALSE; return TRUE; } static gboolean _read_struct(SerializeArchive *sa, NVTable *res) { return _deserialize_static_entries(sa, res) && _deserialize_dynamic_entries(sa, res); } static gboolean _has_to_swap_bytes(guint8 flags) { return !!(flags & NVT_SF_BE) != (G_BYTE_ORDER == G_BIG_ENDIAN); } static inline gboolean _read_magic(SerializeArchive *sa, guint32 *magic) { return serialize_read_uint32(sa, magic); } static inline gboolean _read_flags(SerializeArchive *sa, guint8 *flags) { return serialize_read_uint8(sa, flags); } static inline gboolean _read_metadata(SerializeArchive *sa, NVTableMetaData *meta_data) { if (!_read_magic(sa, &meta_data->magic)) { return FALSE; } if (!_read_flags(sa, &meta_data->flags)) { return FALSE; } if (_has_to_swap_bytes(meta_data->flags)) { meta_data->magic = GUINT32_SWAP_LE_BE(meta_data->magic); } if (memcmp((void *)&meta_data->magic, (const void *)NV_TABLE_MAGIC_V2, 4) != 0) { return FALSE; } return TRUE; } static gboolean _read_header(SerializeArchive *sa, NVTable **nvtable) { NVTable *res = NULL; guint32 size; g_assert(*nvtable == NULL); if (!serialize_read_uint32(sa, &size)) goto error; if (size > NV_TABLE_MAX_BYTES) goto error; res = (NVTable *) g_malloc(size); res->size = size; if (!serialize_read_uint32(sa, &res->used)) goto error; if (!serialize_read_uint16(sa, &res->index_size)) goto error; if (!serialize_read_uint8(sa, &res->num_static_entries)) goto error; /* static entries has to be known by this syslog-ng, if they are over * LM_V_MAX, that means we have no clue how an entry is called, as static * entries don't contain names. If there are less static entries, that * can be ok. */ if (res->num_static_entries > LM_V_MAX) goto error; /* validates self->used and self->index_size value as compared to "size" */ if (!nv_table_alloc_check(res, 0)) goto error; res->borrowed = FALSE; res->ref_cnt = 1; *nvtable = res; return TRUE; error: if (res) g_free(res); return FALSE; } static inline gboolean _read_payload(SerializeArchive *sa, NVTable *res) { return serialize_read_blob(sa, NV_TABLE_ADDR(res, res->size - res->used), res->used); } NVTable * nv_table_deserialize(LogMessageSerializationState *state) { SerializeArchive *sa = state->sa; NVTableMetaData meta_data; NVTable *res = NULL; if (!_read_metadata(sa, &meta_data)) goto error; if (!_read_header(sa, &res)) goto error; state->nvtable_flags = meta_data.flags; state->nvtable = res; if (!_read_struct(sa, res)) goto error; if (!_read_payload(sa, res)) goto error; if (_has_to_swap_bytes(meta_data.flags)) nv_table_data_swap_bytes(res); return res; error: if (res) g_free(res); return NULL; } /********************************************************************** * serialize an NVTable **********************************************************************/ static void _write_struct(SerializeArchive *sa, NVTable *self) { serialize_write_uint32(sa, self->size); serialize_write_uint32(sa, self->used); serialize_write_uint16(sa, self->index_size); serialize_write_uint8(sa, self->num_static_entries); serialize_write_uint32_array(sa, self->static_entries, self->num_static_entries); serialize_write_uint32_array(sa, (guint32 *) nv_table_get_index(self), self->index_size * 2); } static void _write_meta_data(SerializeArchive *sa, NVTableMetaData *meta_data) { serialize_write_uint32(sa, meta_data->magic); serialize_write_uint8(sa, meta_data->flags); } static void _fill_meta_data(NVTable *self, NVTableMetaData *meta_data) { memcpy((void *)&meta_data->magic, (const void *) NV_TABLE_MAGIC_V2, 4); if (G_BYTE_ORDER == G_BIG_ENDIAN) meta_data->flags |= NVT_SF_BE; meta_data->flags |= NVT_SUPPORTS_UNSET; } static void _write_payload(SerializeArchive *sa, NVTable *self) { serialize_write_blob(sa, NV_TABLE_ADDR(self, self->size - self->used), self->used); } gboolean nv_table_serialize(LogMessageSerializationState *state, NVTable *self) { NVTableMetaData meta_data = { 0 }; SerializeArchive *sa = state->sa; _fill_meta_data(self, &meta_data); _write_meta_data(sa, &meta_data); _write_struct(sa, self); _write_payload(sa, self); return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable-serialize.h000066400000000000000000000031161450431004300232030ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2012-2015 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _NVTABLE_SERIALIZE_H #define _NVTABLE_SERIALIZE_H #include "logmsg/nvtable.h" #include "logmsg/serialization.h" #define NV_TABLE_MAGIC_V2 "NVT2" #define NVT_SF_BE 0x1 #define NVT_SUPPORTS_UNSET 0x2 #define NVENTRY_FLAGS_DEFINED_IN_LEGACY_FORMATS 0x3 NVTable *nv_table_deserialize(LogMessageSerializationState *state); gboolean nv_table_serialize(LogMessageSerializationState *state, NVTable *self); gboolean nv_table_fixup_handles(LogMessageSerializationState *state); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable.c000066400000000000000000000622001450431004300212100ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logmsg/nvtable.h" #include "messages.h" #include #include static GMutex nv_registry_lock; const gchar *null_string = ""; NVHandle nv_registry_get_handle(NVRegistry *self, const gchar *name) { gpointer p; p = g_hash_table_lookup(self->name_map, name); if (p) return GPOINTER_TO_UINT(p); return 0; } NVHandle nv_registry_alloc_handle(NVRegistry *self, const gchar *name) { gpointer p; NVHandleDesc stored; gsize len; NVHandle res = 0; g_mutex_lock(&nv_registry_lock); p = g_hash_table_lookup(self->name_map, name); if (p) { res = GPOINTER_TO_UINT(p); goto exit; } len = strlen(name); if (len == 0) goto exit; if (len > 255) { msg_error("Value names cannot be longer than 255 characters, " "this value will always expand to the empty string", evt_tag_str("value", name)); goto exit; } if (self->names->len >= self->nvhandle_max_value) { msg_error("Hard wired limit of name-value pairs have been reached, " "all further name-value pair will expand to nothing", evt_tag_printf("limit", "%"G_GUINT32_FORMAT, self->nvhandle_max_value), evt_tag_str("value", name)); goto exit; } /* name (len bytes) || NULL || flags (2 bytes) || length (1 byte) */ /* memory layout: name (NUL terminated) || flags || length */ stored.flags = 0; stored.name_len = len; stored.name = g_strdup(name); nvhandle_desc_array_append(self->names, &stored); g_hash_table_insert(self->name_map, g_strdup(name), GUINT_TO_POINTER(self->names->len)); res = self->names->len; exit: g_mutex_unlock(&nv_registry_lock); return res; } /** * nv_registry_add_alias: * @handle: a NV handle to be aliased * @alias: must be a caller allocated string pointing to the alias of "handle" **/ void nv_registry_add_alias(NVRegistry *self, NVHandle handle, const gchar *alias) { g_mutex_lock(&nv_registry_lock); g_hash_table_insert(self->name_map, g_strdup(alias), GUINT_TO_POINTER((glong) handle)); g_mutex_unlock(&nv_registry_lock); } void nv_registry_set_handle_flags(NVRegistry *self, NVHandle handle, guint16 flags) { NVHandleDesc *stored; if (G_UNLIKELY(!handle)) return; stored = &nvhandle_desc_array_index(self->names, handle - 1); stored->flags = flags; } void nv_registry_foreach(NVRegistry *self, GHFunc callback, gpointer user_data) { g_hash_table_foreach(self->name_map, callback, user_data); } NVRegistry * nv_registry_new(const gchar **static_names, guint32 nvhandle_max_value) { NVRegistry *self = g_new0(NVRegistry, 1); gint i; self->nvhandle_max_value = nvhandle_max_value; self->name_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); self->names = nvhandle_desc_array_new(NVHANDLE_DESC_ARRAY_INITIAL_SIZE); for (i = 0; static_names[i]; i++) { nv_registry_alloc_handle(self, static_names[i]); } return self; } void nv_registry_free(NVRegistry *self) { nvhandle_desc_array_free(self->names); g_hash_table_destroy(self->name_map); g_free(self); } /* return the offset to a newly allocated payload string */ static inline NVEntry * nv_table_alloc_value(NVTable *self, gsize alloc_size) { NVEntry *entry; alloc_size = NV_TABLE_BOUND(alloc_size); /* alloc error, NVTable should be realloced */ if (!nv_table_alloc_check(self, alloc_size)) return NULL; self->used += alloc_size; entry = (NVEntry *) (nv_table_get_top(self) - (self->used)); /* initialize all flags to zero, so we don't need to bump the version for * a compatible change */ entry->flags = 0; entry->alloc_len = alloc_size; entry->indirect = FALSE; entry->referenced = FALSE; entry->unset = FALSE; entry->type_present = TRUE; entry->type = 0; /* initialize __reserved field (at the same type as type_present is TRUE, * so that future extensions have another byte to use) */ entry->__reserved = 0; return entry; } /* we only support single indirection */ const gchar * nv_table_resolve_indirect(NVTable *self, NVEntry *entry, gssize *length) { const gchar *referenced_value; gssize referenced_length; g_assert(entry->indirect); referenced_value = nv_table_get_value(self, entry->vindirect.handle, &referenced_length, NULL); if (!referenced_value || entry->vindirect.ofs > referenced_length) { if (length) *length = 0; return null_string; } /* here we assume that indirect references are only looked up with * non-zero terminated strings properly handled, thus the caller has * to supply a non-NULL value_len */ g_assert(length != NULL); *length = MIN(entry->vindirect.ofs + entry->vindirect.len, referenced_length) - entry->vindirect.ofs; return referenced_value + entry->vindirect.ofs; } static inline const gchar * nv_table_resolve_direct(NVTable *self, NVEntry *entry, gssize *length) { g_assert(!entry->indirect); if (length) *length = entry->vdirect.value_len; return entry->vdirect.data + entry->name_len + 1; } static inline const gchar * nv_table_resolve_entry(NVTable *self, NVEntry *entry, gssize *length, NVType *type) { if (entry->unset) { if (type) *type = 0; if (length) *length = 0; return null_string; } if (type) *type = entry->type; if (entry->indirect) return nv_table_resolve_indirect(self, entry, length); else return nv_table_resolve_direct(self, entry, length); } static inline NVIndexEntry * _find_index_entry(NVIndexEntry *index_table, gint index_size, NVHandle handle, NVIndexEntry **index_slot) { gint l, h, m; NVHandle mv; /* short-cut, check if "handle" is larger than the last - sorted - * element. If it is, we won't be finding it in this table. The loop * below would conclude the same, but only after a log2(N) iterations */ if (index_size > 0 && index_table[index_size - 1].handle < handle) { *index_slot = &index_table[index_size]; return NULL; } /* open-coded binary search */ l = 0; h = index_size - 1; while (l <= h) { m = (l+h) >> 1; mv = index_table[m].handle; if (mv == handle) { *index_slot = &index_table[m]; return &index_table[m]; } else if (mv > handle) { h = m - 1; } else { l = m + 1; } } *index_slot = &index_table[l]; g_assert(l <= index_size); return NULL; } /* slow path for nv_table_get_entry(), i.e. we need to perform the lookup * for handle in the sorted index_table by implementing a binary search. * * The two output arguments `index_entry` and `index_slot` deserve further * explanation: * index_entry: points to the NVIndexEntry that referenced this NVEntry * * index_slot: points to the NVIndexEntry where a new element of this * handle _should_ be inserted. * * This means that index_entry will be NULL if the handle is not present in * this NVTable, whereas index_slot would point to the index_table element * where we need to insert the new index_entry. * * In case the handle is present in NVTable, both index_entry and index_slot * will point to the same location. */ NVEntry * nv_table_get_entry_slow(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot) { *index_entry = _find_index_entry(nv_table_get_index(self), self->index_size, handle, index_slot); if (*index_entry) return nv_table_get_entry_at_ofs(self, (*index_entry)->ofs); return NULL; } static inline gboolean _alloc_index_entry(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry *index_slot) { if (G_UNLIKELY(!(*index_entry) && !nv_table_is_handle_static(self, handle))) { /* this is a dynamic value */ NVIndexEntry *index_table = nv_table_get_index(self); if (!nv_table_alloc_check(self, sizeof(index_table[0]))) return FALSE; NVIndexEntry *index_top = index_table + self->index_size; if (index_slot != index_top) { /* move index entries up */ memmove(index_slot + 1, index_slot, (index_top - index_slot) * sizeof(index_table[0])); } *index_entry = index_slot; /* we set ofs to zero here, which means that the NVEntry won't be found even if the slot is present in index */ (*index_entry)->handle = handle; (*index_entry)->ofs = 0; self->index_size++; } return TRUE; } static inline void nv_table_set_table_entry(NVTable *self, NVHandle handle, guint32 ofs, NVIndexEntry *index_entry) { if (G_LIKELY(nv_table_is_handle_static(self, handle))) { /* this is a statically allocated value, simply store the offset */ self->static_entries[handle-1] = ofs; } else { /* this is a dynamic value */ (*index_entry).handle = handle; (*index_entry).ofs = ofs; } } static gboolean _make_entry_direct(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data) { NVTable *self = (NVTable *) (((gpointer *) user_data)[0]); NVHandle ref_handle = GPOINTER_TO_UINT(((gpointer *) user_data)[1]); if (entry->indirect && entry->vindirect.handle == ref_handle) { const gchar *value; gssize value_len; value = nv_table_resolve_indirect(self, entry, &value_len); if (!nv_table_add_value(self, handle, entry->vindirect.name, entry->name_len, value, value_len, entry->type, NULL)) { /* nvtable full, but we can't realloc it ourselves, * propagate this back as a failure of * nv_table_add_value() */ return TRUE; } } return FALSE; } static inline gboolean nv_table_break_references_to_entry(NVTable *self, NVHandle handle, NVEntry *entry) { if (G_UNLIKELY(entry && !entry->indirect && entry->referenced)) { gpointer data[2] = { self, GUINT_TO_POINTER((glong) handle) }; if (nv_table_foreach_entry(self, _make_entry_direct, data)) { /* we had to stop iteration, which means that we were unable * to allocate enough space for making indirect entries * direct */ return FALSE; } } return TRUE; } static inline void _overwrite_with_a_direct_entry(NVTable *self, NVHandle handle, NVEntry *entry, const gchar *name, gsize name_len, const gchar *value, gsize value_len, NVType type) { gchar *dst; /* this value already exists and the new value fits in the old space */ if (!entry->indirect) { dst = entry->vdirect.data + entry->name_len + 1; entry->vdirect.value_len = value_len; memmove(dst, value, value_len); dst[value_len] = 0; } else { /* this was an indirect entry, convert it */ entry->indirect = 0; entry->vdirect.value_len = value_len; if (!nv_table_is_handle_static(self, handle)) { /* we pick up the name_len from the entry as it may be static in which case name is not stored */ g_assert(entry->name_len == name_len); memmove(entry->vdirect.data, name, name_len + 1); } else { /* the old entry didn't have a name, we won't add it either */ name_len = 0; entry->vdirect.data[0] = 0; } memmove(entry->vdirect.data + name_len + 1, value, value_len); entry->vdirect.data[entry->name_len + 1 + value_len] = 0; } entry->unset = FALSE; entry->type = type; } gboolean nv_table_add_value(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, const gchar *value, gsize value_len, NVType type, gboolean *new_entry) { NVEntry *entry; guint32 ofs; NVIndexEntry *index_entry, *index_slot; if (value_len > NV_TABLE_MAX_BYTES) value_len = NV_TABLE_MAX_BYTES; if (new_entry) *new_entry = FALSE; entry = nv_table_get_entry(self, handle, &index_entry, &index_slot); if (!nv_table_break_references_to_entry(self, handle, entry)) return FALSE; if (entry && entry->alloc_len >= NV_ENTRY_DIRECT_SIZE(entry->name_len, value_len)) { _overwrite_with_a_direct_entry(self, handle, entry, name, name_len, value, value_len, type); return TRUE; } else if (!entry && new_entry) *new_entry = TRUE; /* check if there's enough free space: size of the struct plus the * size needed for a dynamic table slot */ if (!_alloc_index_entry(self, handle, &index_entry, index_slot)) return FALSE; if (nv_table_is_handle_static(self, handle)) name_len = 0; entry = nv_table_alloc_value(self, NV_ENTRY_DIRECT_SIZE(name_len, value_len)); if (G_UNLIKELY(!entry)) { return FALSE; } entry->type = type; ofs = nv_table_get_ofs_for_an_entry(self, entry); entry->vdirect.value_len = value_len; entry->name_len = name_len; if (entry->name_len != 0) { /* we only store the name for dynamic values */ memmove(entry->vdirect.data, name, name_len + 1); } memmove(entry->vdirect.data + entry->name_len + 1, value, value_len); entry->vdirect.data[entry->name_len + 1 + value_len] = 0; nv_table_set_table_entry(self, handle, ofs, index_entry); return TRUE; } gboolean nv_table_unset_value(NVTable *self, NVHandle handle) { NVIndexEntry *index_entry; NVEntry *entry = nv_table_get_entry(self, handle, &index_entry, NULL); if (!entry) return TRUE; if (!nv_table_break_references_to_entry(self, handle, entry)) return FALSE; entry->unset = TRUE; /* make sure the actual value is also set to the null_string just in case * this message is serialized and then deserialized by an earlier * syslog-ng version which does not support the unset flag */ if (entry->indirect) { entry->vindirect.ofs = 0; entry->vindirect.len = 0; } else { entry->vdirect.value_len = 0; entry->vdirect.data[entry->name_len + 1] = 0; } return TRUE; } static void nv_table_set_indirect_entry(NVTable *self, NVHandle handle, NVEntry *entry, const gchar *name, gsize name_len, const NVReferencedSlice *referenced_slice, NVType type) { entry->vindirect.handle = referenced_slice->handle; entry->vindirect.ofs = referenced_slice->ofs; entry->vindirect.len = referenced_slice->len; entry->vindirect.__deprecated_type_field = 0; entry->type = type; entry->unset = FALSE; if (entry->indirect) return; /* previously a non-indirect entry, convert it */ entry->indirect = 1; if (!nv_table_is_handle_static(self, handle)) { entry->name_len = name_len; memmove(entry->vindirect.name, name, name_len + 1); } else { entry->name_len = 0; } } static gboolean nv_table_copy_referenced_value(NVTable *self, NVEntry *ref_entry, NVHandle handle, const gchar *name, gsize name_len, NVReferencedSlice *ref_slice, NVType type, gboolean *new_entry) { gssize ref_length; const gchar *ref_value = nv_table_resolve_entry(self, ref_entry, &ref_length, NULL); if (ref_slice->ofs > ref_length) { ref_slice->len = 0; ref_slice->ofs = 0; } else { ref_slice->len = MIN(ref_slice->ofs + ref_slice->len, ref_length) - ref_slice->ofs; } return nv_table_add_value(self, handle, name, name_len, ref_value + ref_slice->ofs, ref_slice->len, type, new_entry); } gboolean nv_table_add_value_indirect(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, NVReferencedSlice *referenced_slice, NVType type, gboolean *new_entry) { NVEntry *entry, *ref_entry; NVIndexEntry *index_entry, *index_slot; guint32 ofs; if (new_entry) *new_entry = FALSE; ref_entry = nv_table_get_entry(self, referenced_slice->handle, NULL, NULL); if ((ref_entry && ref_entry->indirect) || handle == referenced_slice->handle) { /* NOTE: uh-oh, the to-be-referenced value is already an indirect * reference, this is not supported, copy the stuff */ return nv_table_copy_referenced_value(self, ref_entry, handle, name, name_len, referenced_slice, type, new_entry); } entry = nv_table_get_entry(self, handle, &index_entry, &index_slot); if ((!entry && !new_entry && referenced_slice->len == 0) || !ref_entry) { /* we don't store zero length matches unless the caller is * interested in whether a new entry was created. It is used by * the SDATA support code to decide whether a previously * not-present SDATA was set */ return TRUE; } if (!nv_table_break_references_to_entry(self, handle, entry)) return FALSE; if (entry && (entry->alloc_len >= NV_ENTRY_INDIRECT_SIZE(name_len))) { /* this value already exists and the new reference fits in the old space */ nv_table_set_indirect_entry(self, handle, entry, name, name_len, referenced_slice, type); ref_entry->referenced = TRUE; return TRUE; } else if (!entry && new_entry) { *new_entry = TRUE; } if (!_alloc_index_entry(self, handle, &index_entry, index_slot)) return FALSE; entry = nv_table_alloc_value(self, NV_ENTRY_INDIRECT_SIZE(name_len)); if (!entry) { return FALSE; } ofs = nv_table_get_ofs_for_an_entry(self, entry); nv_table_set_indirect_entry(self, handle, entry, name, name_len, referenced_slice, type); ref_entry->referenced = TRUE; nv_table_set_table_entry(self, handle, ofs, index_entry); return TRUE; } static gboolean nv_table_call_foreach(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data) { NVTable *self = (NVTable *) ((gpointer *) user_data)[0]; NVRegistry *registry = (NVRegistry *) ((gpointer *) user_data)[1]; NVTableForeachFunc func = ((gpointer *) user_data)[2]; gpointer func_data = ((gpointer *) user_data)[3]; const gchar *value; gssize value_len; NVType type; if (entry->unset) return FALSE; value = nv_table_resolve_entry(self, entry, &value_len, &type); return func(handle, nv_registry_get_handle_name(registry, handle, NULL), value, value_len, type, func_data); } gboolean nv_table_foreach(NVTable *self, NVRegistry *registry, NVTableForeachFunc func, gpointer user_data) { gpointer data[4] = { self, registry, func, user_data }; return nv_table_foreach_entry(self, nv_table_call_foreach, data); } gboolean nv_table_foreach_entry(NVTable *self, NVTableForeachEntryFunc func, gpointer user_data) { NVIndexEntry *index_table; NVEntry *entry; gint i; for (i = 0; i < self->num_static_entries; i++) { entry = nv_table_get_entry_at_ofs(self, self->static_entries[i]); if (!entry) continue; if (func(i + 1, entry, NULL, user_data)) return TRUE; } index_table = nv_table_get_index(self); for (i = 0; i < self->index_size; i++) { entry = nv_table_get_entry_at_ofs(self, index_table[i].ofs); if (!entry) continue; if (func(index_table[i].handle, entry, &index_table[i], user_data)) return TRUE; } return FALSE; } void nv_table_init(NVTable *self, gsize alloc_length, gint num_static_entries) { g_assert(alloc_length <= NV_TABLE_MAX_BYTES); self->size = alloc_length; self->used = 0; self->index_size = 0; self->num_static_entries = num_static_entries; self->ref_cnt = 1; self->borrowed = FALSE; memset(&self->static_entries[0], 0, self->num_static_entries * sizeof(self->static_entries[0])); } NVTable * nv_table_new(gint num_static_entries, gint index_size_hint, gint init_length) { NVTable *self; gsize alloc_length; alloc_length = nv_table_get_alloc_size(num_static_entries, index_size_hint, init_length); self = (NVTable *) g_malloc(alloc_length); nv_table_init(self, alloc_length, num_static_entries); return self; } NVTable * nv_table_init_borrowed(gpointer space, gsize space_len, gint num_static_entries) { NVTable *self = (NVTable *) space; space_len &= ~3; g_assert(space_len > num_static_entries * sizeof(self->static_entries[0]) + sizeof(NVTable)); nv_table_init(self, NV_TABLE_BOUND(space_len), num_static_entries); self->borrowed = TRUE; return self; } /* returns TRUE if successfully realloced, FALSE means that we're unable to grow */ gboolean nv_table_realloc(NVTable *self, NVTable **new_nv_table) { gsize old_size = self->size; gsize new_size; /* double the size of the current allocation */ new_size = ((gsize) self->size) << 1; if (new_size > NV_TABLE_MAX_BYTES) new_size = NV_TABLE_MAX_BYTES; if (new_size == old_size) return FALSE; if (self->ref_cnt == 1 && !self->borrowed) { *new_nv_table = self = g_realloc(self, new_size); self->size = new_size; /* move the downwards growing region to the end of the new buffer */ memmove(NV_TABLE_ADDR(self, self->size - self->used), NV_TABLE_ADDR(self, old_size - self->used), self->used); } else { *new_nv_table = g_malloc(new_size); /* we only copy the header first */ memcpy(*new_nv_table, self, sizeof(NVTable) + self->num_static_entries * sizeof(self->static_entries[0]) + self->index_size * sizeof(NVIndexEntry)); (*new_nv_table)->ref_cnt = 1; (*new_nv_table)->borrowed = FALSE; (*new_nv_table)->size = new_size; memmove(NV_TABLE_ADDR((*new_nv_table), (*new_nv_table)->size - (*new_nv_table)->used), NV_TABLE_ADDR(self, old_size - self->used), self->used); nv_table_unref(self); } return TRUE; } NVTable * nv_table_ref(NVTable *self) { self->ref_cnt++; return self; } void nv_table_unref(NVTable *self) { if ((--self->ref_cnt == 0) && !self->borrowed) { g_free(self); } } /** * nv_table_clone: * @self: payload to clone * @additional_space: specifies how much additional space is needed in * the newly allocated clone * **/ NVTable * nv_table_clone(NVTable *self, gint additional_space) { NVTable *new; gint new_size; if (nv_table_get_bottom(self) - nv_table_get_ofs_table_top(self) < additional_space) new_size = self->size; else new_size = self->size + (NV_TABLE_BOUND(additional_space)); if (new_size > NV_TABLE_MAX_BYTES) new_size = NV_TABLE_MAX_BYTES; new = g_malloc(new_size); memcpy(new, self, sizeof(NVTable) + self->num_static_entries * sizeof(self->static_entries[0]) + self->index_size * sizeof(NVIndexEntry)); new->size = new_size; new->ref_cnt = 1; new->borrowed = FALSE; memcpy(NV_TABLE_ADDR(new, new->size - new->used), NV_TABLE_ADDR(self, self->size - self->used), self->used); return new; } static gboolean _compact_foreach_entry(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data) { gpointer *args = (gpointer *) user_data; NVTable *old = (NVTable *) args[0]; NVTable *new = (NVTable *) args[1]; const gchar *value, *name; gssize value_len, name_len; /* unused entries are skipped */ if (entry->unset) return FALSE; if (entry->name_len) { /* non-builtin entries have their name stored in the origin NVTable, use that */ name = nv_entry_get_name(entry); name_len = entry->name_len; } else { /* builtin entries don't have their name stored, but we won't store * them either, so just set them to NULL/0 */ name = NULL; name_len = 0; } if (!entry->indirect) { value = nv_table_resolve_direct(old, entry, &value_len); gboolean value_successfully_added = nv_table_add_value(new, handle, name, name_len, value, value_len, entry->type, NULL); g_assert(value_successfully_added); } else { NVReferencedSlice referenced_slice = { .handle = entry->vindirect.handle, .ofs = entry->vindirect.ofs, .len = entry->vindirect.len }; gboolean value_successfully_added = nv_table_add_value_indirect(new, handle, name, name_len, &referenced_slice, entry->type, NULL); g_assert(value_successfully_added); } return FALSE; } NVTable * nv_table_compact(NVTable *self) { gint new_size = self->size; NVTable *new = g_malloc(new_size); gpointer args[2] = { self, new }; nv_table_init(new, new_size, self->num_static_entries); nv_table_foreach_entry(self, _compact_foreach_entry, args); return new; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/nvtable.h000066400000000000000000000355661450431004300212340ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PAYLOAD_H_INCLUDED #define PAYLOAD_H_INCLUDED #include "syslog-ng.h" #include "nvhandle-descriptors.h" typedef struct _NVTable NVTable; typedef struct _NVRegistry NVRegistry; typedef struct _NVIndexEntry NVIndexEntry; typedef struct _NVEntry NVEntry; typedef guint32 NVHandle; typedef guint8 NVType; typedef gboolean (*NVTableForeachFunc)(NVHandle handle, const gchar *name, const gchar *value, gssize value_len, NVType type, gpointer user_data); typedef gboolean (*NVTableForeachEntryFunc)(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data); #define NVHANDLE_MAX_VALUE ((NVHandle)-1) /* NVIndexEntry * this represents an entry in the handle based lookup index, embedded in an NVTable. * * NOTE: * The deserialization code (at least version 26) assumes that this can be * represented by a pair of guint32 instances. It is reading the entire * array back as such. Should you need to change the types here, please * ensure that you also update the nvtable deserialization code. */ struct _NVIndexEntry { NVHandle handle; guint32 ofs; }; struct _NVRegistry { /* number of static names that are statically allocated in each payload */ gint num_static_names; NVHandleDescArray *names; GHashTable *name_map; guint32 nvhandle_max_value; }; extern const gchar *null_string; void nv_registry_add_alias(NVRegistry *self, NVHandle handle, const gchar *alias); NVHandle nv_registry_get_handle(NVRegistry *self, const gchar *name); NVHandle nv_registry_alloc_handle(NVRegistry *self, const gchar *name); void nv_registry_set_handle_flags(NVRegistry *self, NVHandle handle, guint16 flags); void nv_registry_foreach(NVRegistry *self, GHFunc callback, gpointer user_data); NVRegistry *nv_registry_new(const gchar **static_names, guint32 nvhandle_max_value); void nv_registry_free(NVRegistry *self); static inline guint16 nv_registry_get_handle_flags(NVRegistry *self, NVHandle handle) { NVHandleDesc *stored; if (G_UNLIKELY(!handle)) return 0; stored = &nvhandle_desc_array_index(self->names, handle - 1); return stored->flags; } static inline const gchar * nv_registry_get_handle_name(NVRegistry *self, NVHandle handle, gssize *length) { NVHandleDesc *stored; if (G_UNLIKELY(!handle)) { if (length) *length = 4; return "None"; } if (handle - 1 >= self->names->len) { if (length) *length = 0; return NULL; } stored = &nvhandle_desc_array_index(self->names, handle - 1); if (G_LIKELY(length)) *length = stored->name_len; return stored->name; } typedef struct _NVReferencedSlice { NVHandle handle; guint32 ofs; guint32 len; } NVReferencedSlice; /* * Contains a name-value pair. */ struct _NVEntry { /* negative offset, counting from string table top, e.g. start of the string is at @top + ofs */ union { struct { /* make sure you don't exceed 8 bits here. So if you want to add new * bits, decrease the size of __bit_padding below */ /* some of these bits were not zero initialized in the past, which we * are fixing by the use of the NVT_SUPPORTS_UNSET flag in the NVTable * header. If that flag is not present, we fix all but the originally * existing bit fields to zero (both in current and legacy * deserializers). We are using * NVENTRY_FLAGS_DEFINED_IN_LEGACY_FORMATS as a bitmask to mask out * "indirect" and "referenced" in the "flags" member below, which is * unioned on the bitfield. */ guint8 indirect:1, referenced:1, unset:1, type_present:1, __bit_padding:4; }; guint8 flags; }; guint8 name_len; NVType type; /* NOTE: this field fills an empty padding byte, so if you are adding * fields, please remove this. This is now zero initialized as of the * first version of syslog-ng that contain this member. Earlier versions * had an uninitialized padding byte here. */ guint8 __reserved; guint32 alloc_len; union { struct { guint32 value_len; /* variable data, first the name of this entry, then the value, both are NUL terminated */ gchar data[]; } vdirect; struct { NVHandle handle; guint32 ofs; guint32 len; /* NOTE: this type field was promoted up into NVEntry, so we won't need * the "type" field here, we are moving the value stored here in existing * serialized messages in _update_entry() in logmsg-serialize-fixup.c. We * might be able to reuse this byte once we drop compatibility with * version 26 of the LogMessage serialization format. * * NOTE: we zero out this field upon reading and then reserializing a message. */ guint8 __deprecated_type_field; gchar name[0]; } vindirect; }; }; #define NV_ENTRY_DIRECT_HDR ((gsize) (&((NVEntry *) NULL)->vdirect.data)) #define NV_ENTRY_DIRECT_SIZE(name_len, value_len) ((value_len) + NV_ENTRY_DIRECT_HDR + (name_len) + 2) #define NV_ENTRY_INDIRECT_HDR (sizeof(NVEntry)) #define NV_ENTRY_INDIRECT_SIZE(name_len) (NV_ENTRY_INDIRECT_HDR + name_len + 1) static inline const gchar * nv_entry_get_name(NVEntry *self) { if (self->indirect) return self->vindirect.name; else return self->vdirect.data; } /* * Contains a set of ordered name-value pairs. * * This struct is used to track a set of name-value pairs that make up * a LogMessage structure. The storage layout is as concise as * possible to make it possible to serialize this payload as a single * writev() operation. * * Memory layout: * ============= * * || struct || static value offsets || dynamic value (id, offset) pairs || || stored (name, value) || * * Name value area: * - the name-value area grows down (e.g. lower addresses) from the end of the struct * - name-value pairs are referenced by the offset counting down from the end of the struct * - all NV pairs are positioned at 4 bytes boundary, so 32 bit variables in NVEntry * can be accessed in an aligned manner * * Static value offsets: * - a fixed size of guint32 array, containing 32 bit offsets for statically allocated entries * - the handles for static values have a low value and they match the index in this array * * Dynamic values: * - a dynamically sized NVIndexEntry array (contains ID + offset) * - dynamic values are sorted by the global ID to make handle->entry lookups fast * * Memory allocation * ================= * - the memory used by NVTable is managed by the caller, sometimes it is * allocated inside an existing data structure (we preallocate space * with LogMessage) * * - when the structure needs to grow the instance pointer itself needs to * be changed. In order to avoid doing that in all the API calls, a * separate nv_table_realloc() call is provided. * * - NVTable instances are reference counted, but the reference counts are * not thread safe (and accessing NVTable itself isn't either). When * reallocation is needed and multiple references exist, NVTable clones * itself and leaves the old copy be. * * - It is possible to clone an NVTable, which basically copies the * underlying memory contents. * * Limits * ====== * There might be various assumptions here and there in the code that fields * in this structure should be limited in values. These are as follows. * (the list is not necessarily comprehensive though, so please be careful * when changing types). * - index_size is used to allocate NVIndexEntry arrays on the stack, * so 2^16 * sizeof(NVIndexEntry) is allocated at most (512k). If you * however change this limit, please be careful to audit the * deserialization code. * */ struct _NVTable { /* byte order indication, etc. */ guint32 size; guint32 used; /* this used to be called num_dyn_entries in earlier versions, it matches * the type of the original type, so it is compatible with earlier * versions, but index_size is a more descriptive name */ guint16 index_size; guint8 num_static_entries; guint8 ref_cnt:7, borrowed:1; /* specifies if the memory used by NVTable was borrowed from the container struct */ /* variable data, see memory layout in the comment above */ union { guint32 __dummy_for_alignment; guint32 static_entries[0]; gchar data[0]; }; }; #define NV_TABLE_BOUND(x) (((x) + 0x3) & ~0x3) #define NV_TABLE_ADDR(self, x) ((gchar *) ((self)) + ((gssize)(x))) /* 256MB, this is an artificial limit, but must be less than MAX_GUINT32 as * we want to compare a guint32 to this variable without overflow. */ #define NV_TABLE_MAX_BYTES (256*1024*1024) /* this has to be large enough to hold the NVTable struct above and the * static values */ #define NV_TABLE_MIN_BYTES 128 gboolean nv_table_add_value(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, const gchar *value, gsize value_len, NVType type, gboolean *new_entry); gboolean nv_table_unset_value(NVTable *self, NVHandle handle); gboolean nv_table_add_value_indirect(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, NVReferencedSlice *referenced_slice, NVType type, gboolean *new_entry); gboolean nv_table_foreach(NVTable *self, NVRegistry *registry, NVTableForeachFunc func, gpointer user_data); gboolean nv_table_foreach_entry(NVTable *self, NVTableForeachEntryFunc func, gpointer user_data); NVTable *nv_table_new(gint num_static_values, gint index_size_hint, gint init_length); NVTable *nv_table_init_borrowed(gpointer space, gsize space_len, gint num_static_entries); gboolean nv_table_realloc(NVTable *self, NVTable **new_nv_table); NVTable *nv_table_compact(NVTable *self); NVTable *nv_table_clone(NVTable *self, gint additional_space); NVTable *nv_table_ref(NVTable *self); void nv_table_unref(NVTable *self); static inline gboolean nv_table_is_handle_static(NVTable *self, NVHandle handle) { return (handle <= self->num_static_entries); } static inline gsize nv_table_get_alloc_size(gint num_static_entries, gint index_size_hint, gint init_length) { NVTable *self G_GNUC_UNUSED = NULL; gsize size; size = NV_TABLE_BOUND(init_length) + NV_TABLE_BOUND(sizeof(NVTable) + num_static_entries * sizeof( self->static_entries[0]) + index_size_hint * sizeof(NVIndexEntry)); if (size < NV_TABLE_MIN_BYTES) return NV_TABLE_MIN_BYTES; if (size > NV_TABLE_MAX_BYTES) size = NV_TABLE_MAX_BYTES; return size; } static inline gchar * nv_table_get_top(NVTable *self) { return NV_TABLE_ADDR(self, self->size); } static inline gchar * nv_table_get_bottom(NVTable *self) { return nv_table_get_top(self) - self->used; } static inline gchar * nv_table_get_ofs_table_top(NVTable *self) { return (gchar *) &self->data[self->num_static_entries * sizeof(self->static_entries[0]) + self->index_size * sizeof(NVIndexEntry)]; } static inline gboolean nv_table_alloc_check(NVTable *self, gsize alloc_size) { if ((gsize)(nv_table_get_bottom(self) - nv_table_get_ofs_table_top(self)) < alloc_size) return FALSE; return TRUE; } /* private declarations for inline functions */ NVEntry *nv_table_get_entry_slow(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot); const gchar *nv_table_resolve_indirect(NVTable *self, NVEntry *entry, gssize *len); static inline NVEntry * __nv_table_get_entry(NVTable *self, NVHandle handle, guint16 num_static_entries, NVIndexEntry **index_entry, NVIndexEntry **index_slot) { guint32 ofs; NVIndexEntry *t1, *t2; if (!index_entry) index_entry = &t1; if (!index_slot) index_slot = &t2; if (G_UNLIKELY(!handle)) { *index_entry = NULL; *index_slot = NULL; return NULL; } if (G_LIKELY(nv_table_is_handle_static(self, handle))) { ofs = self->static_entries[handle - 1]; *index_entry = NULL; *index_slot = NULL; if (G_UNLIKELY(!ofs)) return NULL; return (NVEntry *) (nv_table_get_top(self) - ofs); } else { return nv_table_get_entry_slow(self, handle, index_entry, index_slot); } } static inline NVEntry * nv_table_get_entry(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot) { return __nv_table_get_entry(self, handle, self->num_static_entries, index_entry, index_slot); } static inline gboolean nv_table_is_value_set(NVTable *self, NVHandle handle) { return nv_table_get_entry(self, handle, NULL, NULL) != NULL; } static inline const gchar * nv_table_get_value(NVTable *self, NVHandle handle, gssize *length, NVType *type) { NVEntry *entry; entry = nv_table_get_entry(self, handle, NULL, NULL); if (!entry || entry->unset) { if (length) *length = 0; return NULL; } if (type) *type = entry->type; if (!entry->indirect) { if (length) *length = entry->vdirect.value_len; return entry->vdirect.data + entry->name_len + 1; } return nv_table_resolve_indirect(self, entry, length); } static inline NVIndexEntry * nv_table_get_index(NVTable *self) { return (NVIndexEntry *)&self->static_entries[self->num_static_entries]; } static inline NVEntry * nv_table_get_entry_at_ofs(NVTable *self, guint32 ofs) { if (!ofs) return NULL; return (NVEntry *)(nv_table_get_top(self) - ofs); } static inline guint32 nv_table_get_ofs_for_an_entry(NVTable *self, NVEntry *entry) { return (nv_table_get_top(self) - (gchar *) entry); } static inline gssize nv_table_get_memory_consumption(NVTable *self) { return sizeof(*self)+ self->num_static_entries*sizeof(self->static_entries[0])+ self->used; } #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/serialization.h000066400000000000000000000027351450431004300224460ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGMSG_SERIALIZATION_H #define LOGMSG_SERIALIZATION_H #include "serialize.h" #include "logmsg/logmsg.h" #include "timeutils/unixtime.h" typedef struct _LogMessageSerializationState { guint8 version; SerializeArchive *sa; LogMessage *msg; NVTable *nvtable; guint8 nvtable_flags; guint8 handle_changed; NVHandle *updated_sdata_handles; NVIndexEntry *updated_index; const UnixTime *processed; guint32 flags; } LogMessageSerializationState; #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/tags-serialize.c000066400000000000000000000037001450431004300225000ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "tags-serialize.h" #include "scratch-buffers.h" gboolean tags_deserialize(LogMessage *msg, SerializeArchive *sa) { ScratchBuffersMarker marker; GString *buf = scratch_buffers_alloc_and_mark(&marker); while (1) { if (!serialize_read_string(sa, buf)) return FALSE; if (buf->len == 0) { /* "" , empty string means: last tag */ break; } log_msg_set_tag_by_name(msg, buf->str); } msg->flags |= LF_STATE_OWN_TAGS; scratch_buffers_reclaim_marked(marker); return TRUE; } static gboolean _callback(const LogMessage *msg, LogTagId tag_id, const gchar *name, gpointer user_data) { SerializeArchive *sa = ( SerializeArchive *)user_data; serialize_write_cstring(sa, name, strlen(name)); return TRUE; } gboolean tags_serialize(LogMessage *msg, SerializeArchive *sa) { log_msg_tags_foreach(msg, _callback, (gpointer)sa); return serialize_write_cstring(sa, "", 0); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tags-serialize.h000066400000000000000000000023601450431004300225060ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TAGS_SERIALIZE_H #define TAGS_SERIALIZE_H #include "logmsg/logmsg.h" #include "serialize.h" gboolean tags_deserialize(LogMessage *msg, SerializeArchive *sa); gboolean tags_serialize(LogMessage *msg, SerializeArchive *sa); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/tags.c000066400000000000000000000153141450431004300205170ustar00rootroot00000000000000/* * Copyright (c) 2009-2013 Balabit * Copyright (c) 2009 Marton Illes * Copyright (c) 2009-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "tags.h" #include "messages.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "apphook.h" typedef struct _LogTag { LogTagId id; gchar *name; StatsCounterItem *counter; } LogTag; static LogTag *log_tags_list = NULL; static GHashTable *log_tags_hash = NULL; static guint32 log_tags_num = 0; static guint32 log_tags_list_size = 4; static GMutex log_tags_lock; /* * log_tags_get_by_name * * Lookup a tag id by it's name. If the tag is seen for the first time * the next tag id is assigned and the tag is added to the list. * * The function returns the tag id associated with the name. * * @name: the name of the tag * */ LogTagId log_tags_get_by_name(const gchar *name) { /* If log_tags_hash() is NULL, this unit is already deinitialized but other thread may refer the tag structure. If name is empty, it is an extremal element. In both cases the return value is 0. */ g_assert(log_tags_hash != NULL); g_mutex_lock(&log_tags_lock); gpointer key = g_hash_table_lookup(log_tags_hash, name); guint id = GPOINTER_TO_UINT(key) - 1; if (id == 0xffffffff) { if (log_tags_num < LOG_TAGS_MAX - 1) { id = log_tags_num++; if (id == log_tags_list_size) { log_tags_list_size *= 2; log_tags_list = g_renew(LogTag, log_tags_list, log_tags_list_size); } log_tags_list[id].id = id; log_tags_list[id].name = g_strdup(name); log_tags_list[id].counter = NULL; /* NOTE: stats-level may not be set for calls that happen during * config file parsing, those get fixed up by * log_tags_reinit_stats() below */ stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", name) }; stats_cluster_single_key_set(&sc_key, "tagged_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_TAG, name, NULL, "processed"); stats_register_counter(3, &sc_key, SC_TYPE_SINGLE_VALUE, &log_tags_list[id].counter); stats_unlock(); g_hash_table_insert(log_tags_hash, log_tags_list[id].name, GUINT_TO_POINTER(log_tags_list[id].id + 1)); } else id = 0; } g_mutex_unlock(&log_tags_lock); return id; } /* * log_tag_get_by_id * * Lookup a tag name by it's id. If the id is invalid * NULL is returned, otherwise a gchar * is returned * pointing to the name of the tag. * * The returned pointer should not be freed. * * @id: the tag id to lookup * */ const gchar * log_tags_get_by_id(LogTagId id) { gchar *name = NULL; g_mutex_lock(&log_tags_lock); if (id < log_tags_num) name = log_tags_list[id].name; g_mutex_unlock(&log_tags_lock); return name; } void log_tags_inc_counter(LogTagId id) { g_mutex_lock(&log_tags_lock); if (id < log_tags_num) stats_counter_inc(log_tags_list[id].counter); g_mutex_unlock(&log_tags_lock); } void log_tags_dec_counter(LogTagId id) { /* Reader lock because the log_tag_list is not written */ g_mutex_lock(&log_tags_lock); if (id < log_tags_num) stats_counter_dec(log_tags_list[id].counter); g_mutex_unlock(&log_tags_lock); } /* * NOTE: this is called at cfg_init() time to update the set of counters we * have. If stats-level is decreased, we should unregister everything we * had earlier. If increased we need to register them again. * * log_tags_get_by_name() will also try to register the counter for calls * that are _after_ cfg_init(). Early calls to log_tags_get_by_name() will * not see a proper stats-level() in the global variable here. Those will * get handled by this function. */ void log_tags_reinit_stats(void) { gint id; g_mutex_lock(&log_tags_lock); stats_lock(); for (id = 0; id < log_tags_num; id++) { const gchar *name = log_tags_list[id].name; StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", name) }; stats_cluster_single_key_set(&sc_key, "tagged_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_TAG, name, NULL, "processed"); if (stats_check_level(3)) stats_register_counter(3, &sc_key, SC_TYPE_SINGLE_VALUE, &log_tags_list[id].counter); else stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &log_tags_list[id].counter); } stats_unlock(); g_mutex_unlock(&log_tags_lock); } void log_tags_global_init(void) { /* Necessary only in case of reinitialized tags */ g_mutex_lock(&log_tags_lock); log_tags_hash = g_hash_table_new(g_str_hash, g_str_equal); log_tags_list_size = 4; log_tags_num = 0; log_tags_list = g_new0(LogTag, log_tags_list_size); g_mutex_unlock(&log_tags_lock); register_application_hook(AH_CONFIG_CHANGED, (ApplicationHookFunc) log_tags_reinit_stats, NULL, AHM_RUN_REPEAT); } void log_tags_global_deinit(void) { gint i; g_mutex_lock(&log_tags_lock); g_hash_table_destroy(log_tags_hash); stats_lock(); StatsClusterKey sc_key; for (i = 0; i < log_tags_num; i++) { StatsClusterLabel labels[] = { stats_cluster_label("id", log_tags_list[i].name) }; stats_cluster_single_key_set(&sc_key, "tagged_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_TAG, log_tags_list[i].name, NULL, "processed"); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &log_tags_list[i].counter); g_free(log_tags_list[i].name); } stats_unlock(); log_tags_num = 0; g_free(log_tags_list); log_tags_list = NULL; log_tags_hash = NULL; g_mutex_unlock(&log_tags_lock); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tags.h000066400000000000000000000032711450431004300205230ustar00rootroot00000000000000/* * Copyright (c) 2009-2013 Balabit * Copyright (c) 2009 Marton Illes * Copyright (c) 2009-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TAGS_H_INCLUDED #define TAGS_H_INCLUDED #include "syslog-ng.h" typedef guint16 LogTagId; /* this is limited by the LogMessage structure, where a guint8 stores the * number of 32 bit ints, used to store the tags as a bitfield. 256 * 32 = * 8192. */ #if GLIB_SIZEOF_LONG == 4 #define LOG_TAGS_MAX 8192 #else #define LOG_TAGS_MAX 16384 #endif #define LOG_TAGS_UNDEF 0xFFFF LogTagId log_tags_get_by_name(const gchar *name); const gchar *log_tags_get_by_id(LogTagId id); void log_tags_reinit_stats(void); void log_tags_global_init(void); void log_tags_global_deinit(void); void log_tags_inc_counter(LogTagId id); void log_tags_dec_counter(LogTagId id); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/000077500000000000000000000000001450431004300205535ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/CMakeLists.txt000066400000000000000000000007661450431004300233240ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_logmsg_serialize DEPENDS syslogformat) add_unit_test(CRITERION LIBTEST TARGET test_timestamp_serialize) add_unit_test(CRITERION TARGET test_tags) add_unit_test(CRITERION TARGET test_nvtable) add_unit_test(CRITERION TARGET test_gsockaddr_serialize) add_unit_test(CRITERION LIBTEST TARGET test_log_message) add_unit_test(CRITERION TARGET test_logmsg_ack) add_unit_test(CRITERION TARGET test_nvhandle_desc_array) add_unit_test(CRITERION TARGET test_type_hints) syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/Makefile.am000066400000000000000000000047371450431004300226220ustar00rootroot00000000000000lib_logmsg_tests_TESTS = \ lib/logmsg/tests/test_logmsg_serialize \ lib/logmsg/tests/test_timestamp_serialize \ lib/logmsg/tests/test_tags \ lib/logmsg/tests/test_type_hints EXTRA_DIST += lib/logmsg/tests/CMakeLists.txt \ lib/logmsg/tests/messages/syslog-ng-3.17.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.18.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.21.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.25.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.26.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.28.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.29.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-3.30.1-msg.h \ lib/logmsg/tests/messages/syslog-ng-pe-6.0-msg.h check_PROGRAMS += ${lib_logmsg_tests_TESTS} lib_logmsg_tests_test_timestamp_serialize_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_timestamp_serialize_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_logmsg_serialize_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_logmsg_serialize_LDADD = $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_logmsg_tests_test_tags_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_tags_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_type_hints_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_type_hints_LDADD = $(TEST_LDADD) lib_logmsg_tests_TESTS += \ lib/logmsg/tests/test_nvtable \ lib/logmsg/tests/test_gsockaddr_serialize \ lib/logmsg/tests/test_log_message \ lib/logmsg/tests/test_logmsg_ack \ lib/logmsg/tests/test_nvhandle_desc_array lib_logmsg_tests_test_nvtable_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_nvtable_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_gsockaddr_serialize_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_gsockaddr_serialize_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_log_message_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_log_message_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_logmsg_ack_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_logmsg_ack_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_test_nvhandle_desc_array_LDADD = $(TEST_LDADD) lib_logmsg_tests_test_nvhandle_desc_array_CFLAGS = $(TEST_CFLAGS) .PHONY: dump-logmsg if ENABLE_TESTING noinst_PROGRAMS += \ lib/logmsg/tests/dump_logmsg lib_logmsg_tests_dump_logmsg_CFLAGS = $(TEST_CFLAGS) lib_logmsg_tests_dump_logmsg_LDADD = $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) dump-logmsg: lib/logmsg/tests/dump_logmsg DIR=lib/logmsg/tests/messages/ && \ mkdir -p $${DIR} && \ lib/logmsg/tests/dump_logmsg $(VERSION) > $${DIR}/syslog-ng-$(VERSION)-msg.h endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/dump_logmsg.c000066400000000000000000000045731450431004300232450ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "test_logmsg_serialize.c" GString * _translate_version(const gchar *version) { GString *r = g_string_new(version); for (gsize i = 0; i < r->len; i++) { if (r->str[i] == '.') r->str[i] = '_'; if (r->str[i] == '+') { g_string_truncate(r, i); break; } } return r; } static void _dump_serialized_bytes(const gchar *translated_version) { GString *data = g_string_new(""); SerializeArchive *sa = _serialize_message_for_test(data, RAW_MSG); printf("unsigned char serialized_message_%s[] = {\n", translated_version); printf(" /* serialized payload %d bytes */\n", (gint) data->len); for (gsize line_start = 0; line_start < data->len; line_start += 16) { for (gint row = 0; row < 16 && line_start + row < data->len; row++) { gsize cell = line_start + row; printf("%s0x%02x%s", row == 0 ? " " : "", (guint8) data->str[cell], row == 15 ? ",\n" : ", "); } } serialize_archive_free(sa); printf("\n};\n"); } int main(int argc, char *argv[]) { setup(); if (argc < 2) { fprintf(stderr, "Expected number argument.\n"); teardown(); return 1; } GString *translated_version = _translate_version(argv[1]); _dump_serialized_bytes(translated_version->str); g_string_free(translated_version, TRUE); teardown(); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/000077500000000000000000000000001450431004300223625ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.17.1-msg.h000066400000000000000000000573551450431004300260050ustar00rootroot00000000000000unsigned char serialized_message_3_17_1[] = { /* serialized payload 3953 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xed, 0xb0, 0x00, 0x00, 0xbd, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0x8b, 0x00, 0x00, 0x01, 0x8d, 0x00, 0x00, 0x01, 0x8f, 0x00, 0x00, 0x01, 0x91, 0x00, 0x00, 0x01, 0x93, 0x00, 0x00, 0x01, 0x95, 0x00, 0x00, 0x01, 0x97, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x01, 0x9b, 0x00, 0x00, 0x01, 0x9d, 0x00, 0x00, 0x01, 0x9f, 0x00, 0x00, 0x01, 0xa1, 0x00, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x00, 0x01, 0xa7, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x01, 0x86, 0x00, 0x00, 0x01, 0x87, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0x87, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x01, 0x89, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x8a, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x01, 0x8b, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0x8d, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0x8f, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x02, 0x5c, 0x00, 0x00, 0x01, 0x91, 0x00, 0x00, 0x02, 0x84, 0x00, 0x00, 0x01, 0x92, 0x00, 0x00, 0x02, 0xb0, 0x00, 0x00, 0x01, 0x93, 0x00, 0x00, 0x02, 0xd8, 0x00, 0x00, 0x01, 0x94, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x01, 0x95, 0x00, 0x00, 0x03, 0x2c, 0x00, 0x00, 0x01, 0x96, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x01, 0x97, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x03, 0xac, 0x00, 0x00, 0x01, 0x99, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x01, 0x9a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x9b, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0x04, 0x54, 0x00, 0x00, 0x01, 0x9d, 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x01, 0x9e, 0x00, 0x00, 0x04, 0xa8, 0x00, 0x00, 0x01, 0x9f, 0x00, 0x00, 0x04, 0xd4, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0xa1, 0x00, 0x00, 0x05, 0x2c, 0x00, 0x00, 0x01, 0xa2, 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x05, 0x84, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x05, 0xb0, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x00, 0x05, 0xdc, 0x00, 0x00, 0x01, 0xa6, 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0xa7, 0x00, 0x00, 0x06, 0x34, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x06, 0x8c, 0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x06, 0xb8, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x06, 0xe4, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x07, 0x68, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x07, 0x94, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x07, 0xec, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x08, 0x44, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x08, 0x9c, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x08, 0xc8, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x08, 0xf4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x09, 0xa4, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x09, 0xd0, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x09, 0xfc, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x0a, 0xd8, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x0b, 0x30, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x0b, 0x5c, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x0b, 0x88, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x0b, 0xb4, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x70, 0x70, 0x00, 0x17, 0x63, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x40, 0x30, 0x00, 0x16, 0x75, 0x74, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x44, 0x40, 0x30, 0x00, 0x15, 0x76, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x76, 0x6e, 0x00, 0x15, 0x6c, 0x6f, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.18.1-msg.h000066400000000000000000000573551450431004300260060ustar00rootroot00000000000000unsigned char serialized_message_3_18_1[] = { /* serialized payload 3953 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xed, 0xe2, 0x00, 0x0a, 0xdb, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xed, 0xe2, 0x00, 0x0a, 0xdb, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x01, 0xa5, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x01, 0xa6, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x01, 0xa7, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x02, 0x5c, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x02, 0x84, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x02, 0xb0, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x02, 0xd8, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x03, 0x2c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x03, 0xac, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x04, 0x54, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x04, 0xa8, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x04, 0xd4, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x05, 0x2c, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x05, 0x84, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x05, 0xb0, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x05, 0xdc, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x06, 0x34, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x06, 0x8c, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x06, 0xb8, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x06, 0xe4, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x07, 0x68, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x07, 0x94, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x07, 0xec, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x08, 0x44, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x08, 0x9c, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x08, 0xc8, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x08, 0xf4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x09, 0xa4, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x09, 0xd0, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x09, 0xfc, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x0a, 0xd8, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x0b, 0x30, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x0b, 0x5c, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x0b, 0x88, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x0b, 0xb4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x70, 0x70, 0x00, 0x17, 0x63, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x40, 0x30, 0x00, 0x16, 0x75, 0x74, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x44, 0x40, 0x30, 0x00, 0x15, 0x76, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x76, 0x6e, 0x00, 0x15, 0x6c, 0x6f, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.21.1-msg.h000066400000000000000000000573551450431004300260000ustar00rootroot00000000000000unsigned char serialized_message_3_21_1[] = { /* serialized payload 3953 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x17, 0x00, 0x02, 0x20, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x17, 0x00, 0x02, 0x20, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x01, 0xa5, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x01, 0xa6, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x01, 0xa7, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x02, 0x5c, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x02, 0x84, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x02, 0xb0, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x02, 0xd8, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x03, 0x2c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x03, 0xac, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x04, 0x54, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x04, 0xa8, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x04, 0xd4, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x05, 0x2c, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x05, 0x84, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x05, 0xb0, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x05, 0xdc, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x06, 0x34, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x06, 0x8c, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x06, 0xb8, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x06, 0xe4, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x07, 0x68, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x07, 0x94, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x07, 0xec, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x08, 0x44, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x08, 0x9c, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x08, 0xc8, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x08, 0xf4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x09, 0xa4, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x09, 0xd0, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x09, 0xfc, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x0a, 0xd8, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x0b, 0x30, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x0b, 0x5c, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x0b, 0x88, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x0b, 0xb4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x70, 0x70, 0x00, 0x17, 0x63, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x40, 0x30, 0x00, 0x16, 0x75, 0x74, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x44, 0x40, 0x30, 0x00, 0x15, 0x76, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x76, 0x6e, 0x00, 0x15, 0x6c, 0x6f, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.25.1-msg.h000066400000000000000000000573551450431004300260040ustar00rootroot00000000000000unsigned char serialized_message_3_25_1[] = { /* serialized payload 3953 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x55, 0x00, 0x0b, 0xe0, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x55, 0x00, 0x0b, 0xe0, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x01, 0xaa, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0xaa, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x02, 0x5c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x02, 0x84, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x02, 0xb0, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x02, 0xd8, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x03, 0x2c, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x03, 0x58, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x03, 0xac, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x04, 0x54, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x04, 0xa8, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x04, 0xd4, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x05, 0x2c, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x05, 0x84, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x05, 0xb0, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x05, 0xdc, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x06, 0x34, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x06, 0x8c, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x06, 0xb8, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x06, 0xe4, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x07, 0x3c, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x07, 0x68, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x07, 0x94, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x07, 0xec, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x08, 0x44, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x08, 0x9c, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x08, 0xc8, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x08, 0xf4, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x09, 0xa4, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x09, 0xd0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x09, 0xfc, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x0a, 0xac, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x0a, 0xd8, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0b, 0x30, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0b, 0x5c, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x0b, 0x88, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x0b, 0xb4, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x0c, 0x38, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x70, 0x70, 0x00, 0x17, 0x63, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x40, 0x30, 0x00, 0x16, 0x75, 0x74, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x44, 0x40, 0x30, 0x00, 0x15, 0x76, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x76, 0x6e, 0x00, 0x15, 0x6c, 0x6f, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.26.1-msg.h000066400000000000000000000571611450431004300260000ustar00rootroot00000000000000unsigned char serialized_message_3_26_1[] = { /* serialized payload 3933 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x9b, 0x00, 0x05, 0x74, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xee, 0x9b, 0x00, 0x05, 0x74, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x01, 0xef, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x01, 0xad, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xab, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x02, 0x9c, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x03, 0x44, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x03, 0x6c, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x04, 0x94, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x05, 0x18, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x05, 0x44, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x05, 0x9c, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x05, 0xf4, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x06, 0xa4, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x06, 0xd0, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x06, 0xfc, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x07, 0x54, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x07, 0xd8, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x08, 0x5c, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x08, 0xb4, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x08, 0xe0, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x09, 0x0c, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x09, 0x90, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x09, 0xbc, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x09, 0xe8, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x0a, 0x6c, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0a, 0x98, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x0b, 0x1c, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x0b, 0x48, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x0b, 0x74, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x0b, 0xa0, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x0b, 0xcc, 0x00, 0x00, 0x01, 0xef, 0x00, 0x00, 0x0b, 0xf8, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x6f, 0x6e, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x63, 0x68, 0x69, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x74, 0x53, 0x6f, 0x00, 0x15, 0x63, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x6d, 0x70, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.28.1-msg.h000066400000000000000000000571611450431004300260020ustar00rootroot00000000000000unsigned char serialized_message_3_28_1[] = { /* serialized payload 3933 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xef, 0x69, 0x00, 0x0d, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9b, 0xef, 0x69, 0x00, 0x0d, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb0, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x02, 0x9c, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x03, 0x44, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0x6c, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x04, 0x94, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x05, 0x18, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x05, 0x44, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x05, 0x9c, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x05, 0xf4, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x06, 0xa4, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x06, 0xd0, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x06, 0xfc, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x07, 0x54, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x07, 0xd8, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x08, 0x5c, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x08, 0xb4, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x08, 0xe0, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x09, 0x0c, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x09, 0x90, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x09, 0xbc, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x09, 0xe8, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x0a, 0x6c, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x0a, 0x98, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x0b, 0x1c, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x0b, 0x48, 0x00, 0x00, 0x01, 0xef, 0x00, 0x00, 0x0b, 0x74, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x0b, 0xa0, 0x00, 0x00, 0x01, 0xf1, 0x00, 0x00, 0x0b, 0xcc, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x0b, 0xf8, 0x00, 0x00, 0x01, 0xf3, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x6f, 0x6e, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x63, 0x68, 0x69, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x74, 0x53, 0x6f, 0x00, 0x15, 0x63, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x6d, 0x70, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.29.1-msg.h000066400000000000000000000571611450431004300260030ustar00rootroot00000000000000unsigned char serialized_message_3_29_1[] = { /* serialized payload 3933 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9e, 0x4c, 0x60, 0x00, 0x08, 0xca, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9e, 0x4c, 0x60, 0x00, 0x08, 0xca, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb0, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x02, 0x9c, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x03, 0x44, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0x6c, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x04, 0x94, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x05, 0x18, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x05, 0x44, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x05, 0x9c, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x05, 0xf4, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x06, 0xa4, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x06, 0xd0, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x06, 0xfc, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x07, 0x54, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x07, 0xd8, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x08, 0x5c, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x08, 0xb4, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x08, 0xe0, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x09, 0x0c, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x09, 0x90, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x09, 0xbc, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x09, 0xe8, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x0a, 0x6c, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x0a, 0x98, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x0b, 0x1c, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x0b, 0x48, 0x00, 0x00, 0x01, 0xef, 0x00, 0x00, 0x0b, 0x74, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x0b, 0xa0, 0x00, 0x00, 0x01, 0xf1, 0x00, 0x00, 0x0b, 0xcc, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x0b, 0xf8, 0x00, 0x00, 0x01, 0xf3, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x6f, 0x6e, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x63, 0x68, 0x69, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x74, 0x53, 0x6f, 0x00, 0x15, 0x63, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x6d, 0x70, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-3.30.1-msg.h000066400000000000000000000571611450431004300257730ustar00rootroot00000000000000unsigned char serialized_message_3_30_1[] = { /* serialized payload 3933 bytes */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9e, 0x4c, 0xa8, 0x00, 0x0a, 0x1d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x9e, 0x4c, 0xa8, 0x00, 0x0a, 0x1d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x28, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x01, 0xb0, 0x32, 0x54, 0x56, 0x4e, 0x02, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x46, 0x09, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xae, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x01, 0xaf, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x01, 0xb1, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x01, 0xb3, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x01, 0xb4, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x01, 0xb5, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x01, 0xb6, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x01, 0xb9, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x01, 0xba, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x01, 0xbb, 0x00, 0x00, 0x02, 0x9c, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x01, 0xbe, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, 0x01, 0xbf, 0x00, 0x00, 0x03, 0x44, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0x6c, 0x00, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0xc2, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0xc3, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x01, 0xc5, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x01, 0xc6, 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x00, 0x04, 0x94, 0x00, 0x00, 0x01, 0xc8, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x01, 0xc9, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x01, 0xca, 0x00, 0x00, 0x05, 0x18, 0x00, 0x00, 0x01, 0xcb, 0x00, 0x00, 0x05, 0x44, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x01, 0xcd, 0x00, 0x00, 0x05, 0x9c, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x01, 0xcf, 0x00, 0x00, 0x05, 0xf4, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x01, 0xd1, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00, 0x01, 0xd2, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x06, 0xa4, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x06, 0xd0, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x00, 0x06, 0xfc, 0x00, 0x00, 0x01, 0xd6, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x01, 0xd7, 0x00, 0x00, 0x07, 0x54, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x01, 0xd9, 0x00, 0x00, 0x07, 0xac, 0x00, 0x00, 0x01, 0xda, 0x00, 0x00, 0x07, 0xd8, 0x00, 0x00, 0x01, 0xdb, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x08, 0x5c, 0x00, 0x00, 0x01, 0xde, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x01, 0xdf, 0x00, 0x00, 0x08, 0xb4, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x08, 0xe0, 0x00, 0x00, 0x01, 0xe1, 0x00, 0x00, 0x09, 0x0c, 0x00, 0x00, 0x01, 0xe2, 0x00, 0x00, 0x09, 0x38, 0x00, 0x00, 0x01, 0xe3, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x01, 0xe4, 0x00, 0x00, 0x09, 0x90, 0x00, 0x00, 0x01, 0xe5, 0x00, 0x00, 0x09, 0xbc, 0x00, 0x00, 0x01, 0xe6, 0x00, 0x00, 0x09, 0xe8, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x00, 0x01, 0xe9, 0x00, 0x00, 0x0a, 0x6c, 0x00, 0x00, 0x01, 0xea, 0x00, 0x00, 0x0a, 0x98, 0x00, 0x00, 0x01, 0xeb, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x01, 0xec, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x01, 0xed, 0x00, 0x00, 0x0b, 0x1c, 0x00, 0x00, 0x01, 0xee, 0x00, 0x00, 0x0b, 0x48, 0x00, 0x00, 0x01, 0xef, 0x00, 0x00, 0x0b, 0x74, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x0b, 0xa0, 0x00, 0x00, 0x01, 0xf1, 0x00, 0x00, 0x0b, 0xcc, 0x00, 0x00, 0x01, 0xf2, 0x00, 0x00, 0x0b, 0xf8, 0x00, 0x00, 0x01, 0xf3, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x79, 0x6e, 0x61, 0x00, 0x17, 0x63, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x61, 0x6d, 0x00, 0x16, 0x2e, 0x66, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x63, 0x2e, 0x00, 0x17, 0x65, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x2e, 0x66, 0x00, 0x16, 0x6c, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x65, 0x6c, 0x00, 0x17, 0x00, 0x76, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x64, 0x00, 0x16, 0x76, 0x61, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x36, 0x00, 0x76, 0x00, 0x17, 0x75, 0x65, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6c, 0x75, 0x65, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6f, 0x72, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x6f, 0x72, 0x00, 0x16, 0x6c, 0x2e, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x53, 0x44, 0x41, 0x00, 0x17, 0x2e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x76, 0x61, 0x00, 0x16, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x5f, 0x32, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x41, 0x6e, 0x20, 0x00, 0x17, 0x70, 0x6c, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x44, 0x41, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x69, 0x6f, 0x6e, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x63, 0x68, 0x69, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x65, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x75, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x16, 0x6e, 0x64, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x72, 0x65, 0x63, 0x00, 0x16, 0x31, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x39, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x74, 0x53, 0x6f, 0x00, 0x15, 0x63, 0x65, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x38, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x6d, 0x70, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x37, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x36, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x16, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x2e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x30, 0x00, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/messages/syslog-ng-pe-6.0-msg.h000066400000000000000000000062361450431004300261530ustar00rootroot00000000000000unsigned char serialized_pe_msg[] = { 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0xfd, 0x0f, 0x00, 0x02, 0x61, 0x60, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x56, 0xa2, 0x1e, 0xb7, 0x00, 0x0e, 0x89, 0x04, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x56, 0xa2, 0x1e, 0xb7, 0x00, 0x0e, 0x89, 0x04, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x01, 0x94, 0x00, 0x00, 0x01, 0x95, 0x00, 0x00, 0x01, 0x96, 0x00, 0x00, 0x01, 0x97, 0x32, 0x54, 0x56, 0x4e, 0x00, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x01, 0x94, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x95, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0x96, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x01, 0x97, 0x00, 0x00, 0x00, 0xf8, 0xFC, 0x03, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x41, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x44, 0x49, 0x44, 0x40, 0x30, 0x2e, 0x69, 0x75, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x65, 0x76, 0x6e, 0x74, 0x73, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x74, 0x7a, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x53, 0x44, 0x41, 0x54, 0x41, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x51, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x69, 0x73, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x00, 0x30, 0x00, 0x00, 0x00 }; syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_gsockaddr_serialize.c000066400000000000000000000133521450431004300257720ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" #include "logmsg/gsockaddr-serialize.h" #include TestSuite(gsockaddr_serialize, .init = app_startup, .fini = app_shutdown); Test(gsockaddr_serialize, test_empty) { GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); GSockAddr *read_addr = NULL; cr_assert(g_sockaddr_serialize(sa, NULL), "failed to serialize empty GSockAddr"); cr_assert(g_sockaddr_deserialize(sa, &read_addr), "failed to read back empty GSockAddr"); cr_assert_null(read_addr, "deserialized GSockAddr should be empty (NULL)"); serialize_archive_free(sa); g_string_free(stream, TRUE); } Test(gsockaddr_serialize, test_inet) { GSockAddr *addr = g_sockaddr_inet_new("127.0.0.1", 5555); GSockAddr *read_addr = NULL; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet GSockAddr"); cr_assert(g_sockaddr_deserialize(sa, &read_addr), "failed to read back inet GSockAddr"); cr_assert_arr_eq(g_sockaddr_inet_get_sa(addr), g_sockaddr_inet_get_sa(read_addr), addr->salen); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } #if SYSLOG_NG_ENABLE_IPV6 Test(gsockaddr_serialize, test_inet6) { GSockAddr *addr = g_sockaddr_inet6_new("::1", 5555); GSockAddr *read_addr = NULL; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet6 GSockAddr"); cr_assert(g_sockaddr_deserialize(sa, &read_addr), "failed to read back inet6 GSockAddr"); cr_assert_arr_eq(g_sockaddr_inet6_get_sa(addr), g_sockaddr_inet6_get_sa(read_addr), addr->salen); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } #endif Test(gsockaddr_serialize, test_unix) { GSockAddr *addr = g_sockaddr_unix_new("testpath"); GSockAddr *read_addr = NULL; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize unix GSockAddr"); cr_assert(g_sockaddr_deserialize(sa, &read_addr), "failed to read back unix GSockAddr"); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } Test(gsockaddr_serialize, test_inet_false) { GSockAddr *addr = g_sockaddr_inet_new("127.0.0.1", 5555); GSockAddr *read_addr = NULL; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet GSockAddr"); g_string_truncate(stream, 0); cr_assert_not(g_sockaddr_deserialize(sa, &read_addr), "SHOULD HAVE FAILED HERE"); serialize_archive_free(sa); sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet GSockAddr"); g_string_truncate(stream, 2); cr_assert_not(g_sockaddr_deserialize(sa, &read_addr), "SHOULD BE FAILED_HERE"); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } #if SYSLOG_NG_ENABLE_IPV6 Test(gsockaddr_serialize, test_inet6_false) { GSockAddr *addr = g_sockaddr_inet6_new("::1", 5555); GSockAddr *read_addr = NULL; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet6 GSockAddr"); g_string_truncate(stream, 0); cr_assert_not(g_sockaddr_deserialize(sa, &read_addr), "SHOULD HAVE FAILED HERE"); serialize_archive_free(sa); sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize inet6 GSockAddr"); g_string_truncate(stream, 2); cr_assert_not(g_sockaddr_deserialize(sa, &read_addr), "SHOULD BE FAILED_HERE"); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } #endif Test(gsockaddr_serialize, test_bad_family) { GSockAddr *addr = g_sockaddr_inet_new("127.0.0.1", 5555); GSockAddr *read_addr = NULL; guint16 bad_family = 0xFFFF; GString *stream = g_string_new(""); SerializeArchive *sa = serialize_string_archive_new(stream); cr_assert(g_sockaddr_serialize(sa, addr), "failed to serialize GSockAddr"); g_string_overwrite_len(stream, 0, (const gchar *)&bad_family, sizeof(bad_family)/sizeof(gchar)); cr_assert_not(g_sockaddr_deserialize(sa, &read_addr), "SHOULD HAVE FAILED HERE"); serialize_archive_free(sa); g_string_free(stream, TRUE); g_sockaddr_unref(addr); g_sockaddr_unref(read_addr); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_log_message.c000066400000000000000000000743431450431004300242560ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/msg_parse_lib.h" #include "libtest/persist_lib.h" #include "apphook.h" #include "logpipe.h" #include "scratch-buffers.h" #include "rcptid.h" typedef struct _LogMessageTestParams { LogMessage *message; LogMessage *cloned_message; NVHandle nv_handle; NVHandle sd_handle; const gchar *tag_name; } LogMessageTestParams; static LogMessage * _construct_log_message(void) { const gchar *raw_msg = "foo"; LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_HOST, raw_msg, -1); return msg; } static LogMessage * _construct_merge_base_message(void) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, "base", "basevalue", -1); log_msg_set_tag_by_name(msg, "basetag"); return msg; } static LogMessage * _construct_merged_message(const gchar *name, const gchar *value) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, name, value, -1); log_msg_set_tag_by_name(msg, "mergedtag"); return msg; } static void assert_log_msg_clear_clears_all_properties(LogMessage *message, NVHandle nv_handle, NVHandle sd_handle, const gchar *tag_name) { message->flags |= LF_LOCAL + LF_UTF8 + LF_INTERNAL + LF_MARK; log_msg_clear(message); cr_assert_str_empty(log_msg_get_value(message, nv_handle, NULL), "Message still contains value after log_msg_clear"); cr_assert_str_empty(log_msg_get_value(message, sd_handle, NULL), "Message still contains sdata value after log_msg_clear"); cr_assert_null(message->saddr, "Message still contains an saddr after log_msg_clear"); cr_assert_not(log_msg_is_tag_by_name(message, tag_name), "Message still contains a valid tag after log_msg_clear"); cr_assert((message->flags & LF_LOCAL) == 0, "Message still contains the 'local' flag after log_msg_clear"); cr_assert((message->flags & LF_UTF8) == 0, "Message still contains the 'utf8' flag after log_msg_clear"); cr_assert((message->flags & LF_MARK) == 0, "Message still contains the 'mark' flag after log_msg_clear"); cr_assert((message->flags & LF_INTERNAL) == 0, "Message still contains the 'internal' flag after log_msg_clear"); } static void assert_sdata_value_with_seqnum_equals(LogMessage *msg, guint32 seq_num, const gchar *expected) { GString *result = g_string_sized_new(0); log_msg_append_format_sdata(msg, result, seq_num); cr_assert_str_eq(result->str, expected, "SDATA value does not match, '%s' vs '%s'", expected, result->str); g_string_free(result, TRUE); } static void assert_sdata_value_equals(LogMessage *msg, const gchar *expected) { assert_sdata_value_with_seqnum_equals(msg, 0, expected); } static LogMessageTestParams * log_message_test_params_new(void) { LogMessageTestParams *params = g_new0(LogMessageTestParams, 1); params->tag_name = "tag"; params->message = _construct_log_message(); params->nv_handle = log_msg_get_value_handle("foo"); params->sd_handle = log_msg_get_value_handle(".SDATA.foo.bar"); log_msg_set_value(params->message, params->nv_handle, "value", -1); log_msg_set_value(params->message, params->sd_handle, "value", -1); params->message->saddr = g_sockaddr_inet_new("1.2.3.4", 5050); log_msg_set_tag_by_name(params->message, params->tag_name); return params; } void log_message_test_params_free(LogMessageTestParams *params) { log_msg_unref(params->message); if (params->cloned_message) log_msg_unref(params->cloned_message); g_free(params); } LogMessage * log_message_test_params_clone_message(LogMessageTestParams *params) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; params->cloned_message = log_msg_clone_cow(params->message, &path_options); return params->cloned_message; } void setup(void) { app_startup(); } void teardown(void) { scratch_buffers_explicit_gc(); deinit_syslogformat_module(); app_shutdown(); } TestSuite(log_message, .init = setup, .fini = teardown); Test(log_message, test_log_message_can_be_created_and_freed) { LogMessage *msg = _construct_log_message(); log_msg_unref(msg); } Test(log_message, test_log_message_can_be_cleared) { LogMessageTestParams *params = log_message_test_params_new(); log_message_test_params_clone_message(params); assert_log_msg_clear_clears_all_properties(params->message, params->nv_handle, params->sd_handle, params->tag_name); assert_log_msg_clear_clears_all_properties(params->cloned_message, params->nv_handle, params->sd_handle, params->tag_name); log_message_test_params_free(params); } Test(log_message, test_log_msg_clear_handles_cloned_noninline_tags_properly) { LogMessage *msg = _construct_log_message(); for (gint i = 0; i < 100; i++) { gchar tag_name[32]; g_snprintf(tag_name, sizeof(tag_name), "tag%d", i); log_msg_set_tag_by_name(msg, tag_name); } LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *cloned = log_msg_clone_cow(msg, &path_options); log_msg_clear(cloned); for (gint i = 0; i < 100; i++) { gchar tag_name[32]; g_snprintf(tag_name, sizeof(tag_name), "tag%d", i); cr_assert(log_msg_is_tag_by_name(cloned, tag_name) == FALSE); } log_msg_unref(cloned); log_msg_unref(msg); } Test(log_message, test_rcptid_is_automatically_assigned_to_a_newly_created_log_message) { LogMessage *msg; PersistState *state = clean_and_create_persist_state_for_test("test_values.persist"); rcptid_init(state, TRUE); msg = log_msg_new_empty(); cr_assert_eq(msg->rcptid, 1, "rcptid is not automatically set"); log_msg_unref(msg); commit_and_destroy_persist_state(state); rcptid_deinit(); } Test(log_message, test_log_message_merge_with_empty_context) { LogMessageTestParams *params = log_message_test_params_new(); LogMessage *context[] = {}; log_message_test_params_clone_message(params); log_msg_merge_context(params->message, context, 0); assert_log_messages_equal(params->message, params->cloned_message); log_message_test_params_free(params); } Test(log_message, test_log_message_merge_unset_value) { LogMessage *msg; GPtrArray *context = g_ptr_array_sized_new(0); msg = _construct_merge_base_message(); g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue")); log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len); assert_log_message_value_by_name(msg, "base", "basevalue"); assert_log_message_value_by_name(msg, "merged", "mergedvalue"); g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL); g_ptr_array_free(context, TRUE); log_msg_unref(msg); } Test(log_message, test_log_message_merge_doesnt_overwrite_already_set_values) { LogMessage *msg; GPtrArray *context = g_ptr_array_sized_new(0); msg = _construct_merge_base_message(); g_ptr_array_add(context, _construct_merged_message("base", "mergedvalue")); log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len); assert_log_message_value_by_name(msg, "base", "basevalue"); g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL); g_ptr_array_free(context, TRUE); log_msg_unref(msg); } Test(log_message, test_log_message_merge_merges_the_closest_value_in_the_context) { LogMessage *msg; GPtrArray *context = g_ptr_array_sized_new(0); msg = _construct_merge_base_message(); g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue1")); g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue2")); log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len); assert_log_message_value_by_name(msg, "merged", "mergedvalue2"); g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL); g_ptr_array_free(context, TRUE); log_msg_unref(msg); } Test(log_message, test_log_message_merge_merges_from_all_messages_in_the_context) { LogMessage *msg; GPtrArray *context = g_ptr_array_sized_new(0); msg = _construct_merge_base_message(); g_ptr_array_add(context, _construct_merged_message("merged1", "mergedvalue1")); g_ptr_array_add(context, _construct_merged_message("merged2", "mergedvalue2")); g_ptr_array_add(context, _construct_merged_message("merged3", "mergedvalue3")); log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len); assert_log_message_value_by_name(msg, "merged1", "mergedvalue1"); assert_log_message_value_by_name(msg, "merged2", "mergedvalue2"); assert_log_message_value_by_name(msg, "merged3", "mergedvalue3"); g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL); g_ptr_array_free(context, TRUE); log_msg_unref(msg); } Test(log_message, test_log_message_merge_leaves_base_tags_intact) { LogMessage *msg; GPtrArray *context = g_ptr_array_sized_new(0); msg = _construct_merge_base_message(); g_ptr_array_add(context, _construct_merged_message("merged1", "mergedvalue1")); log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len); assert_log_message_has_tag(msg, "basetag"); assert_log_message_doesnt_have_tag(msg, "mergedtag"); g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL); g_ptr_array_free(context, TRUE); log_msg_unref(msg); } Test(log_message, test_log_msg_set_value_indirect_with_self_referencing_handle_results_in_a_nonindirect_value) { LogMessageTestParams *params = log_message_test_params_new(); gssize value_len; log_msg_set_value_indirect(params->message, params->nv_handle, params->nv_handle, 0, 5); cr_assert_str_eq(log_msg_get_value(params->message, params->nv_handle, &value_len), "value", "indirect self-reference value doesn't match"); log_message_test_params_free(params); } Test(log_message, test_log_msg_get_value_with_time_related_macro) { LogMessage *msg; gssize value_len; NVHandle handle; const char *date_value; msg = log_msg_new_empty(); msg->timestamps[LM_TS_STAMP].ut_sec = 1389783444; msg->timestamps[LM_TS_STAMP].ut_gmtoff = 3600; handle = log_msg_get_value_handle("ISODATE"); date_value = log_msg_get_value(msg, handle, &value_len); cr_assert_str_eq(date_value, "2014-01-15T11:57:24+01:00", "ISODATE macro value does not match! value=%s", date_value); log_msg_unref(msg); } Test(log_message, test_local_logmsg_created_with_the_right_flags_and_timestamps) { LogMessage *msg = log_msg_new_local(); gboolean are_equals = unix_time_eq(&msg->timestamps[LM_TS_STAMP], &msg->timestamps[LM_TS_RECVD]); cr_assert_neq((msg->flags & LF_LOCAL), 0, "LogMessage created by log_msg_new_local() should have LF_LOCAL flag set"); cr_assert(are_equals, "The timestamps in a LogMessage created by log_msg_new_local() should be equals"); log_msg_unref(msg); } Test(log_message, test_sdata_sanitization) { LogMessage *msg; /* These keys looks strange, but JSON object can be parsed to SDATA, * so the key could contain any character, while the specification * does not declare any way to encode the keys, just the values. * The goal is to have a syntactically valid syslog message. * * Block names are sanitized with the same function as the keys, * thus no need for exhaust testing, added just one case to the end * to see if business logic applied. */ msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.bar[0]", "value[0]", -1); assert_sdata_value_equals(msg, "[foo bar%5B0%5D=\"value[0\\]\"]"); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.bácsi", "bácsi", -1); assert_sdata_value_equals(msg, "[foo b%C3%A1csi=\"bácsi\"]"); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.sp ace", "sp ace", -1); assert_sdata_value_equals(msg, "[foo sp%20ace=\"sp ace\"]"); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.eq=al", "eq=al", -1); assert_sdata_value_equals(msg, "[foo eq%3Dal=\"eq=al\"]"); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.quo\"te", "quo\"te", -1); assert_sdata_value_equals(msg, "[foo quo%22te=\"quo\\\"te\"]"); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.fo@o[0].bar", "value", -1); assert_sdata_value_equals(msg, "[fo@o%5B0%5D bar=\"value\"]"); log_msg_unref(msg); } Test(log_message, test_sdata_value_is_updated_by_sdata_name_value_pairs) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1); assert_sdata_value_equals(msg, "[foo bar1=\"value\"]"); log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1); assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\"]"); log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1); assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]"); log_msg_set_value_by_name(msg, ".SDATA.post.value1", "value", -1); assert_sdata_value_equals(msg, "[post value1=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]"); log_msg_set_value_by_name(msg, ".SDATA.post.value2", "value", -1); assert_sdata_value_equals(msg, "[post value1=\"value\" value2=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]"); log_msg_unref(msg); } Test(log_message, test_sdata_seqnum_adds_meta_sequence_id) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1); log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1); log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1); assert_sdata_value_with_seqnum_equals(msg, 5, "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"][meta sequenceId=\"5\"]"); log_msg_set_value_by_name(msg, ".SDATA.meta.foobar", "value", -1); assert_sdata_value_with_seqnum_equals(msg, 6, "[meta sequenceId=\"6\" foobar=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]"); log_msg_unref(msg); } Test(log_message, test_sdata_value_omits_unset_values) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1); log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1); log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1); assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]"); log_msg_unset_value_by_name(msg, ".SDATA.foo.bar2"); assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar3=\"value\"]"); log_msg_unset_value_by_name(msg, ".SDATA.foo.bar1"); log_msg_unset_value_by_name(msg, ".SDATA.foo.bar3"); assert_sdata_value_equals(msg, ""); log_msg_unref(msg); } Test(log_message, test_value_retains_type_information) { LogMessage *msg; LogMessageValueType type; const gchar *value; msg = log_msg_new_empty(); /* unset */ value = log_msg_get_value_by_name_with_type(msg, "nvpair", NULL, &type); cr_assert_str_empty(value); cr_assert(type == LM_VT_NULL); /* set with a specific type */ log_msg_set_value_by_name_with_type(msg, "nvpair", "value", -1, LM_VT_JSON); value = log_msg_get_value_by_name_with_type(msg, "nvpair", NULL, &type); cr_assert_str_eq(value, "value"); cr_assert(type == LM_VT_JSON); /* changed with a specific type */ log_msg_set_value_by_name_with_type(msg, "nvpair", "123", -1, LM_VT_INTEGER); value = log_msg_get_value_by_name_with_type(msg, "nvpair", NULL, &type); cr_assert_str_eq(value, "123"); cr_assert(type == LM_VT_INTEGER); /* unset becomes string again */ log_msg_unset_value_by_name(msg, "nvpair"); value = log_msg_get_value_by_name_with_type(msg, "nvpair", NULL, &type); cr_assert_str_empty(value, "value"); cr_assert(type == LM_VT_NULL); log_msg_unref(msg); } Test(log_message, test_macro_is_always_a_string) { LogMessage *msg; LogMessageValueType type; const gchar *value; msg = log_msg_new_empty(); value = log_msg_get_value_by_name_with_type(msg, "FACILITY", NULL, &type); cr_assert_str_eq(value, "user"); cr_assert(type == LM_VT_STRING); log_msg_unref(msg); } Test(log_message, test_macro_value_is_set_and_is_a_string) { LogMessage *msg; LogMessageValueType type; const gchar *value; msg = log_msg_new_empty(); value = log_msg_get_value_if_set_with_type(msg, log_msg_get_value_handle("FACILITY"), NULL, &type); cr_assert_str_eq(value, "user"); cr_assert(type == LM_VT_STRING); log_msg_unref(msg); } Test(log_message, test_set_match_returns_the_same_value_in_get) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_match(msg, 0, "match0", -1); assert_log_message_match_value(msg, 0, "match0"); log_msg_unref(msg); } Test(log_message, test_unset_match_returns_null) { LogMessage *msg; msg = log_msg_new_empty(); /* initially, it is unset */ const gchar *value = log_msg_get_match_if_set_with_type(msg, 0, NULL, NULL); cr_assert(value == NULL); /* after setting it, it is set */ log_msg_set_match(msg, 0, "match0", -1); value = log_msg_get_match_if_set_with_type(msg, 0, NULL, NULL); cr_assert_str_eq(value, "match0"); /* after unset()-ing, it is unset */ log_msg_unset_match(msg, 0); value = log_msg_get_match_if_set_with_type(msg, 0, NULL, NULL); cr_assert(value == NULL); log_msg_unref(msg); } Test(log_message, test_match_alias_numbered_macros) { LogMessage *msg; msg = log_msg_new_empty(); /* set $0 */ log_msg_set_match(msg, 0, "match0", -1); /* check both get_value and get_match returns the same */ assert_log_message_match_value(msg, 0, "match0"); assert_log_message_value_by_name(msg, "0", "match0"); /* set using set_match() */ log_msg_set_match(msg, 0, "match0-update1", -1); assert_log_message_match_value(msg, 0, "match0-update1"); assert_log_message_value_by_name(msg, "0", "match0-update1"); /* set using set_value() */ log_msg_set_value_by_name(msg, "0", "match0-update2", -1); assert_log_message_match_value(msg, 0, "match0-update2"); assert_log_message_value_by_name(msg, "0", "match0-update2"); /* unset using unset_match() */ log_msg_unset_match(msg, 0); assert_log_message_value_unset_by_name(msg, "0"); /* unset using unset_value() */ log_msg_set_value_by_name(msg, "0", "match0-update3", -1); assert_log_message_match_value(msg, 0, "match0-update3"); log_msg_unset_value_by_name(msg, "0"); assert_log_message_value_unset_by_name(msg, "0"); log_msg_set_match(msg, 128, "match128", -1); assert_log_message_value_by_name(msg, "128", "match128"); log_msg_unref(msg); } Test(log_message, test_set_match_access_out_of_range_are_ignored) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, "dummy-value", -1); /* set $0 */ log_msg_set_match(msg, 0, "match0", -1); log_msg_set_match(msg, 1, "match1", -1); log_msg_set_match(msg, 255, "match255", -1); assert_log_message_match_value(msg, 0, "match0"); assert_log_message_match_value(msg, 1, "match1"); assert_log_message_match_value(msg, 255, "match255"); log_msg_set_match(msg, 256, "match256", -1); assert_log_message_match_value(msg, 256, ""); log_msg_set_match_indirect(msg, 256, LM_V_MESSAGE, 0, 1); assert_log_message_match_value(msg, 256, ""); log_msg_set_value_indirect(msg, log_msg_get_value_handle("256"), LM_V_MESSAGE, 0, 5); assert_log_message_value_by_name(msg, "256", "dummy"); log_msg_unref(msg); } Test(log_message, test_value_that_looks_like_out_of_range_match_behaves_like_a_regular_nv_pair_and_cannot_be_accessed_as_a_match) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, "dummy-value", -1); log_msg_set_value_indirect(msg, log_msg_get_value_handle("256"), LM_V_MESSAGE, 0, 5); assert_log_message_value_by_name(msg, "256", "dummy"); assert_log_message_match_value(msg, 256, ""); log_msg_unref(msg); } Test(log_message, test_log_message_updates_num_matches_according_to_matches_being_set) { LogMessage *msg; msg = log_msg_new_empty(); cr_assert(msg->num_matches == 0); log_msg_set_match(msg, 1, "match1", -1); cr_assert(msg->num_matches == 2); log_msg_set_match(msg, 2, "match2", -1); cr_assert(msg->num_matches == 3); log_msg_set_match(msg, 3, "match3", -1); cr_assert(msg->num_matches == 4); log_msg_unref(msg); } Test(log_message, test_format_matches_produces_a_list_of_matches_even_if_populated_via_explicit_set) { LogMessage *msg; GString *result = g_string_new(""); msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "match1", -1); log_msg_set_match(msg, 2, "match2", -1); log_msg_set_match(msg, 3, "match3", -1); log_msg_format_matches(msg, result); cr_assert_str_eq(result->str, "match1,match2,match3"); log_msg_set_match(msg, 4, "match4", -1); g_string_truncate(result, 0); log_msg_format_matches(msg, result); cr_assert_str_eq(result->str, "match1,match2,match3,match4"); g_string_free(result, TRUE); log_msg_unref(msg); } Test(log_message, test_format_matches_resets_match_values_if_an_out_of_range_element_is_set) { LogMessage *msg; GString *result = g_string_new(""); msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "match1", -1); log_msg_set_match(msg, 2, "match2", -1); log_msg_set_match(msg, 3, "match3", -1); log_msg_set_match(msg, 4, "match4", -1); log_msg_truncate_matches(msg, 4); log_msg_format_matches(msg, result); /* $4 missing due to num_matches changed */ cr_assert_str_eq(result->str, "match1,match2,match3"); /* $4 was set but was not part of the array, setting $7 */ log_msg_set_match(msg, 7, "match7", -1); g_string_truncate(result, 0); log_msg_format_matches(msg, result); /* match 4 is unset even though it did hold a value before, the other in-between elements are similarly empty */ cr_assert_str_eq(result->str, "match1,match2,match3,\"\",\"\",\"\",match7"); /* fill the whole */ log_msg_set_match(msg, 4, "updated-match4", -1); g_string_truncate(result, 0); log_msg_format_matches(msg, result); /* match 5 still missing as the "whole" was just filled, but that does not include match 5 */ cr_assert_str_eq(result->str, "match1,match2,match3,updated-match4,\"\",\"\",match7"); g_string_free(result, TRUE); log_msg_unref(msg); } Test(log_message, test_changing_num_matches_causes_numbered_matches_to_become_undefined) { LogMessage *msg; GString *result = g_string_new(""); msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "match1", -1); log_msg_set_match(msg, 2, "match2", -1); log_msg_set_match(msg, 3, "match3", -1); cr_assert_eq(msg->num_matches, 4); assert_log_message_match_value(msg, 3, "match3"); log_msg_truncate_matches(msg, 3); assert_log_message_match_value(msg, 3, ""); log_msg_format_matches(msg, result); cr_assert_str_eq(result->str, "match1,match2"); g_string_free(result, TRUE); log_msg_unref(msg); } Test(log_message, test_clear_matches_call_resets_all_matches_to_unset) { LogMessage *msg; msg = log_msg_new_empty(); log_msg_set_match(msg, 0, "match0", -1); log_msg_set_match(msg, 1, "match1", -1); log_msg_set_match(msg, 2, "match2", -1); log_msg_set_match(msg, 3, "match3", -1); cr_assert_eq(msg->num_matches, 4); log_msg_clear_matches(msg); cr_assert_eq(msg->num_matches, 0); assert_log_message_match_value(msg, 0, ""); assert_log_message_match_value(msg, 1, ""); assert_log_message_match_value(msg, 2, ""); assert_log_message_match_value(msg, 3, ""); log_msg_unref(msg); } #define DEFUN_KEY_VALUE(name, key, value, size) \ gchar name ## _key[size]; \ gchar name ## _value[size]; \ name ## _key[size-1] = name ## _value[size-1] = 0; \ memset(name ## _key, key, sizeof(name ##_key)-1); \ memset(name ## _value, value, sizeof(name ##_value)-1); \ typedef struct { gssize nvtable_size_old; gssize nvtable_size_new; gssize msg_size_old; gssize msg_size_new; } sizes_t; static sizes_t add_key_value(LogMessage *msg, gchar *key, gchar *value) { sizes_t sizes; sizes.msg_size_old = log_msg_get_size(msg); sizes.nvtable_size_old = nv_table_get_memory_consumption(msg->payload); log_msg_set_value_by_name(msg, key, value, -1); sizes.nvtable_size_new = nv_table_get_memory_consumption(msg->payload); sizes.msg_size_new = log_msg_get_size(msg); return sizes; } static void test_with_sdata(LogMessage *msg, guint32 old_msg_size) { sizes_t sizes; gchar key[] = ".SDATA.**"; gchar value[] = "AAAAAAA"; guint32 single_sdata_kv_size; guint32 sdata_payload_array_size; const char iter_length = 17; for (char i = 0; i < iter_length; i++) { g_snprintf(key, sizeof(key), ".SDATA.%02d", i); sizes = add_key_value(msg, key, value); single_sdata_kv_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(strlen(key)+1 + strlen(value)+1); /* i+1 is stored, but the sdata array size is calculated when adding the i-th */ sdata_payload_array_size = STRICT_ROUND_TO_NEXT_EIGHT(i) * sizeof(msg->sdata[0]); cr_assert_eq(old_msg_size + (i+1) * single_sdata_kv_size + sdata_payload_array_size, sizes.msg_size_new); } } #define SMALL_LENGTH 10 #define LARGE_LENGTH 256 Test(log_message, test_message_size) { LogMessage *msg = log_msg_new_empty(); sizes_t sizes; DEFUN_KEY_VALUE(small, 'C', 'D', SMALL_LENGTH); sizes = add_key_value(msg, small_key, small_value); // (SMALL_LENGTH-1)*'C'+'\0' + (SMALL_LENGTH-1)*'D'+'\0' guint32 entry_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(SMALL_LENGTH + SMALL_LENGTH); cr_assert_eq(sizes.nvtable_size_old + entry_size, sizes.nvtable_size_new); cr_assert_eq(sizes.msg_size_old + entry_size, sizes.msg_size_new); // Size increased because of nvtable guint32 msg_size = sizes.msg_size_new; log_msg_set_tag_by_name(msg, "test_tag_storage"); cr_assert(log_msg_is_tag_by_name(msg, "test_tag_storage")); cr_assert_eq(msg_size, log_msg_get_size(msg)); // Tag is not increased until tag id 65 char *tag_name = strdup("00tagname"); // (*8 to convert to bits) + no need plus 1 bcause we already added one tag: test_tag_storage for (int i = 0; i < GLIB_SIZEOF_LONG*8; i++) { sprintf(tag_name, "%dtagname", i); log_msg_set_tag_by_name(msg, tag_name); } free(tag_name); cr_assert_eq(msg_size + 2*GLIB_SIZEOF_LONG, log_msg_get_size(msg)); DEFUN_KEY_VALUE(big, 'A', 'B', LARGE_LENGTH); sizes = add_key_value(msg, big_key, big_value); // nvtable is expanded entry_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(LARGE_LENGTH + LARGE_LENGTH); cr_assert_eq(sizes.nvtable_size_old + entry_size, sizes.nvtable_size_new); // but only increased by the entry cr_assert_eq(sizes.msg_size_old + entry_size, sizes.msg_size_new); // nvtable is doubled test_with_sdata(msg, sizes.msg_size_new); log_msg_unref(msg); } Test(log_message, when_get_indirect_value_with_null_value_len_abort_instead_of_sigsegv, .signal=SIGABRT) { LogMessageTestParams *params = log_message_test_params_new(); NVHandle indirect = log_msg_get_value_handle("INDIRECT"); log_msg_set_value_indirect(params->message, indirect, params->nv_handle, 0, 5); log_msg_get_value(params->message, indirect, NULL); log_message_test_params_free(params); } Test(log_message, test_cow_writing_cloned_message) { LogMessage *msg = _construct_log_message(); log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *cloned = log_msg_clone_cow(msg, &path_options); log_msg_set_value_by_name(cloned, "cloned_name", "cloned_value", -1); log_msg_set_value_by_name(cloned, "orig_name", "modified_value", -1); cr_assert_str_eq(log_msg_get_value_by_name(msg, "orig_name", NULL), "orig_value", "Modifications on a COW-cloned message should not leak into the original message; actual: %s, expected: %s", log_msg_get_value_by_name(msg, "orig_name", NULL), "orig_value"); NVHandle cloned_name = log_msg_get_value_handle("cloned_name"); gssize value_length; cr_assert_null(log_msg_get_value_if_set(msg, cloned_name, &value_length), "Modifications on a COW-cloned message should not leak into the original message"); log_msg_unref(cloned); log_msg_unref(msg); } Test(log_message, test_cow_make_writable) { LogMessage *msg = _construct_log_message(); log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1); log_msg_write_protect(msg); cr_assert(log_msg_is_write_protected(msg)); LogMessage *orig_msg = log_msg_ref(msg); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_make_writable(&msg, &path_options); log_msg_set_value_by_name(msg, "orig_name2", "orig_value2", -1); NVHandle orig_name2 = log_msg_get_value_handle("orig_name2"); gssize value_length; cr_assert_null(log_msg_get_value_if_set(orig_msg, orig_name2, &value_length), "Modifications on a COW-cloned message should not leak into the original message"); log_msg_unref(orig_msg); log_msg_unref(msg); } Test(log_message, test_cow_unset_value) { LogMessage *msg = _construct_log_message(); log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1); log_msg_write_protect(msg); LogMessage *orig_msg = log_msg_ref(msg); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_msg_make_writable(&msg, &path_options); log_msg_unset_value_by_name(msg, "orig_name"); cr_assert_str_eq(log_msg_get_value_by_name(orig_msg, "orig_name", NULL), "orig_value", "Unsetting a value in a COW-cloned message should not unset the value in the original message; actual: %s, expected: %s", log_msg_get_value_by_name(orig_msg, "orig_name", NULL), "orig_value"); log_msg_unref(orig_msg); log_msg_unref(msg); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_logmsg_ack.c000066400000000000000000000106271450431004300240720ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "logmsg/logmsg.h" #include "apphook.h" #include "logpipe.h" struct _AckRecord { LogMessage *original; LogPathOptions path_options; gboolean acked; void (*init)(AckRecord *); void (*deinit)(AckRecord *); void (*ack_message)(LogMessage *lm, AckType ack_type); }; static void _init(AckRecord *self) { self->acked = FALSE; log_msg_ref(self->original); log_msg_refcache_start_producer(self->original); log_msg_add_ack(self->original, &self->path_options); log_msg_ref(self->original); log_msg_write_protect(self->original); } static void _deinit(AckRecord *self) { log_msg_drop(self->original, &self->path_options, AT_PROCESSED); log_msg_refcache_stop(); } static void _ack_message(LogMessage *msg, AckType type) { AckRecord *self = msg->ack_record; self->acked = TRUE; } static void ack_record_free(AckRecord *self) { log_msg_unref(self->original); g_free(self); } static AckRecord * ack_record_new(void) { AckRecord *self = g_new0(AckRecord, 1); self->init = _init; self->deinit = _deinit; self->ack_message = _ack_message; self->original = log_msg_new_empty(); self->original->ack_func = self->ack_message; self->original->ack_record = self; self->path_options.ack_needed = TRUE; return self; } static void setup(void) { app_startup(); } static void teardown(void) { app_shutdown(); } static LogMessage * create_clone(LogMessage *msg, LogPathOptions *path_options) { LogMessage *cloned = log_msg_ref(msg); cloned = log_msg_make_writable(&cloned, path_options); log_msg_add_ack(msg, path_options); return cloned; } TestSuite(msg_ack, .init = setup, .fini = teardown); Test(msg_ack, normal_ack) { AckRecord *t = ack_record_new(); t->init(t); t->deinit(t); cr_assert(t->acked); ack_record_free(t); } Test(msg_ack, clone_ack) { AckRecord *t = ack_record_new(); t->init(t); LogMessage *cloned = create_clone(t->original, &t->path_options); log_msg_drop(cloned, &t->path_options, AT_PROCESSED); cr_assert_not(t->acked); t->deinit(t); cr_assert(t->acked); ack_record_free(t); } struct nv_pair { const gchar *name; const gchar *value; }; ParameterizedTestParameters(msg_ack, test_cloned_clone) { static struct nv_pair params[] = { /* This ensures, that the clone message has own payload */ {"test", "value"}, /* Using these parameters the clone message won't has own payload */ {"", ""} }; size_t nb_params = sizeof (params) / sizeof (struct nv_pair); return cr_make_param_array(struct nv_pair, params, nb_params); } /* * This tests that the clone does not break the acknowledgement or the reference counting, * whether the cloned message has own payload or not */ ParameterizedTest(struct nv_pair *param, msg_ack, test_cloned_clone) { AckRecord *t = ack_record_new(); t->init(t); LogMessage *cloned = create_clone(t->original, &t->path_options); log_msg_set_value_by_name(cloned, param->name, param->value, -1); log_msg_write_protect(cloned); LogMessage *cloned_clone1 = create_clone(cloned, &t->path_options); LogMessage *cloned_clone2 = create_clone(cloned, &t->path_options); log_msg_drop(cloned_clone1, &t->path_options, AT_PROCESSED); cr_assert_not(t->acked); log_msg_drop(cloned_clone2, &t->path_options, AT_PROCESSED); cr_assert_not(t->acked); log_msg_drop(cloned, &t->path_options, AT_PROCESSED); cr_assert_not(t->acked); t->deinit(t); cr_assert(t->acked); ack_record_free(t); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_logmsg_serialize.c000066400000000000000000000320131450431004300253140ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/msg_parse_lib.h" #include "libtest/cr_template.h" #include "libtest/stopwatch.h" #include "logmsg/logmsg.h" #include "msg-format.h" #include "apphook.h" #include "cfg.h" #include "plugin.h" #include "logmsg/logmsg-serialize.h" #define RAW_MSG "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [exampleSDID@0 iut=\"3\" eventSource=\"Application\"] An application event log entry..." #define ERROR_MSG "Failed at %s(%d)", __FILE__, __LINE__ MsgFormatOptions parse_options; static void _alloc_dummy_values_to_change_handle_values_across_restarts(void) { static gint iteration = 1; for (gint i = 0; i < iteration; i++) { gchar dummy_name[32]; g_snprintf(dummy_name, sizeof(dummy_name), "dummy%d", i); nv_registry_alloc_handle(logmsg_registry, dummy_name); } iteration *= 2; } static void _reset_log_msg_registry(void) { log_msg_registry_deinit(); log_msg_registry_init(); _alloc_dummy_values_to_change_handle_values_across_restarts(); } static void _check_deserialized_message_original_fields(LogMessage *msg) { assert_template_format_msg("${ISODATE}", "2006-10-29T01:59:59.156+01:00", msg); assert_log_message_value_and_type(msg, LM_V_HOST, "mymachine", LM_VT_STRING); assert_log_message_value_and_type(msg, LM_V_PROGRAM, "evntslog", LM_VT_STRING); assert_log_message_value_and_type(msg, LM_V_MESSAGE, "An application event log entry...", LM_VT_STRING); assert_log_message_value_unset(msg, log_msg_get_value_handle("unset_value")); assert_log_message_value_and_type(msg, log_msg_get_value_handle(".SDATA.exampleSDID@0.eventSource"), "Application", LM_VT_STRING); cr_assert_eq(msg->pri, 132, ERROR_MSG); } static void _check_deserialized_message_all_fields(LogMessage *msg) { _check_deserialized_message_original_fields(msg); assert_log_message_value(msg, log_msg_get_value_handle("indirect_1"), "val"); assert_log_message_value_and_type(msg, log_msg_get_value_handle("indirect_2"), "53", LM_VT_INTEGER); } static LogMessage * _create_message_to_be_serialized(const gchar *raw_msg, const int raw_msg_len) { parse_options.flags |= LP_SYSLOG_PROTOCOL; NVHandle test_handle = log_msg_get_value_handle("aaa"); LogMessage *msg = msg_format_parse(&parse_options, (const guchar *) raw_msg, raw_msg_len); log_msg_set_value(msg, test_handle, "test_value53", -1); NVHandle indirect_handle = log_msg_get_value_handle("indirect_1"); log_msg_set_value_indirect(msg, indirect_handle, test_handle, 5, 3); NVHandle indirect_with_type_handle = log_msg_get_value_handle("indirect_2"); log_msg_set_value_indirect_with_type(msg, indirect_with_type_handle, test_handle, 10, 2, LM_VT_INTEGER); log_msg_set_value_by_name(msg, "unset_value", "foobar", -1); log_msg_unset_value_by_name(msg, "unset_value"); for (int i = 0; i < 32; i++) { gchar value_name[64]; g_snprintf(value_name, sizeof(value_name), ".SDATA.dynamic.field%d", i); log_msg_set_value_by_name(msg, value_name, "value", -1); g_snprintf(value_name, sizeof(value_name), ".normal.dynamic.field%d", i); log_msg_set_value_by_name(msg, value_name, "value", -1); } return msg; } static SerializeArchive * _serialize_message_for_test(GString *stream, const gchar *raw_msg) { SerializeArchive *sa = serialize_string_archive_new(stream); LogMessage *msg = _create_message_to_be_serialized(raw_msg, strlen(raw_msg)); log_msg_serialize(msg, sa, 0); log_msg_unref(msg); return sa; } static LogMessage * _deserialize_message_from_string(const guint8 *serialized, gsize serialized_len) { GString s = {0}; s.allocated_len = 0; s.len = serialized_len; s.str = (gchar *) serialized; LogMessage *msg = log_msg_new_empty(); SerializeArchive *sa = serialize_string_archive_new(&s); _reset_log_msg_registry(); cr_assert(log_msg_deserialize(msg, sa), ERROR_MSG); serialize_archive_free(sa); return msg; } Test(logmsg_serialize, serialize) { GString *stream = g_string_new(""); SerializeArchive *sa = _serialize_message_for_test(stream, RAW_MSG); _reset_log_msg_registry(); LogMessage *msg = log_msg_new_empty(); cr_assert(log_msg_deserialize(msg, sa), ERROR_MSG); /* we use nv_registry_get_handle() as it will not change the name-value * pair flags, whereas log_msg_get_value_handle() would */ NVHandle sdata_handle = nv_registry_get_handle(logmsg_registry, ".SDATA.exampleSDID@0.eventSource"); cr_assert(sdata_handle != 0, "the .SDATA.exampleSDID@0.eventSource handle was not defined during deserialization"); cr_assert(log_msg_is_handle_sdata(sdata_handle), "deserialized SDATA name-value pairs have to marked as such"); _check_deserialized_message_all_fields(msg); log_msg_unref(msg); serialize_archive_free(sa); g_string_free(stream, TRUE); } static LogMessage * _create_message_to_be_serialized_with_ts_processed(const gchar *raw_msg, const int raw_msg_len, UnixTime *processed) { LogMessage *msg = _create_message_to_be_serialized(RAW_MSG, strlen(RAW_MSG)); msg->timestamps[LM_TS_PROCESSED].ut_sec = processed->ut_sec; msg->timestamps[LM_TS_PROCESSED].ut_usec = processed->ut_usec; msg->timestamps[LM_TS_PROCESSED].ut_gmtoff = processed->ut_gmtoff; return msg; } static void _check_processed_timestamp(LogMessage *msg, UnixTime *processed) { cr_assert_eq(msg->timestamps[LM_TS_PROCESSED].ut_sec, processed->ut_sec, "tv_sec value does not match"); cr_assert_eq(msg->timestamps[LM_TS_PROCESSED].ut_usec, processed->ut_usec, "tv_usec value does not match"); cr_assert_eq(msg->timestamps[LM_TS_PROCESSED].ut_gmtoff, processed->ut_gmtoff, "zone_offset value does not match"); } Test(logmsg_serialize, simple_serialization) { LogMessage *msg = _create_message_to_be_serialized(RAW_MSG, strlen(RAW_MSG)); GString *stream = g_string_sized_new(512); SerializeArchive *sa = serialize_string_archive_new(stream); log_msg_serialize(msg, sa, 0); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_deserialize(msg, sa); UnixTime ls = { .ut_sec = msg->timestamps[LM_TS_RECVD].ut_sec, .ut_usec = msg->timestamps[LM_TS_RECVD].ut_usec, .ut_gmtoff = msg->timestamps[LM_TS_RECVD].ut_gmtoff }; _check_processed_timestamp(msg, &ls); log_msg_unref(msg); serialize_archive_free(sa); g_string_free(stream, TRUE); } Test(logmsg_serialize, given_ts_processed) { LogMessage *msg = _create_message_to_be_serialized(RAW_MSG, strlen(RAW_MSG)); GString *stream = g_string_sized_new(512); SerializeArchive *sa = serialize_string_archive_new(stream); UnixTime ls = { .ut_sec = 11, .ut_usec = 12, .ut_gmtoff = 13 }; log_msg_serialize_with_ts_processed(msg, sa, &ls, 0); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_deserialize(msg, sa); _check_processed_timestamp(msg, &ls); log_msg_unref(msg); serialize_archive_free(sa); g_string_free(stream, TRUE); } Test(logmsg_serialize, existing_ts_processed) { UnixTime ls = { .ut_sec = 1, .ut_usec = 2, .ut_gmtoff = 3 }; LogMessage *msg = _create_message_to_be_serialized_with_ts_processed(RAW_MSG, strlen(RAW_MSG), &ls); GString *stream = g_string_sized_new(512); SerializeArchive *sa = serialize_string_archive_new(stream); log_msg_serialize(msg, sa, 0); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_deserialize(msg, sa); _check_processed_timestamp(msg, &ls); log_msg_unref(msg); serialize_archive_free(sa); g_string_free(stream, TRUE); } Test(logmsg_serialize, existing_and_given_ts_processed) { UnixTime ls = { .ut_sec = 1, .ut_usec = 2, .ut_gmtoff = 3 }; LogMessage *msg = _create_message_to_be_serialized_with_ts_processed(RAW_MSG, strlen(RAW_MSG), &ls); GString *stream = g_string_sized_new(512); SerializeArchive *sa = serialize_string_archive_new(stream); ls.ut_sec = 11; ls.ut_usec = 12; ls.ut_gmtoff = 13; log_msg_serialize_with_ts_processed(msg, sa, &ls, 0); log_msg_unref(msg); msg = log_msg_new_empty(); log_msg_deserialize(msg, sa); _check_processed_timestamp(msg, &ls); log_msg_unref(msg); serialize_archive_free(sa); g_string_free(stream, TRUE); } #include "messages/syslog-ng-pe-6.0-msg.h" #include "messages/syslog-ng-3.17.1-msg.h" #include "messages/syslog-ng-3.18.1-msg.h" #include "messages/syslog-ng-3.21.1-msg.h" #include "messages/syslog-ng-3.25.1-msg.h" #include "messages/syslog-ng-3.26.1-msg.h" #include "messages/syslog-ng-3.28.1-msg.h" #include "messages/syslog-ng-3.29.1-msg.h" #include "messages/syslog-ng-3.30.1-msg.h" ParameterizedTestParameters(logmsg_serialize, test_deserialization_of_legacy_messages) { static struct iovec messages[] = { { serialized_message_3_17_1, sizeof(serialized_message_3_17_1) }, { serialized_message_3_18_1, sizeof(serialized_message_3_18_1) }, { serialized_message_3_21_1, sizeof(serialized_message_3_21_1) }, { serialized_message_3_25_1, sizeof(serialized_message_3_25_1) }, { serialized_message_3_26_1, sizeof(serialized_message_3_26_1) }, { serialized_message_3_28_1, sizeof(serialized_message_3_28_1) }, { serialized_message_3_29_1, sizeof(serialized_message_3_29_1) }, { serialized_message_3_30_1, sizeof(serialized_message_3_30_1) }, }; return cr_make_param_array(struct iovec, messages, G_N_ELEMENTS(messages)); } Test(logmsg_serialize, test_deserialization_of_pe_message) { LogMessage *msg = _deserialize_message_from_string(serialized_pe_msg, sizeof(serialized_pe_msg)); _check_deserialized_message_original_fields(msg); log_msg_unref(msg); } ParameterizedTest(struct iovec *param, logmsg_serialize, test_deserialization_of_legacy_messages) { LogMessage *msg = _deserialize_message_from_string(param->iov_base, param->iov_len); _check_deserialized_message_all_fields(msg); log_msg_unref(msg); } Test(logmsg_serialize, serialization_performance) { LogMessage *msg = _create_message_to_be_serialized(RAW_MSG, strlen(RAW_MSG)); GString *stream = g_string_sized_new(512); const int iterations = 100000; SerializeArchive *sa = serialize_string_archive_new(stream); start_stopwatch(); for (int i = 0; i < iterations; i++) { g_string_truncate(stream, 0); log_msg_serialize(msg, sa, 0); } stop_stopwatch_and_display_result(iterations, "serializing (without compaction) %d times took", iterations); serialize_archive_free(sa); log_msg_unref(msg); g_string_free(stream, TRUE); } Test(logmsg_serialize, serialization_with_compaction_performance) { LogMessage *msg = _create_message_to_be_serialized(RAW_MSG, strlen(RAW_MSG)); GString *stream = g_string_sized_new(512); const int iterations = 100000; SerializeArchive *sa = serialize_string_archive_new(stream); start_stopwatch(); for (int i = 0; i < iterations; i++) { g_string_truncate(stream, 0); log_msg_serialize(msg, sa, LMSF_COMPACTION); } stop_stopwatch_and_display_result(iterations, "serializing (with compaction) %d times took", iterations); serialize_archive_free(sa); log_msg_unref(msg); g_string_free(stream, TRUE); } Test(logmsg_serialize, deserialization_performance) { GString *stream = g_string_sized_new(512); SerializeArchive *sa = _serialize_message_for_test(stream, RAW_MSG); const int iterations = 100000; LogMessage *msg; start_stopwatch(); for (int i = 0; i < iterations; i++) { serialize_string_archive_reset(sa); msg = log_msg_new_empty(); log_msg_deserialize(msg, sa); log_msg_unref(msg); } stop_stopwatch_and_display_result(iterations, "deserializing %d times took", iterations); serialize_archive_free(sa); g_string_free(stream, TRUE); } static void setup(void) { app_startup(); init_template_tests(); configuration->template_options.frac_digits = 3; msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); } static void teardown(void) { deinit_template_tests(); app_shutdown(); } TestSuite(logmsg_serialize, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_nvhandle_desc_array.c000066400000000000000000000036751450431004300257640ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "logmsg/nvhandle-descriptors.h" #include Test(nvhandle_desc_array, add_elements) { NVHandleDesc desc0 = { .name = g_strdup("test0"), .flags = 0, .name_len = strlen("test0")}; NVHandleDesc desc1 = { .name = g_strdup("test1"), .flags = 1, .name_len = strlen("test1")}; NVHandleDesc desc2 = { .name = g_strdup("test2"), .flags = 2, .name_len = strlen("test2")}; NVHandleDesc desc3 = { .name = g_strdup("test3"), .flags = 3, .name_len = strlen("test3")}; NVHandleDescArray *array = nvhandle_desc_array_new(2); nvhandle_desc_array_append(array, &desc0); nvhandle_desc_array_append(array, &desc1); nvhandle_desc_array_append(array, &desc2); nvhandle_desc_array_append(array, &desc3); cr_assert_eq(array->len, 4); NVHandleDesc *candidate = &nvhandle_desc_array_index(array, 2); cr_assert_eq(candidate->flags, 2); cr_assert_str_eq(candidate->name, "test2"); cr_assert_eq(candidate->name_len, strlen("test2")); nvhandle_desc_array_free(array); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_nvtable.c000066400000000000000000001151631450431004300234200ustar00rootroot00000000000000/* * Copyright (c) 2009-2016 Balabit * Copyright (c) 2009-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "logmsg/nvtable.h" #include "apphook.h" #include "logmsg/logmsg.h" #include #include #include #define STATIC_VALUES 16 #define STATIC_HANDLE 1 #define STATIC_NAME "VAL1" #define DYN_HANDLE 17 #define DYN_NAME "VAL17" void assert_nvtable(NVTable *tab, NVHandle handle, gchar *expected_value, gssize expected_length) { const gchar *value; gssize length; value = nv_table_get_value(tab, handle, &length, NULL); cr_assert_eq(length, expected_length, "NVTable value mismatch, value=%.*s, expected=%.*s\n", (gint) length, value, (gint) expected_length, expected_value); cr_assert_arr_eq(value, expected_value, expected_length, "NVTable value mismatch, value=%.*s, expected=%.*s\n", (gint) length, value, (gint) expected_length, expected_value); } TestSuite(nvtable, .init = app_startup, .fini = app_shutdown); /* NVRegistry */ /* testcases: * * - static names will have the lowest numbered handles, starting with 1 * - registering the same name will always map to the same handle * - adding an alias and looking up an NV pair by alias should return the same handle * - NV pairs cannot have the zero-length string as a name * - NV pairs cannot have names longer than 255 characters * - no more than predefined number of NV pairs are supported * - */ #define TEST_NVHANDLE_MAX_VALUE 10 Test(nvtable, test_nv_registry) { NVRegistry *reg; gint i, j; NVHandle handle, prev_handle; const gchar *name; gssize len; const gchar *builtins[] = { "BUILTIN1", "BUILTIN2", "BUILTIN3", NULL }; reg = nv_registry_new(builtins, TEST_NVHANDLE_MAX_VALUE); for (i = 0; builtins[i]; i++) { handle = nv_registry_alloc_handle(reg, builtins[i]); cr_assert_eq(handle, (i+1)); name = nv_registry_get_handle_name(reg, handle, &len); cr_assert_str_eq(name, builtins[i]); cr_assert_eq(strlen(name), len); } for (i = 4; i < TEST_NVHANDLE_MAX_VALUE + 1; i++) { gchar dyn_name[16]; g_snprintf(dyn_name, sizeof(dyn_name), "DYN%05d", i); /* try to look up the same name multiple times */ prev_handle = 0; for (j = 0; j < 4; j++) { handle = nv_registry_alloc_handle(reg, dyn_name); g_assert(prev_handle == 0 || (handle == prev_handle)); prev_handle = handle; } name = nv_registry_get_handle_name(reg, handle, &len); g_assert(strcmp(name, dyn_name) == 0); g_assert(strlen(name) == len); g_snprintf(dyn_name, sizeof(dyn_name), "ALIAS%05d", i); nv_registry_add_alias(reg, handle, dyn_name); handle = nv_registry_alloc_handle(reg, dyn_name); g_assert(handle == prev_handle); } for (i = TEST_NVHANDLE_MAX_VALUE; i >= 4; i--) { gchar dyn_name[16]; g_snprintf(dyn_name, sizeof(dyn_name), "DYN%05d", i); /* try to look up the same name multiple times */ prev_handle = 0; for (j = 0; j < 4; j++) { handle = nv_registry_alloc_handle(reg, dyn_name); g_assert(prev_handle == 0 || (handle == prev_handle)); prev_handle = handle; } name = nv_registry_get_handle_name(reg, handle, &len); g_assert(strcmp(name, dyn_name) == 0); g_assert(strlen(name) == len); } handle = nv_registry_alloc_handle(reg, "too-many-values"); cr_assert_eq(handle, 0); nv_registry_free(reg); } /* * - NVTable direct values * - set/get static NV entries * - new NV entry * - entries that fit into the current NVTable * - entries that do not fit into the current NVTable * - overwrite direct NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable * - overwrite indirect NV entry: not possible as static entries cannot be indirect * * - set/get dynamic NV entries * - new NV entry * - entries that fit into the current NVTable * - entries that do not fit into the current NVTable * - overwrite direct NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable * - overwrite indirect NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable */ Test(nvtable, test_nvtable_direct) { NVTable *tab; NVHandle handle; gchar value[1024], name[16]; gboolean success; gint i; guint16 used; for (i = 0; i < sizeof(value); i++) value[i] = 'A' + (i % 26); handle = STATIC_HANDLE; do { g_snprintf(name, sizeof(name), "VAL%d", handle); /*************************************************************/ /* new NV entry */ /*************************************************************/ /* one that fits */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, handle, name, strlen(name), value, 128, 0, NULL); cr_assert(success); assert_nvtable(tab, handle, value, 128); nv_table_unref(tab); /* one that is too large */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, handle, name, strlen(name), value, 512, 0, NULL); cr_assert_not(success); nv_table_unref(tab); /*************************************************************/ /* overwrite NV entry */ /*************************************************************/ /* one that fits, but realloced size wouldn't fit */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, handle, name, strlen(name), value, 128, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value(tab, handle, name, strlen(name), value, 64, 0, NULL); cr_assert(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, handle, value, 64); nv_table_unref(tab); /* one that is too large for the given entry, but still fits in the NVTable */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, handle, name, strlen(name), value, 64, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value(tab, handle, name, strlen(name), value, 128, 0, NULL); cr_assert(success); cr_assert_gt(tab->used, used); assert_nvtable(tab, handle, value, 128); nv_table_unref(tab); /* one that is too large for the given entry, and also for the NVTable */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, handle, name, strlen(name), value, 64, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 512, 0, NULL); cr_assert_not(success); assert_nvtable(tab, handle, value, 64); nv_table_unref(tab); /*************************************************************/ /* overwrite indirect entry */ /*************************************************************/ if (handle > STATIC_VALUES) { /* we can only test this with dynamic entries */ /* setup code: add static and a dynamic-indirect entry */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); used = tab->used; /* store a direct entry over the indirect one */ success = nv_table_add_value(tab, handle, name, strlen(name), value, 1, 0, NULL); cr_assert(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value, 1); nv_table_unref(tab); /* setup code: add static and a dynamic-indirect entry */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 64, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 63 }, 0, NULL); cr_assert(success); used = tab->used; /* store a direct entry over the indirect one, we don't fit in the allocated space */ success = nv_table_add_value(tab, handle, name, strlen(name), value, 128, 0, NULL); cr_assert(success); cr_assert_gt(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 64); assert_nvtable(tab, handle, value, 128); nv_table_unref(tab); /* setup code: add static and a dynamic-indirect entry */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 64, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 62 }, 0, NULL); cr_assert(success); used = tab->used; /* store a direct entry over the indirect one, we don't fit in the allocated space */ success = nv_table_add_value(tab, handle, name, strlen(name), value, 256, 0, NULL); cr_assert_not(success); assert_nvtable(tab, STATIC_HANDLE, value, 64); assert_nvtable(tab, handle, value + 1, 62); nv_table_unref(tab); } handle += STATIC_VALUES; } while (handle < 2 * STATIC_VALUES); } /* * - indirect values * - indirect static values are not possible * - set/get dynamic NV entries that refer to direct entries * - new NV entry * - entries that fit into the current NVTable * - entries that do not fit into the current NVTable * - overwrite indirect NV entry * - value always fits to a current NV entry, no other cases * - overwrite direct NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable * - set/get dynamic NV entries that refer to indirect entry, they become direct entries * - new NV entry * - entries that fit into the current NVTable * - entries that do not fit into the current NVTable * - overwrite indirect NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable * - overwrite direct NV entry * - value that fits into the current entry * - value that doesn't fit into the current entry, but fits into NVTable * - value that doesn't fit into the current entry and neither to NVTable * - set/get dynamic NV entries that refer to a non-existent entry * - */ Test(nvtable, test_nvtable_indirect) { NVTable *tab; NVHandle handle; gchar value[1024], name[16]; gboolean success; gint i; guint16 used; for (i = 0; i < sizeof(value); i++) value[i] = 'A' + (i % 26); handle = DYN_HANDLE+1; g_snprintf(name, sizeof(name), "VAL%d", handle); fprintf(stderr, "Testing indirect values, name: %s, handle: %d\n", name, handle); /*************************************************************/ /*************************************************************/ /* indirect entries that refer to direct entries */ /*************************************************************/ /*************************************************************/ /*************************************************************/ /* new NV entry */ /*************************************************************/ /* one that fits */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); /* one that is too large */ /* NOTE: the sizing of the NVTable can easily be broken, it is sized to make it possible to store one direct entry */ tab = nv_table_new(STATIC_VALUES, 0, 138+3); // direct: +3 success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert_not(success); nv_table_unref(tab); /*************************************************************/ /* overwrite NV entry */ /*************************************************************/ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 62 }, 0, NULL); cr_assert(success); cr_assert_eq(used, tab->used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value + 1, 62); nv_table_unref(tab); /*************************************************************/ /* overwrite direct entry */ /*************************************************************/ /* the new entry fits to the space allocated to the old */ /* setup code: add static and a dynamic-direct entry */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 64, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); /* the new entry will not fit to the space allocated to the old */ /* setup code: add static and a dynamic-direct entry */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 1, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); cr_assert_gt(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); /* the new entry will not fit to the space allocated to the old and neither to the NVTable */ /* setup code: add static and a dynamic-direct entry */ tab = nv_table_new(STATIC_VALUES, 1, 154+3+4); // direct: +3, indirect: +4 success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 1, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert_not(success); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value, 1); nv_table_unref(tab); /*************************************************************/ /*************************************************************/ /* indirect entries that refer to indirect entries */ /*************************************************************/ /*************************************************************/ /*************************************************************/ /* new NV entry */ /*************************************************************/ /* one that fits */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 122 }, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 2, 122); nv_table_unref(tab); /* one that is too large */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 122 }, 0, NULL); cr_assert_not(success); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, "", 0); nv_table_unref(tab); /*************************************************************/ /* overwrite indirect NV entry */ /*************************************************************/ /* we fit to the space of the old */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 1 }, 0, NULL); cr_assert(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 2, 1); nv_table_unref(tab); /* the new entry will not fit to the space allocated to the old */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 16 }, 0, NULL); cr_assert(success); cr_assert_gt(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 2, 16); nv_table_unref(tab); /* one that is too large */ tab = nv_table_new(STATIC_VALUES, 4, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 124 }, 0, NULL); cr_assert_not(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); /*************************************************************/ /* overwrite direct NV entry */ /*************************************************************/ /* we fit to the space of the old */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 64, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 16 }, 0, NULL); cr_assert(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 2, 16); nv_table_unref(tab); /* the new entry will not fit to the space allocated to the old */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 16, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 32 }, 0, NULL); cr_assert(success); cr_assert_gt(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value + 2, 32); nv_table_unref(tab); /* one that is too large */ tab = nv_table_new(STATIC_VALUES, 4, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, handle, name, strlen(name), value, 16, 0, NULL); cr_assert(success); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { DYN_HANDLE, 1, 124 }, 0, NULL); cr_assert_not(success); cr_assert_eq(tab->used, used); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, DYN_HANDLE, value + 1, 126); assert_nvtable(tab, handle, value, 16); nv_table_unref(tab); /*************************************************************/ /* indirect that refers to non-existent entry */ /*************************************************************/ /* one that fits */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); used = tab->used; success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); cr_assert_eq(used, tab->used); assert_nvtable(tab, STATIC_HANDLE, "", 0); assert_nvtable(tab, handle, "", 0); nv_table_unref(tab); } /* * * - other corner cases * - set zero length value in direct value * - add a zero-length value to non-existing entry * - add a zero-length value to an existing entry that is not zero-length * - add a zero-length value to an existing entry that is zero-length * - set zero length value in an indirect value * * - change an entry that is referenced by other entries */ Test(nvtable, test_nvtable_others) { NVTable *tab; NVHandle handle; gchar value[1024], name[16]; gboolean success; gint i; for (i = 0; i < sizeof(value); i++) value[i] = 'A' + (i % 26); handle = DYN_HANDLE+1; g_snprintf(name, sizeof(name), "VAL%d", handle); fprintf(stderr, "Testing other cases, name: %s, handle: %d\n", name, handle); /* one that fits */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 256); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value + 32, 32, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, value + 32, 32); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); /* one that doesn't fit */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 192); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value, 128, 0, NULL); cr_assert(success); success = nv_table_add_value_indirect(tab, handle, name, strlen(name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 126 }, 0, NULL); cr_assert(success); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, 4, value + 32, 32, 0, NULL); cr_assert_not(success); assert_nvtable(tab, STATIC_HANDLE, value, 128); assert_nvtable(tab, handle, value + 1, 126); nv_table_unref(tab); } Test(nvtable, test_nvtable_lookup) { NVTable *tab; NVHandle handle; gchar name[16]; gboolean success; gint i; NVHandle handles[100]; gint x; srand(time(NULL)); for (x = 0; x < 100; x++) { /* test dynamic lookup */ tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 4096); for (i = 0; i < 100; i++) { do { handle = rand() & 0x8FFF; } while (handle == 0); g_snprintf(name, sizeof(name), "VAL%d", handle); success = nv_table_add_value(tab, handle, name, strlen(name), name, strlen(name), 0, NULL); g_assert(success); handles[i] = handle; } for (i = 99; i >= 0; i--) { handle = handles[i]; g_snprintf(name, sizeof(name), "VAL%d", handle); assert_nvtable(tab, handles[i], name, strlen(name)); g_assert(nv_table_is_value_set(tab, handles[i])); } cr_assert_not(nv_table_is_value_set(tab, 0xFE00)); nv_table_unref(tab); } } Test(nvtable, test_nvtable_clone_grows_the_cloned_structure) { NVTable *tab, *tab_clone; gboolean success; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 64); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, "value", 5); tab_clone = nv_table_clone(tab, 64); assert_nvtable(tab_clone, STATIC_HANDLE, "value", 5); cr_assert_lt(tab->size, tab_clone->size); nv_table_unref(tab_clone); nv_table_unref(tab); } Test(nvtable, test_nvtable_clone_cannot_grow_nvtable_larger_than_nvtable_max_bytes) { NVTable *tab, *tab_clone; gboolean success; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, NV_TABLE_MAX_BYTES - 1024); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, "value", 5); tab_clone = nv_table_clone(tab, 2048); assert_nvtable(tab_clone, STATIC_HANDLE, "value", 5); cr_assert_lt(tab->size, tab_clone->size); cr_assert_leq(tab_clone->size, NV_TABLE_MAX_BYTES); nv_table_unref(tab_clone); nv_table_unref(tab); } Test(nvtable, test_nvtable_realloc_doubles_nvtable_size) { NVTable *tab; gboolean success; gsize old_size; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, "value", 5); old_size = tab->size; cr_assert(nv_table_realloc(tab, &tab)); cr_assert_geq(tab->size, old_size * 2); assert_nvtable(tab, STATIC_HANDLE, "value", 5); nv_table_unref(tab); } Test(nvtable, test_nvtable_realloc_sets_size_to_nv_table_max_bytes_at_most) { NVTable *tab; gboolean success; gsize old_size; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, NV_TABLE_MAX_BYTES - 1024); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, "value", 5); old_size = tab->size; cr_assert(nv_table_realloc(tab, &tab)); cr_assert_gt(tab->size, old_size); cr_assert_leq(tab->size, NV_TABLE_MAX_BYTES); assert_nvtable(tab, STATIC_HANDLE, "value", 5); nv_table_unref(tab); } Test(nvtable, test_nvtable_realloc_fails_if_size_is_at_maximum) { NVTable *tab; gboolean success; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, NV_TABLE_MAX_BYTES); success = nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab, STATIC_HANDLE, "value", 5); cr_assert_not(nv_table_realloc(tab, &tab)); cr_assert_eq(tab->size, NV_TABLE_MAX_BYTES); assert_nvtable(tab, STATIC_HANDLE, "value", 5); nv_table_unref(tab); } Test(nvtable, test_nvtable_realloc_leaves_original_intact_if_there_are_multiple_references) { NVTable *tab_ref1, *tab_ref2; gboolean success; gsize old_size; tab_ref1 = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); tab_ref2 = nv_table_ref(tab_ref1); success = nv_table_add_value(tab_ref1, STATIC_HANDLE, STATIC_NAME, strlen(STATIC_NAME), "value", 5, 0, NULL); cr_assert(success); assert_nvtable(tab_ref1, STATIC_HANDLE, "value", 5); assert_nvtable(tab_ref2, STATIC_HANDLE, "value", 5); old_size = tab_ref1->size; cr_assert(nv_table_realloc(tab_ref2, &tab_ref2)); cr_assert_eq(tab_ref1->size, old_size); cr_assert_geq(tab_ref2->size, old_size); assert_nvtable(tab_ref1, STATIC_HANDLE, "value", 5); assert_nvtable(tab_ref2, STATIC_HANDLE, "value", 5); nv_table_unref(tab_ref1); nv_table_unref(tab_ref2); } Test(nvtable, test_nvtable_unset_values) { NVTable *tab; gssize size = 9999; const gchar *value; gboolean success; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_null(value); cr_assert_eq(size, 0); size = 1; value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_null(value); cr_assert_eq(size, 0); success = nv_table_add_value(tab, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), "foo", 3, 0, NULL); cr_assert(success); size = 1; value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert_arr_eq(value, "foo", 3); cr_assert_eq(size, 3); nv_table_unset_value(tab, DYN_HANDLE); size = 1; value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_null(value); cr_assert_eq(size, 0); nv_table_unref(tab); } Test(nvtable, test_nvtable_unset_copies_indirect_references) { NVTable *tab; gssize size = 9999; const gchar *value; const gchar *indirect_nv_name = "indirect-name"; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(DYN_NAME), "static-foo", 10, 0, NULL); nv_table_add_value_indirect(tab, DYN_HANDLE, indirect_nv_name, strlen(indirect_nv_name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 5 }, 0, NULL); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "tatic", 5) == 0); cr_assert_eq(size, 5); nv_table_unset_value(tab, STATIC_HANDLE); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "tatic", 5) == 0); cr_assert_eq(size, 5); nv_table_unref(tab); } Test(nvtable, test_nvtable_indirect_references_unset_and_then_set_again_are_present) { NVTable *tab; gssize size = 9999; const gchar *value; const gchar *indirect_nv_name = "indirect-name"; tab = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); nv_table_add_value(tab, STATIC_HANDLE, STATIC_NAME, strlen(DYN_NAME), "static-foo", 10, 0, NULL); nv_table_add_value_indirect(tab, DYN_HANDLE, indirect_nv_name, strlen(indirect_nv_name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 5 }, 0, NULL); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "tatic", 5) == 0); cr_assert_eq(size, 5); nv_table_unset_value(tab, DYN_HANDLE); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_null(value); nv_table_add_value_indirect(tab, DYN_HANDLE, indirect_nv_name, strlen(indirect_nv_name), &(NVReferencedSlice) { STATIC_HANDLE, 2, 4 }, 0, NULL); value = nv_table_get_value(tab, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "atic", 4) == 0); cr_assert_eq(size, 4); nv_table_unref(tab); } Test(nvtable, test_nvtable_compact_copies_name_value_pairs) { NVTable *tab1, *tab2; gssize size = 9999; const gchar *value; const gchar *indirect_nv_name = "indirect-name"; tab1 = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); nv_table_add_value(tab1, STATIC_HANDLE, STATIC_NAME, strlen(DYN_NAME), "static-foo", 10, 0, NULL); nv_table_add_value(tab1, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), "dyn-foo", 7, 0, NULL); nv_table_add_value_indirect(tab1, DYN_HANDLE+1, indirect_nv_name, strlen(indirect_nv_name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 5 }, 0, NULL); tab2 = nv_table_compact(tab1); nv_table_unref(tab1); value = nv_table_get_value(tab2, DYN_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert_str_eq(value, "dyn-foo"); cr_assert_eq(size, 7); value = nv_table_get_value(tab2, STATIC_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert_str_eq(value, "static-foo"); cr_assert_eq(size, 10); value = nv_table_get_value(tab2, DYN_HANDLE+1, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "tatic", size) == 0); cr_assert_eq(size, 5); nv_table_unref(tab2); } Test(nvtable, test_nvtable_compact_skips_unset_values) { NVTable *tab1, *tab2; gssize size = 9999; const gchar *value; const gchar *indirect_nv_name = "indirect-name"; tab1 = nv_table_new(STATIC_VALUES, STATIC_VALUES, 1024); nv_table_add_value(tab1, STATIC_HANDLE, STATIC_NAME, strlen(DYN_NAME), "static-foo", 10, 0, NULL); nv_table_add_value(tab1, DYN_HANDLE, DYN_NAME, strlen(DYN_NAME), "dyn-foo", 7, 0, NULL); nv_table_add_value_indirect(tab1, DYN_HANDLE+1, indirect_nv_name, strlen(indirect_nv_name), &(NVReferencedSlice) { STATIC_HANDLE, 1, 5 }, 0, NULL); nv_table_unset_value(tab1, DYN_HANDLE); /* this should get rid off the unset value, thus used should be smaller */ tab2 = nv_table_compact(tab1); cr_assert(tab2->used < tab1->used); nv_table_unref(tab1); value = nv_table_get_value(tab2, DYN_HANDLE, &size, NULL); cr_assert_null(value); cr_assert_eq(size, 0); value = nv_table_get_value(tab2, STATIC_HANDLE, &size, NULL); cr_assert_not_null(value); cr_assert_str_eq(value, "static-foo"); cr_assert_eq(size, 10); value = nv_table_get_value(tab2, DYN_HANDLE+1, &size, NULL); cr_assert_not_null(value); cr_assert(strncmp(value, "tatic", size) == 0); cr_assert_eq(size, 5); nv_table_unref(tab2); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_tags.c000066400000000000000000000135661450431004300227270ustar00rootroot00000000000000/* * Copyright (c) 2009-2016 Balabit * Copyright (c) 2009 Marton Illes * Copyright (c) 2009-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include #include "apphook.h" #include "logmsg/logmsg.h" #include "messages.h" #include "filter/filter-tags.h" #include #include #include #include #include #define NUM_TAGS 8159 #define FILTER_TAGS 100 static gchar * get_tag_by_id(LogTagId id) { return g_strdup_printf("tags%d", id); } Test(tags, test_tags) { guint i, check; guint id; gchar *name; const gchar *tag_name; for (check = 0; check < 2; check++) for (i = 0; i < NUM_TAGS; i++) { name = get_tag_by_id(i); id = log_tags_get_by_name(name); cr_log_info("%s tag %s %d\n", check ? "Checking" : "Adding", name, id); cr_assert_eq(id, i, "Invalid tag id %d %s", id, name); g_free(name); } for (i = 0; i < NUM_TAGS; i++) { name = get_tag_by_id(i); tag_name = log_tags_get_by_id(i); cr_log_info("Looking up tag by id %d %s(%s)\n", i, tag_name, name); cr_assert_not_null(tag_name, "Error looking up tag by id %d %s\n", i, name); cr_assert_str_eq(name, tag_name, "Bad tag name for id %d %s (%s)\n", i, tag_name, name); g_free(name); } for (i = NUM_TAGS; i < (NUM_TAGS + 3); i++) { cr_log_info("Looking up tag by invalid id %d\n", i); tag_name = log_tags_get_by_id(i); cr_assert_not(tag_name, "Found tag name for invalid id %d %s\n", i, tag_name); } } Test(tags, test_msg_tags) { gchar *name; gint i, set; cr_log_info("=== LogMessage tests ===\n"); LogMessage *msg = log_msg_new_empty(); for (set = 1; set != -1; set--) { for (i = 0; i < NUM_TAGS; i++) { name = get_tag_by_id(i); LogTagId id = log_tags_get_by_name(name); if (set) log_msg_set_tag_by_name(msg, name); else log_msg_clear_tag_by_name(msg, name); cr_log_info("%s tag %d %s\n", set ? "Setting" : "Clearing", id, name); cr_assert_not(set ^ log_msg_is_tag_by_id(msg, id), "Tag is %sset now (by id) %d", set ? "not " : "", id); g_free(name); } } log_msg_unref(msg); msg = log_msg_new_empty(); for (set = 1; set != -1; set--) { for (i = 0; i < NUM_TAGS; i++) { name = get_tag_by_id(i); if (set) log_msg_set_tag_by_name(msg, name); else log_msg_clear_tag_by_name(msg, name); cr_log_info("%s tag %d %s\n", set ? "Setting" : "Clearing", i, name); cr_assert_not(set ^ log_msg_is_tag_by_id(msg, i), "Tag is %sset now (by id) %d\n", set ? "not " : "", i); cr_assert_not(set && i < sizeof(gulong) * 8 && msg->num_tags != 0, "Small IDs are set which should be stored in-line but num_tags is non-zero"); g_free(name); } } log_msg_unref(msg); } Test(tags, test_filters_true) { LogMessage *msg = log_msg_new_empty(); FilterExprNode *f = filter_tags_new(NULL); guint i; GList *l = NULL; gchar *name; cr_log_info("=== filter tests not===\n"); for (i = 1; i < FILTER_TAGS; i += 3) l = g_list_prepend(l, get_tag_by_id(i)); filter_tags_add(f, l); f->comp = TRUE; for (i = 0; i < FILTER_TAGS; i++) { cr_log_info("Testing filter, message has tag %d\n", i); name = get_tag_by_id(i); LogTagId id = log_tags_get_by_name(name); g_free(name); log_msg_set_tag_by_id(msg, id); cr_assert(((i % 3 == 1) ^ filter_expr_eval(f, msg)), "Failed to match message by tag %d\n", id); cr_log_info("Testing filter, message no tag\n"); log_msg_clear_tag_by_id(msg, id); cr_assert(filter_expr_eval(f, msg), "Failed to match message with no tags\n"); } filter_expr_unref(f); log_msg_unref(msg); } Test(tags, test_filters_false) { LogMessage *msg = log_msg_new_empty(); FilterExprNode *f = filter_tags_new(NULL); guint i; GList *l = NULL; gchar *name; cr_log_info("=== filter tests ===\n"); for (i = 1; i < FILTER_TAGS; i += 3) l = g_list_prepend(l, get_tag_by_id(i)); filter_tags_add(f, l); f->comp = FALSE; for (i = 0; i < FILTER_TAGS; i++) { cr_log_info("Testing filter, message has tag %d\n", i); name = get_tag_by_id(i); LogTagId id = log_tags_get_by_name(name); g_free(name); log_msg_set_tag_by_id(msg, id); cr_assert_not(((i % 3 == 1) ^ filter_expr_eval(f, msg)), "Failed to match message by tag %d\n", id); cr_log_info("Testing filter, message no tag\n"); log_msg_clear_tag_by_id(msg, id); cr_assert_not(filter_expr_eval(f, msg), "Failed to match message with no tags\n"); } filter_expr_unref(f); log_msg_unref(msg); } static void setup(void) { app_startup(); msg_init(TRUE); } static void teardown(void) { app_shutdown(); } TestSuite(tags, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_timestamp_serialize.c000066400000000000000000000063301450431004300260320ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "logmsg/logmsg.h" #include "logmsg/timestamp-serialize.h" #include "apphook.h" SerializeArchive *sa = NULL; GString *stream = NULL; UnixTime input_timestamps[LM_TS_MAX]; UnixTime output_timestamps[LM_TS_MAX]; Test(template_timestamp, test_normal_working) { cr_assert(timestamp_serialize(sa, input_timestamps), "Failed to serialize timestamps"); cr_assert(timestamp_deserialize(sa, output_timestamps), "Failed to deserialize timestamps"); cr_assert_str_eq((const gchar *)input_timestamps, (const gchar *)output_timestamps, "The serialized and the deserialized timestamps are not equal"); } Test(template_timestamp, test_derializing_injured_timestamp) { cr_assert(timestamp_serialize(sa, input_timestamps), "Failed to serialize timestamps"); g_string_truncate(stream, 0); cr_assert_not(timestamp_deserialize(sa, output_timestamps), "Should be failed"); serialize_archive_free(sa); sa = serialize_string_archive_new(stream); cr_assert(timestamp_serialize(sa, input_timestamps), "Failed to serialize timestamps"); g_string_truncate(stream, sizeof(guint64)); cr_assert_not(timestamp_deserialize(sa, output_timestamps), "Should be failed"); serialize_archive_free(sa); sa = serialize_string_archive_new(stream); cr_assert(timestamp_serialize(sa, input_timestamps), "Failed to serialize timestamps"); g_string_truncate(stream, sizeof(guint64) + sizeof(guint32)); cr_assert_not(timestamp_deserialize(sa, output_timestamps), "Should be failed"); } static void setup(void) { stream = g_string_new(""); app_startup(); input_timestamps[LM_TS_STAMP].ut_sec = 1; input_timestamps[LM_TS_STAMP].ut_usec = 2; input_timestamps[LM_TS_STAMP].ut_gmtoff = 3; input_timestamps[LM_TS_RECVD].ut_sec = 4; input_timestamps[LM_TS_RECVD].ut_usec = 5; input_timestamps[LM_TS_RECVD].ut_gmtoff = 6; input_timestamps[LM_TS_PROCESSED].ut_sec = 255; input_timestamps[LM_TS_PROCESSED].ut_usec = 255; input_timestamps[LM_TS_PROCESSED].ut_gmtoff = -1; sa = serialize_string_archive_new(stream); } static void teardown(void) { serialize_archive_free(sa); g_string_free(stream, TRUE); app_shutdown(); } TestSuite(template_timestamp, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/logmsg/tests/test_type_hints.c000066400000000000000000000245061450431004300241530ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "logmsg/type-hinting.h" #include "apphook.h" #include #include #include #include typedef struct _StringHintPair { gchar *string; LogMessageValueType value; } StringHintPair; typedef struct _StringBoolPair { gchar *string; gboolean value; } StringBoolPair; typedef struct _StringDoublePair { gchar *string; gdouble value; } StringDoublePair; typedef struct _StringUInt64Pair { gchar *string; guint64 value; } StringUInt64Pair; ParameterizedTestParameters(type_hints, test_type_hint_parse) { static StringHintPair string_value_pairs[] = { {"string", LM_VT_STRING}, {"literal", LM_VT_JSON}, {"json", LM_VT_JSON}, {"boolean", LM_VT_BOOLEAN}, {"int", LM_VT_INTEGER}, {"int32", LM_VT_INTEGER}, {"int64", LM_VT_INTEGER}, {"float", LM_VT_DOUBLE}, {"double", LM_VT_DOUBLE}, {"datetime", LM_VT_DATETIME}, {"list", LM_VT_LIST}, {"null", LM_VT_NULL}, {"bytes", LM_VT_BYTES}, {"protobuf", LM_VT_PROTOBUF}, }; return cr_make_param_array(StringHintPair, string_value_pairs, sizeof(string_value_pairs) / sizeof(string_value_pairs[0])); } ParameterizedTest(StringHintPair *string_value_pair, type_hints, test_type_hint_parse) { LogMessageValueType type_hint; GError *error = NULL; cr_assert_eq(type_hint_parse(string_value_pair->string, &type_hint, &error), TRUE, "Parsing \"%s\" as type hint failed", string_value_pair->string); cr_assert_eq(type_hint, string_value_pair->value); cr_assert_null(error); } Test(type_hints, test_invalid_type_hint_parse) { LogMessageValueType t; GError *error = NULL; cr_assert_eq(type_hint_parse("invalid-hint", &t, &error), FALSE, "Parsing an invalid hint results in an error."); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_TYPE); g_clear_error(&error); } ParameterizedTestParameters(type_hints, test_bool_cast) { static StringBoolPair string_value_pairs[] = { {"True", TRUE}, {"true", TRUE}, {"1", TRUE}, {"totaly true", TRUE}, {"False", FALSE}, {"false", FALSE}, {"0", FALSE}, {"fatally false", FALSE} }; return cr_make_param_array(StringBoolPair, string_value_pairs, sizeof(string_value_pairs) / sizeof(string_value_pairs[0])); } ParameterizedTest(StringBoolPair *string_value_pair, type_hints, test_bool_cast) { gboolean value; GError *error = NULL; cr_assert_eq(type_cast_to_boolean(string_value_pair->string, &value, &error), TRUE, "Type cast of \"%s\" to gboolean failed", string_value_pair->string); cr_assert_eq(value, string_value_pair->value); cr_assert_null(error); } Test(type_hints, test_invalid_bool_cast) { GError *error = NULL; gboolean value; /* test invalid boolean value cast */ cr_assert_eq(type_cast_to_boolean("booyah", &value, &error), FALSE, "Type cast \"booyah\" to gboolean should be failed"); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); } Test(type_hints, test_int32_cast) { GError *error = NULL; gint32 value; cr_assert(type_cast_to_int32("12345", &value, &error), "Type cast of \"12345\" to gint32 failed"); cr_assert_eq(value, 12345); cr_assert_null(error); cr_assert(type_cast_to_int32("0x1000", &value, &error), "Type cast of \"0x1000\" to gint32 failed"); cr_assert_eq(value, 0x1000); cr_assert_null(error); cr_assert(type_cast_to_int32("0111", &value, &error), "Type cast of \"0111\" to gint32 failed"); cr_assert_eq(value, 111); cr_assert_null(error); /* test for invalid string */ cr_assert_not(type_cast_to_int32("12345a", &value, &error), "Type cast of invalid string to gint32 should be failed"); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); /* empty string */ cr_assert_not(type_cast_to_int32("", &value, &error), "Type cast of empty string to gint32 should be failed"); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); } Test(type_hints, test_int64_cast) { GError *error = NULL; gint64 value; cr_assert(type_cast_to_int64("12345", &value, &error), "Type cast of \"12345\" to gint64 failed"); cr_assert_eq(value, 12345); cr_assert_null(error); cr_assert(type_cast_to_int64("0x1000", &value, &error), "Type cast of \"0x1000\" to gint64 failed"); cr_assert_eq(value, 0x1000); cr_assert_null(error); cr_assert(type_cast_to_int64("0111", &value, &error), "Type cast of \"0111\" to gint64 failed"); cr_assert_eq(value, 111); cr_assert_null(error); /* test for invalid string */ cr_assert_not(type_cast_to_int64("12345a", &value, &error), "Type cast of invalid string to gint64 should be failed"); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); /* empty string */ cr_assert_not(type_cast_to_int64("", &value, &error), "Type cast of empty string to gint64 should be failed"); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); } ParameterizedTestParameters(type_hints, test_double_cast) { static StringDoublePair string_value_pairs[] = { #ifdef INFINITY {"INF", (gdouble)INFINITY}, #endif {"1.0", 1.0}, {"1e-100000000", 0.0} }; return cr_make_param_array(StringDoublePair, string_value_pairs, sizeof(string_value_pairs) / sizeof(string_value_pairs[0])); } static void cr_assert_gdouble_eq(gdouble a, gdouble b) { const gint is_a_inf = isinf(a); const gint is_b_inf = isinf(b); cr_assert_eq(is_a_inf, is_b_inf); if (is_a_inf && is_b_inf) { cr_assert(TRUE); return; } cr_assert(fabs(a-b) < G_MINDOUBLE); } ParameterizedTest(StringDoublePair *string_value_pair, type_hints, test_double_cast) { gdouble value; GError *error = NULL; cr_assert(type_cast_to_double(string_value_pair->string, &value, &error), "Type cast of \"%s\" to double failed", string_value_pair->string); cr_assert_gdouble_eq(value, string_value_pair->value); cr_assert_null(error); } ParameterizedTestParameters(type_hints, test_invalid_double_cast) { static StringDoublePair string_list[] = { {"2.0bad", }, {"bad", }, {"", }, {"1e1000000", }, {"-1e1000000" }, }; return cr_make_param_array(StringDoublePair, string_list, sizeof(string_list) / sizeof(string_list[0])); } ParameterizedTest(StringDoublePair *string_value_pair, type_hints, test_invalid_double_cast) { gdouble value; GError *error = NULL; cr_assert_not(type_cast_to_double(string_value_pair->string, &value, &error), "Type cast of invalid string (%s) to double should be failed", string_value_pair->string); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); } ParameterizedTestParameters(type_hints, test_datetime_cast) { static StringUInt64Pair string_value_pairs[] = { {"12345", 12345000}, {"12345.5", 12345500}, {"12345.54", 12345540}, {"12345.543", 12345543}, {"12345.54321", 12345543}, {"12345.987654", 12345987}, {"12345.987654321", 12345987}, {"12345+05:00", 12345000}, {"12345-05:00", 12345000}, }; return cr_make_param_array(StringUInt64Pair, string_value_pairs, sizeof(string_value_pairs) / sizeof(string_value_pairs[0])); } ParameterizedTest(StringUInt64Pair *string_value_pair, type_hints, test_datetime_cast) { gint64 value; GError *error = NULL; cr_assert_eq(type_cast_to_datetime_msec(string_value_pair->string, &value, &error), TRUE, "Type cast of \"%s\" to msecs failed", string_value_pair->string); cr_assert_eq(value, string_value_pair->value, "datetime cast failed %" G_GINT64_FORMAT " != %" G_GINT64_FORMAT, value, string_value_pair->value); cr_assert_null(error); } ParameterizedTestParameters(type_hints, test_invalid_datetime_cast) { static StringUInt64Pair string_value_pairs[] = { {"invalid", }, {"12345T", }, {"12345.", }, {"12345.1234567890", }, {"12345+XX:YY", 12345000}, {"12345-05", 12345000}, {"12345-XX:YY", 12345000} }; return cr_make_param_array(StringUInt64Pair, string_value_pairs, sizeof(string_value_pairs) / sizeof(string_value_pairs[0])); } ParameterizedTest(StringUInt64Pair *string_value_pair, type_hints, test_invalid_datetime_cast) { GError *error = NULL; gint64 value; cr_assert_eq(type_cast_to_datetime_msec(string_value_pair->string, &value, &error), FALSE, "Type cast of invalid string to gint64 should have failed %s", string_value_pair->string); cr_assert_not_null(error); cr_assert_eq(error->domain, TYPE_HINTING_ERROR); cr_assert_eq(error->code, TYPE_HINTING_INVALID_CAST); g_clear_error(&error); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/timestamp-serialize.c000066400000000000000000000044671450431004300235600ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timestamp-serialize.h" static gboolean _write_log_stamp(SerializeArchive *sa, const UnixTime *stamp) { return serialize_write_uint64(sa, stamp->ut_sec) && serialize_write_uint32(sa, stamp->ut_usec) && serialize_write_uint32(sa, stamp->ut_gmtoff); } static gboolean _read_log_stamp(SerializeArchive *sa, UnixTime *stamp) { guint64 val64; guint32 val; if (!serialize_read_uint64(sa, &val64)) return FALSE; stamp->ut_sec = (gint64) val64; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->ut_usec = val; if (!serialize_read_uint32(sa, &val)) return FALSE; stamp->ut_gmtoff = (gint) val; return TRUE; } gboolean timestamp_serialize(SerializeArchive *sa, UnixTime *timestamps) { return _write_log_stamp(sa, ×tamps[LM_TS_STAMP]) && _write_log_stamp(sa, ×tamps[LM_TS_RECVD]) && _write_log_stamp(sa, ×tamps[LM_TS_PROCESSED]); } gboolean timestamp_deserialize_legacy(SerializeArchive *sa, UnixTime *timestamps) { return (_read_log_stamp(sa, ×tamps[LM_TS_STAMP]) && _read_log_stamp(sa, ×tamps[LM_TS_RECVD])); } gboolean timestamp_deserialize(SerializeArchive *sa, UnixTime *timestamps) { return (timestamp_deserialize_legacy(sa, timestamps) && _read_log_stamp(sa, ×tamps[LM_TS_PROCESSED])); } syslog-ng-syslog-ng-4.4.0/lib/logmsg/timestamp-serialize.h000066400000000000000000000025431450431004300235560ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 2015 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMESTAMP_SERIALIZE_H #define TIMESTAMP_SERIALIZE_H #include "logmsg/logmsg.h" #include "serialize.h" gboolean timestamp_serialize(SerializeArchive *sa, UnixTime *timestamps); gboolean timestamp_deserialize_legacy(SerializeArchive *sa, UnixTime *timestamps); gboolean timestamp_deserialize(SerializeArchive *sa, UnixTime *timestamps); #endif syslog-ng-syslog-ng-4.4.0/lib/logmsg/type-hinting.c000066400000000000000000000127221450431004300222000ustar00rootroot00000000000000/* * Copyright (c) 2012-2014 Balabit * Copyright (c) 2012-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "messages.h" #include "type-hinting.h" #include "template/templates.h" #include "timeutils/scan-timestamp.h" #include #include #include #include GQuark type_hinting_error_quark(void) { return g_quark_from_static_string("type-hinting-error-quark"); } gboolean type_hint_parse(const gchar *hint, LogMessageValueType *out_type, GError **error) { if (!log_msg_value_type_from_str(hint, out_type) || *out_type == LM_VT_NONE) { g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_TYPE, "Unknown type specified in type hinting: %s", hint); return FALSE; } return TRUE; } gboolean type_cast_drop_helper(gint drop_flags, const gchar *value, const gchar *type_hint) { if (!(drop_flags & ON_ERROR_SILENT)) { msg_error("Casting error", evt_tag_str("value", value), evt_tag_str("type-hint", type_hint)); } return drop_flags & ON_ERROR_DROP_MESSAGE; } gboolean type_cast_to_boolean(const gchar *value, gboolean *out, GError **error) { if (value[0] == 'T' || value[0] == 't' || value[0] == '1') *out = TRUE; else if (value[0] == 'F' || value[0] == 'f' || value[0] == '0') *out = FALSE; else { if (error) g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_CAST, "boolean(%s)", value); return FALSE; } return TRUE; } static gboolean _is_value_hex(const gchar *value) { if (value[0] == '+' || value[0] == '-') value++; return (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')); } gboolean type_cast_to_int32(const gchar *value, gint32 *out, GError **error) { gchar *endptr; if (_is_value_hex(value)) *out = (gint32)strtol(value, &endptr, 16); else *out = (gint32)strtol(value, &endptr, 10); if (value[0] == 0 || endptr[0] != '\0') { if (error) g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_CAST, "int32(%s)", value); return FALSE; } return TRUE; } gboolean type_cast_to_int64(const gchar *value, gint64 *out, GError **error) { gchar *endptr; if (_is_value_hex(value)) *out = (gint64)strtoll(value, &endptr, 16); else *out = (gint64)strtoll(value, &endptr, 10); if (value[0] == 0 || endptr[0] != '\0') { if (error) g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_CAST, "int64(%s)", value); return FALSE; } return TRUE; } gboolean type_cast_to_double(const gchar *value, gdouble *out, GError **error) { gchar *endptr = NULL; gboolean success = TRUE; errno = 0; *out = strtod(value, &endptr); if (errno == ERANGE && (*out >= HUGE_VAL || *out <= -HUGE_VAL)) success = FALSE; if (endptr == value) success = FALSE; if (endptr[0] != '\0') success = FALSE; if (!success && error) { g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_CAST, "double(%s)", value); } return success; } static gboolean _parse_fixed_point_timestamp_in_nsec(const gchar *value, gchar **endptr, gint64 *sec, gint64 *nsec) { *nsec = 0; *sec = (gint64) strtoll(value, endptr, 10); if (**endptr == '.') { const gchar *nsec_start = (*endptr) + 1; *nsec = (gint64) strtoll(nsec_start, endptr, 10); gint nsec_length = (*endptr) - nsec_start; if (nsec_length == 0) return FALSE; if (nsec_length > 9) return FALSE; for (gint i = 0; i < 9 - nsec_length; i++) *nsec *= 10; return TRUE; } return TRUE; } gboolean type_cast_to_datetime_unixtime(const gchar *value, UnixTime *ut, GError **error) { gchar *endptr; gint64 sec, nsec; gint tzofs = -1; if (!_parse_fixed_point_timestamp_in_nsec(value, &endptr, &sec, &nsec)) goto error; const guchar *tz_start = (guchar *) endptr; if (*tz_start != 0) { gint tz_length = strlen(endptr); if (!scan_iso_timezone(&tz_start, &tz_length, &tzofs)) goto error; } ut->ut_sec = sec; ut->ut_usec = nsec / 1000; ut->ut_gmtoff = tzofs; return TRUE; error: if (error) g_set_error(error, TYPE_HINTING_ERROR, TYPE_HINTING_INVALID_CAST, "datetime(%s)", value); return FALSE; } gboolean type_cast_to_datetime_msec(const gchar *value, gint64 *out, GError **error) { UnixTime ut; if (!type_cast_to_datetime_unixtime(value, &ut, error)) return FALSE; *out = ut.ut_sec * 1000 + ut.ut_usec / 1000; return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/logmsg/type-hinting.h000066400000000000000000000037461450431004300222130ustar00rootroot00000000000000/* * Copyright (c) 2012-2014 Balabit * Copyright (c) 2012-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TYPE_HINTING_H #define TYPE_HINTING_H #include "syslog-ng.h" #include "logmsg/logmsg.h" #define TYPE_HINTING_ERROR type_hinting_error_quark() GQuark type_hinting_error_quark(void); enum TypeHintingError { TYPE_HINTING_INVALID_TYPE, TYPE_HINTING_INVALID_CAST, }; gboolean type_hint_parse(const gchar *hint, LogMessageValueType *out_hint, GError **error); gboolean type_cast_drop_helper(gint drop_flags, const gchar *value, const gchar *type_hint); gboolean type_cast_to_boolean(const gchar *value, gboolean *out, GError **error); gboolean type_cast_to_int32(const gchar *value, gint32 *out, GError **error); gboolean type_cast_to_int64(const gchar *value, gint64 *out, GError **error); gboolean type_cast_to_double(const gchar *value, gdouble *out, GError **error); gboolean type_cast_to_datetime_msec(const gchar *value, gint64 *out, GError **error); gboolean type_cast_to_datetime_unixtime(const gchar *value, UnixTime *ut, GError **error); #endif syslog-ng-syslog-ng-4.4.0/lib/logpipe.c000066400000000000000000000104771450431004300177350ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logpipe.h" #include "cfg-tree.h" #include "cfg-walker.h" gboolean (*pipe_single_step_hook)(LogPipe *pipe, LogMessage *msg, const LogPathOptions *path_options); EVTTAG * log_pipe_location_tag(LogPipe *pipe) { return log_expr_node_location_tag(pipe->expr_node); } void log_pipe_attach_expr_node(LogPipe *self, LogExprNode *expr_node) { self->expr_node = log_expr_node_ref(expr_node); } void log_pipe_detach_expr_node(LogPipe *self) { if (!self->expr_node) return; log_expr_node_unref(self->expr_node); self->expr_node = NULL; } static GList * _arcs(LogPipe *self) { if (self->pipe_next) return g_list_append(NULL, arc_new(self, self->pipe_next, ARC_TYPE_PIPE_NEXT)); else return NULL; } void log_pipe_clone_method(LogPipe *dst, const LogPipe *src) { log_pipe_set_options(dst, &src->options); } void log_pipe_init_instance(LogPipe *self, GlobalConfig *cfg) { g_atomic_counter_set(&self->ref_cnt, 1); self->cfg = cfg; self->pipe_next = NULL; self->persist_name = NULL; self->plugin_name = NULL; self->signal_slot_connector = signal_slot_connector_new(); /* NOTE: queue == NULL means that this pipe simply forwards the * message along the pipeline, e.g. like it has called * log_msg_forward_msg. Since this is a common case, it is better * inlined (than to use an indirect call) for performance. */ self->queue = NULL; self->free_fn = log_pipe_free_method; self->arcs = _arcs; } LogPipe * log_pipe_new(GlobalConfig *cfg) { LogPipe *self = g_new0(LogPipe, 1); log_pipe_init_instance(self, cfg); return self; } void log_pipe_free_method(LogPipe *self) { ; } LogPipe * log_pipe_ref(LogPipe *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } static void _free(LogPipe *self) { if (self->free_fn) self->free_fn(self); g_free((gpointer)self->persist_name); g_free(self->plugin_name); g_list_free_full(self->info, g_free); signal_slot_connector_free(self->signal_slot_connector); g_free(self); } gboolean log_pipe_unref(LogPipe *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) { _free(self); return TRUE; } return FALSE; } void log_pipe_forward_notify(LogPipe *self, gint notify_code, gpointer user_data) { log_pipe_notify(self->pipe_next, notify_code, user_data); } void log_pipe_set_persist_name(LogPipe *self, const gchar *persist_name) { g_free((gpointer)self->persist_name); self->persist_name = g_strdup(persist_name); } const gchar * log_pipe_get_persist_name(const LogPipe *self) { return (self->generate_persist_name != NULL) ? self->generate_persist_name(self) : self->persist_name; } void log_pipe_set_options(LogPipe *self, const LogPipeOptions *options) { self->options = *options; } void log_pipe_set_internal(LogPipe *self, gboolean internal) { self->options.internal = internal; } gboolean log_pipe_is_internal(const LogPipe *self) { return self->options.internal; } void log_pipe_add_info(LogPipe *self, const gchar *info) { self->info = g_list_append(self->info, g_strdup(info)); } #ifdef __linux__ void __log_pipe_forward_msg(LogPipe *self, LogMessage *msg, const LogPathOptions *path_options) __attribute__((alias("log_pipe_forward_msg"))); #endif syslog-ng-syslog-ng-4.4.0/lib/logpipe.h000066400000000000000000000377001450431004300177400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPIPE_H_INCLUDED #define LOGPIPE_H_INCLUDED #include "syslog-ng.h" #include "logmsg/logmsg.h" #include "cfg.h" #include "atomic.h" #include "messages.h" #include "signal-slot-connector/signal-slot-connector.h" /* notify code values */ #define NC_CLOSE 1 #define NC_READ_ERROR 2 #define NC_WRITE_ERROR 3 #define NC_FILE_MOVED 4 #define NC_FILE_EOF 5 #define NC_REOPEN_REQUIRED 6 #define NC_FILE_DELETED 7 /* indicates that the LogPipe was initialized */ #define PIF_INITIALIZED 0x0001 /* indicates that this LogPipe got cloned into the tree already */ #define PIF_INLINED 0x0002 /* this pipe is a source for messages, it is not meant to be used to * forward messages, syslog-ng will only use these pipes for the * left-hand side of the processing graph, e.g. no other pipes may be * sending messages to these pipes and these are expected to generate * messages "automatically". */ #define PIF_SOURCE 0x0004 /* log statement flags that are copied to the head of a branch */ #define PIF_BRANCH_FINAL 0x0008 #define PIF_BRANCH_FALLBACK 0x0010 #define PIF_BRANCH_PROPERTIES (PIF_BRANCH_FINAL + PIF_BRANCH_FALLBACK) /* branch starting with this pipe wants hard flow control */ #define PIF_HARD_FLOW_CONTROL 0x0020 /* LogPipe right after the filter in an "if (filter)" expression */ #define PIF_CONDITIONAL_MIDPOINT 0x0040 /* LogPipe as the joining element of a junction */ #define PIF_JUNCTION_END 0x0080 /* node created directly by the user */ #define PIF_CONFIG_RELATED 0x0100 /* private flags range, to be used by other LogPipe instances for their own purposes */ #define PIF_PRIVATE(x) ((x) << 16) /** * * Processing pipeline * * Within syslog-ng, the user configuration is converted into a tree-like * structure. It's node in this tree is a LogPipe object responsible for * queueing message towards the destination. Each node is free to * drop/transform the message it receives. * * The center.c module contains code that transforms the configuration * into the log processing tree. Each log statement in user configuration * becomes a linked list of pipes, then each source, referenced by the * is piped into the newly created pipe. * * Something like this: * * log statement: * mpx | filter | parser | dest1 | dest2 | dest3 * * source1 -> log statement1 * |-> log statement2 * * E.g. each source is sending to each log path it was referenced from. Each * item in the log path is a pipe, which receives messages and forwards it * at its discretion. Filters are pipes too, which lose data. Destinations * are piping their output to the next element on the pipeline. This * basically means that the pipeline is a wired representation of the user * configuration without having to loop through configuration data. * * Reference counting * * The pipes do not reference each other through their pipe_next member, * simply because there'd be too much reference loops to care about. * Instead pipe_next is a borrowed reference, which is assumed to be valid * as long as the configuration is not freed. * * Flow control * * Flow control is the mechanism used to control the message rate between * input/output sides of syslog-ng in order to avoid message loss. If the * two sides were independent, the input side could well receive messages * at a much higher rate than the destination is able to cope with. * * This is implemented by allocating a per-source window (similar to a TCP * window), which can be "filled" by the source without the danger of * output queue overflow. Also, whenever a message is processed by the * destination it invokes an ACK, which in turn increments the window size. * * This basically boils down to the following: * * the source is free to receive as much messages as fits into its window * * whenever the destination has processed a message, this is signalled * to freeing up a lot in its window * * if the message is full, the source is suspended, no further messages * are received. * * This controls the message rate but doesn't completely ruin throughput, * as the source has some space without being suspended, as suspension and * resuming action takes considerable amount of time (mostly latency, but * CPU is certainly also used). * * There are currently two forms of flow control: * * hard flow control * * soft flow control * * The first is the form of flow control present in earlier syslog-ng * versions and was renamed as "hard" in order to differentiate from the * other form. Hard means that the source is completely suspended until * the destination indeed processed a message. If the network is down, * the disk is full, the source will not accept messages. * * Soft flow control was introduced when syslog-ng became threaded and the * earlier priority based behaviour couldn't be mimiced any other way. * Soft flow control cannot be configured, it is automatically used by * file destinations if "hard" flow control is not enabled by the user. * Soft flow control means that flow is only controlled as long as the * destination is writable, if an error occurs (disk full, etc) messages * get dropped on the floor. But as long as the destination is writable, * the destination rate controls the source rate as well. * * The behaviour in non-threaded syslog-ng was, that destinations were * prioritized over sources, and whenever a destination was writable, * sources were implicitly suspended. This is not easily implementable by * threads and ivykis, thus this alternative mechanism was created. * * Please note that soft-flow-control is a somewhat stronger guarantee * than the earlier behaviour, therefore it is currently only used for * destination files. * * Plugin overrides * * Various methods can be overridden by external objects within * LogPipe and derived classes. The aim of this functionality to * make it possible to attach new functions to a LogPipe at runtime. * * For example, it'd make sense to implement the "suppress" * functionality as such plugin, which is currently implemented in * LogWriter, and in case a non-LogWriter destination would need it, * then a separate implementation would be needed. * * The way to override a method by an external object is as follows: * * - it should save the current value of the method address (for * example "queue" for the queue method) * * - it should change the pointer pointing to the relevant method to * its own code (e.g. change "queue" in LogPipe) * * - once the hook is invoked, it should take care about calling the * original function **/ struct _LogPathOptions { /* an acknowledgement is "passed" to this path, an ACK is still * needed to close the window slot. This was called "flow-control" * and meant both of these things: the user requested * flags(flow-control), _AND_ an acknowledgement was needed. With * the latest change, the one below specifies the user option, * while the "ack is still needed" condition is stored in * ack_needed. */ gboolean ack_needed; /* The user has requested flow-control on this processing path, * which means that the destination should invoke log_msg_ack() * after it has completed processing it (e.g. after sending to the * actual destination, possibly after confirmation if the transport * supports that). If flow-control is not requested, destinations * are permitted to call log_msg_ack() early (e.g. at queue time). * * This is initially FALSE and can be set to TRUE anywhere _before_ * the destination driver, which will actually carry out the * required action. */ gboolean flow_control_requested; gboolean *matched; const LogPathOptions *parent; }; #define LOG_PATH_OPTIONS_INIT { TRUE, FALSE, NULL, NULL } #define LOG_PATH_OPTIONS_INIT_NOACK { FALSE, FALSE, NULL, NULL } static inline void log_path_options_push_junction(LogPathOptions *local_path_options, gboolean *matched, const LogPathOptions *parent) { *local_path_options = *parent; local_path_options->matched = matched; local_path_options->parent = parent; } static inline void log_path_options_pop_conditional(LogPathOptions *local_path_options) { if (local_path_options->parent) local_path_options->matched = local_path_options->parent->matched; } /* * NOTE: we need to be optional about ->parent being set, as synthetic * messages (e.g. the likes emitted by db-parser/grouping-by() may arrive * at the end of a junction without actually crossing the beginning of the * same junction. But this is ok, in these cases we don't need to propagate * our matched state to anywhere, we can assume that the synthetic message * will just follow the same route as the one it was created from. */ static inline void log_path_options_pop_junction(LogPathOptions *local_path_options) { log_path_options_pop_conditional(local_path_options); if (local_path_options->parent) local_path_options->parent = local_path_options->parent->parent; } typedef struct _LogPipeOptions LogPipeOptions; struct _LogPipeOptions { gboolean internal; }; struct _LogPipe { GAtomicCounter ref_cnt; gint32 flags; void (*queue)(LogPipe *self, LogMessage *msg, const LogPathOptions *path_options); GlobalConfig *cfg; LogExprNode *expr_node; LogPipe *pipe_next; StatsCounterItem *discarded_messages; const gchar *persist_name; gchar *plugin_name; SignalSlotConnector *signal_slot_connector; LogPipeOptions options; gboolean (*pre_init)(LogPipe *self); gboolean (*init)(LogPipe *self); gboolean (*deinit)(LogPipe *self); void (*post_deinit)(LogPipe *self); gboolean (*pre_config_init)(LogPipe *self); /* this event function is used to perform necessary operation, such as * starting worker thread, and etc. therefore, syslog-ng will terminate if * return value is false. */ gboolean (*post_config_init)(LogPipe *self); const gchar *(*generate_persist_name)(const LogPipe *self); GList *(*arcs)(LogPipe *self); /* clone this pipe when used in multiple locations in the processing * pipe-line. If it contains state, it should behave as if it was * the same instance, otherwise it can be a copy. */ LogPipe *(*clone)(LogPipe *self); void (*free_fn)(LogPipe *self); void (*notify)(LogPipe *self, gint notify_code, gpointer user_data); GList *info; }; /* cpu-cache optimization: queue method should be as close as possible to flags. Rationale: the pointer pointing to this LogPipe instance is resolved right before calling queue and the colocation of flags and the queue pointer ensures that they are on the same cache line. The queue method is probably the single most often called virtual method */ G_STATIC_ASSERT(G_STRUCT_OFFSET(LogPipe, queue) - G_STRUCT_OFFSET(LogPipe, flags) <= 4); extern gboolean (*pipe_single_step_hook)(LogPipe *pipe, LogMessage *msg, const LogPathOptions *path_options); LogPipe *log_pipe_ref(LogPipe *self); gboolean log_pipe_unref(LogPipe *self); LogPipe *log_pipe_new(GlobalConfig *cfg); void log_pipe_init_instance(LogPipe *self, GlobalConfig *cfg); void log_pipe_clone_method(LogPipe *dst, const LogPipe *src); void log_pipe_forward_notify(LogPipe *self, gint notify_code, gpointer user_data); EVTTAG *log_pipe_location_tag(LogPipe *pipe); void log_pipe_attach_expr_node(LogPipe *self, LogExprNode *expr_node); void log_pipe_detach_expr_node(LogPipe *self); static inline GlobalConfig * log_pipe_get_config(LogPipe *s) { g_assert(s->cfg); return s->cfg; } static inline void log_pipe_set_config(LogPipe *s, GlobalConfig *cfg) { s->cfg = cfg; } static inline void log_pipe_reset_config(LogPipe *s) { log_pipe_set_config(s, NULL); } static inline gboolean log_pipe_init(LogPipe *s) { if (!(s->flags & PIF_INITIALIZED)) { if (s->pre_init && !s->pre_init(s)) return FALSE; if (!s->init || s->init(s)) { s->flags |= PIF_INITIALIZED; return TRUE; } return FALSE; } return TRUE; } static inline gboolean log_pipe_deinit(LogPipe *s) { if ((s->flags & PIF_INITIALIZED)) { if (!s->deinit || s->deinit(s)) { s->flags &= ~PIF_INITIALIZED; if (s->post_deinit) s->post_deinit(s); return TRUE; } return FALSE; } return TRUE; } static inline gboolean log_pipe_pre_config_init(LogPipe *s) { if (s->pre_config_init) return s->pre_config_init(s); return TRUE; } static inline gboolean log_pipe_post_config_init(LogPipe *s) { if (s->post_config_init) return s->post_config_init(s); return TRUE; } static inline void log_pipe_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options); static inline void log_pipe_forward_msg(LogPipe *self, LogMessage *msg, const LogPathOptions *path_options) { if (self->pipe_next) { log_pipe_queue(self->pipe_next, msg, path_options); } else { log_msg_drop(msg, path_options, AT_PROCESSED); } } static inline void log_pipe_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogPathOptions local_path_options; g_assert((s->flags & PIF_INITIALIZED) != 0); if (G_UNLIKELY(pipe_single_step_hook)) { if (!pipe_single_step_hook(s, msg, path_options)) { log_msg_drop(msg, path_options, AT_PROCESSED); return; } } if (G_UNLIKELY(s->flags & (PIF_HARD_FLOW_CONTROL | PIF_JUNCTION_END | PIF_CONDITIONAL_MIDPOINT))) { local_path_options = *path_options; if (s->flags & PIF_HARD_FLOW_CONTROL) { local_path_options.flow_control_requested = 1; msg_trace("Requesting flow control", log_pipe_location_tag(s)); } if (s->flags & PIF_JUNCTION_END) { log_path_options_pop_junction(&local_path_options); } if (s->flags & PIF_CONDITIONAL_MIDPOINT) { log_path_options_pop_conditional(&local_path_options); } path_options = &local_path_options; } if (s->queue) { s->queue(s, msg, path_options); } else { log_pipe_forward_msg(s, msg, path_options); } } static inline LogPipe * log_pipe_clone(LogPipe *self) { g_assert(NULL != self->clone); return self->clone(self); } static inline void log_pipe_notify(LogPipe *s, gint notify_code, gpointer user_data) { if (s->notify) s->notify(s, notify_code, user_data); } static inline void log_pipe_append(LogPipe *s, LogPipe *next) { s->pipe_next = next; } void log_pipe_set_persist_name(LogPipe *self, const gchar *persist_name); const gchar * log_pipe_get_persist_name(const LogPipe *self); void log_pipe_set_options(LogPipe *self, const LogPipeOptions *options); void log_pipe_set_internal(LogPipe *self, gboolean internal); gboolean log_pipe_is_internal(const LogPipe *self); void log_pipe_free_method(LogPipe *s); static inline GList * log_pipe_get_arcs(LogPipe *s) { return s->arcs(s); } void log_pipe_add_info(LogPipe *self, const gchar *info); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/000077500000000000000000000000001450431004300177665ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logproto/CMakeLists.txt000066400000000000000000000017731450431004300225360ustar00rootroot00000000000000set(LOGPROTO_HEADERS logproto/logproto-buffered-server.h logproto/logproto-builtins.h logproto/logproto-client.h logproto/logproto-dgram-server.h logproto/logproto-framed-client.h logproto/logproto-framed-server.h logproto/logproto.h logproto/logproto-multiline-server.h logproto/logproto-record-server.h logproto/logproto-server.h logproto/logproto-text-client.h logproto/logproto-text-server.h logproto/logproto-proxied-text-server.h PARENT_SCOPE) set(LOGPROTO_SOURCES logproto/logproto-buffered-server.c logproto/logproto-builtins.c logproto/logproto-client.c logproto/logproto-dgram-server.c logproto/logproto-framed-client.c logproto/logproto-framed-server.c logproto/logproto-multiline-server.c logproto/logproto-record-server.c logproto/logproto-server.c logproto/logproto-text-client.c logproto/logproto-text-server.c logproto/logproto-proxied-text-server.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/logproto/Makefile.am000066400000000000000000000022161450431004300220230ustar00rootroot00000000000000logprotoincludedir = ${pkgincludedir}/logproto EXTRA_DIST += lib/logproto/CMakeLists.txt logprotoinclude_HEADERS = \ lib/logproto/logproto-client.h \ lib/logproto/logproto-server.h \ lib/logproto/logproto-buffered-server.h \ lib/logproto/logproto-dgram-server.h \ lib/logproto/logproto-framed-client.h \ lib/logproto/logproto-framed-server.h \ lib/logproto/logproto-text-client.h \ lib/logproto/logproto-text-server.h \ lib/logproto/logproto-proxied-text-server.h \ lib/logproto/logproto-multiline-server.h \ lib/logproto/logproto-record-server.h \ lib/logproto/logproto-builtins.h \ lib/logproto/logproto.h logproto_sources = \ lib/logproto/logproto-client.c \ lib/logproto/logproto-server.c \ lib/logproto/logproto-buffered-server.c \ lib/logproto/logproto-dgram-server.c \ lib/logproto/logproto-framed-client.c \ lib/logproto/logproto-framed-server.c \ lib/logproto/logproto-text-client.c \ lib/logproto/logproto-text-server.c \ lib/logproto/logproto-proxied-text-server.c \ lib/logproto/logproto-multiline-server.c \ lib/logproto/logproto-record-server.c \ lib/logproto/logproto-builtins.c include lib/logproto/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-buffered-server.c000066400000000000000000001113751450431004300250730ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-buffered-server.h" #include "logproto.h" #include "messages.h" #include "serialize.h" #include "compat/string.h" #include #include #include #include typedef struct _BufferedServerBookmarkData { PersistEntryHandle persist_handle; gint32 pending_buffer_pos; gint64 pending_raw_stream_pos; gint32 pending_raw_buffer_size; } BufferedServerBookmarkData; LogProtoBufferedServerState * log_proto_buffered_server_get_state(LogProtoBufferedServer *self) { if (self->persist_state) { g_assert(self->persist_handle != 0); return persist_state_map_entry(self->persist_state, self->persist_handle); } if (G_UNLIKELY(!self->state1)) { self->state1 = g_new0(LogProtoBufferedServerState, 1); } return self->state1; } void log_proto_buffered_server_put_state(LogProtoBufferedServer *self) { if (self->persist_state && self->persist_handle) persist_state_unmap_entry(self->persist_state, self->persist_handle); } static inline gboolean _log_proto_buffered_server_fallback_non_persistent(LogProtoBufferedServer *self) { return self->persist_state == NULL; } static gboolean log_proto_buffered_server_convert_from_raw(LogProtoBufferedServer *self, const guchar *raw_buffer, gsize raw_buffer_len) { /* some data was read */ gsize avail_in = raw_buffer_len; gsize avail_out; gchar *out; gboolean success = FALSE; LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); do { avail_out = state->buffer_size - state->pending_buffer_end; out = (gchar *) self->buffer + state->pending_buffer_end; gint ret = g_iconv(self->convert, (gchar **) &raw_buffer, &avail_in, (gchar **) &out, &avail_out); if (ret == (gsize) -1) { switch (errno) { case EINVAL: if (self->stream_based) { /* Incomplete text, do not report an error, rather try to read again */ state->pending_buffer_end = state->buffer_size - avail_out; if (avail_in > 0) { if (avail_in > sizeof(state->raw_buffer_leftover)) { msg_error("Invalid byte sequence, the remaining raw buffer is larger than the supported leftover size", evt_tag_str("encoding", self->super.options->encoding), evt_tag_int("avail_in", avail_in), evt_tag_int("leftover_size", sizeof(state->raw_buffer_leftover))); goto error; } memcpy(state->raw_buffer_leftover, raw_buffer, avail_in); state->raw_buffer_leftover_size = avail_in; state->raw_buffer_size -= avail_in; msg_trace("Leftover characters remained after conversion, delaying message until another chunk arrives", evt_tag_str("encoding", self->super.options->encoding), evt_tag_int("avail_in", avail_in)); goto success; } } else { msg_error("Byte sequence too short, cannot convert an individual frame in its entirety", evt_tag_str("encoding", self->super.options->encoding), evt_tag_int("avail_in", avail_in)); goto error; } break; case E2BIG: state->pending_buffer_end = state->buffer_size - avail_out; /* extend the buffer */ if (state->buffer_size < self->super.options->max_buffer_size) { state->buffer_size *= 2; if (state->buffer_size > self->super.options->max_buffer_size) state->buffer_size = self->super.options->max_buffer_size; self->buffer = g_realloc(self->buffer, state->buffer_size); } else { msg_error("Incoming byte stream requires a too large conversion buffer, probably invalid character sequence", evt_tag_str("encoding", self->super.options->encoding), evt_tag_mem("buffer", self->buffer, state->pending_buffer_end)); goto error; } break; case EILSEQ: msg_notice("Invalid byte sequence, skipping character", evt_tag_str("encoding", self->super.options->encoding), evt_tag_printf("char", "0x%02x", *(guchar *) raw_buffer)); raw_buffer++; avail_in--; state->pending_buffer_end = state->buffer_size - avail_out; break; default: msg_error("Unknown error while converting input", evt_tag_error("errno"), evt_tag_str("encoding", self->super.options->encoding), evt_tag_printf("char", "0x%02x", *(guchar *) raw_buffer)); goto error; } } else { state->pending_buffer_end = state->buffer_size - avail_out; } } while (avail_in > 0); success: success = TRUE; error: log_proto_buffered_server_put_state(self); return success; } static void log_proto_buffered_server_apply_state(LogProtoBufferedServer *self, PersistEntryHandle handle, const gchar *persist_name) { struct stat st; gint64 ofs = 0; LogProtoBufferedServerState *state; gint fd; fd = self->super.transport->fd; self->persist_handle = handle; if (fstat(fd, &st) < 0) return; state = log_proto_buffered_server_get_state(self); if (!self->buffer) { gssize buffer_size = MAX(state->buffer_size, self->super.options->init_buffer_size); self->buffer = g_malloc(buffer_size); state->buffer_size = buffer_size; } state->pending_buffer_end = 0; if (state->file_inode && state->file_inode == st.st_ino && state->file_size <= st.st_size && state->raw_stream_pos <= st.st_size) { ofs = state->raw_stream_pos; lseek(fd, ofs, SEEK_SET); } else { if (state->file_inode) { /* the stored state does not match the current file */ msg_notice("The current log file has a mismatching size/inode information, restarting from the beginning", evt_tag_str("state", persist_name), evt_tag_int("stored_inode", state->file_inode), evt_tag_int("cur_file_inode", st.st_ino), evt_tag_int("stored_size", state->file_size), evt_tag_int("cur_file_size", st.st_size), evt_tag_int("raw_stream_pos", state->raw_stream_pos)); } goto error; } if (state->raw_buffer_size) { gssize rc; guchar *raw_buffer; if (!self->super.options->encoding) { /* no conversion, we read directly into our buffer */ if (state->raw_buffer_size > state->buffer_size) { msg_notice("Invalid LogProtoBufferedServerState.raw_buffer_size, larger than buffer_size and no encoding is set, restarting from the beginning", evt_tag_str("state", persist_name), evt_tag_int("raw_buffer_size", state->raw_buffer_size), evt_tag_int("buffer_size", state->buffer_size), evt_tag_int("init_buffer_size", self->super.options->init_buffer_size)); goto error; } raw_buffer = self->buffer; } else { if (state->raw_buffer_size > self->super.options->max_buffer_size) { msg_notice("Invalid LogProtoBufferedServerState.raw_buffer_size, larger than max_buffer_size, restarting from the beginning", evt_tag_str("state", persist_name), evt_tag_int("raw_buffer_size", state->raw_buffer_size), evt_tag_int("init_buffer_size", self->super.options->init_buffer_size), evt_tag_int("max_buffer_size", self->super.options->max_buffer_size)); goto error; } raw_buffer = g_alloca(state->raw_buffer_size); } rc = log_transport_read(self->super.transport, raw_buffer, state->raw_buffer_size, NULL); if (rc != state->raw_buffer_size) { msg_notice("Error re-reading buffer contents of the file to be continued, restarting from the beginning", evt_tag_str("state", persist_name)); goto error; } state->pending_buffer_end = 0; if (self->super.options->encoding) { if (!log_proto_buffered_server_convert_from_raw(self, raw_buffer, rc)) { msg_notice("Error re-converting buffer contents of the file to be continued, restarting from the beginning", evt_tag_str("state", persist_name)); goto error; } } else { state->pending_buffer_end += rc; } if (state->buffer_pos > state->pending_buffer_end) { msg_notice("Converted buffer contents is smaller than the current buffer position, starting from the beginning of the buffer, some lines may be duplicated", evt_tag_str("state", persist_name)); state->buffer_pos = state->pending_buffer_pos = 0; } self->fetch_state = LPBSF_FETCHING_FROM_BUFFER; } else { /* although we do have buffer position information, but the * complete contents of the buffer is already processed, instead * of reading and then dropping it, position the file after the * indicated block */ state->raw_stream_pos += state->raw_buffer_size; ofs = state->raw_stream_pos; state->raw_buffer_size = 0; state->buffer_pos = state->pending_buffer_end = 0; lseek(fd, state->raw_stream_pos, SEEK_SET); } goto exit; error: ofs = 0; state->buffer_pos = 0; state->pending_buffer_end = 0; state->__deprecated_buffer_cached_eol = 0; state->raw_stream_pos = 0; state->raw_buffer_size = 0; state->raw_buffer_leftover_size = 0; lseek(fd, 0, SEEK_SET); exit: state->file_inode = st.st_ino; state->file_size = st.st_size; state->raw_stream_pos = ofs; state->pending_buffer_pos = state->buffer_pos; state->pending_raw_stream_pos = state->raw_stream_pos; state->pending_raw_buffer_size = state->raw_buffer_size; state->__deprecated_buffer_cached_eol = 0; state = NULL; log_proto_buffered_server_put_state(self); } static PersistEntryHandle log_proto_buffered_server_alloc_state(LogProtoBufferedServer *self, PersistState *persist_state, const gchar *persist_name) { LogProtoBufferedServerState *state; PersistEntryHandle handle; handle = persist_state_alloc_entry(persist_state, persist_name, sizeof(LogProtoBufferedServerState)); if (handle) { state = persist_state_map_entry(persist_state, handle); state->header.version = 0; state->header.big_endian = (G_BYTE_ORDER == G_BIG_ENDIAN); persist_state_unmap_entry(persist_state, handle); } return handle; } static gboolean log_proto_buffered_server_convert_state(LogProtoBufferedServer *self, guint8 persist_version, gpointer old_state, gsize old_state_size, LogProtoBufferedServerState *state) { if (persist_version <= 2) { state->header.version = 0; state->file_inode = 0; state->raw_stream_pos = strtoll((gchar *) old_state, NULL, 10); state->file_size = 0; return TRUE; } else if (persist_version == 3) { SerializeArchive *archive; guint32 read_length; gint64 cur_size; gint64 cur_inode; gint64 cur_pos; guint16 version = 0; gchar *buffer; gsize buffer_len; cur_inode = -1; cur_pos = 0; cur_size = 0; version = 0; archive = serialize_buffer_archive_new(old_state, old_state_size); /* NOTE: the v23 conversion code adds an extra length field which we * need to read out. */ g_assert(serialize_read_uint32(archive, &read_length) && read_length == old_state_size - sizeof(read_length)); /* original v3 format starts here */ if (!serialize_read_uint16(archive, &version) || version != 0) { msg_error("Internal error restoring log reader state, stored data has incorrect version", evt_tag_int("version", version)); goto error_converting_v3; } if (!serialize_read_uint64(archive, (guint64 *) &cur_pos) || !serialize_read_uint64(archive, (guint64 *) &cur_inode) || !serialize_read_uint64(archive, (guint64 *) &cur_size)) { msg_error("Internal error restoring information about the current file position, restarting from the beginning"); goto error_converting_v3; } if (!serialize_read_uint16(archive, &version) || version != 0) { msg_error("Internal error, protocol state has incorrect version", evt_tag_int("version", version)); goto error_converting_v3; } if (!serialize_read_cstring(archive, &buffer, &buffer_len)) { msg_error("Internal error, error reading buffer contents", evt_tag_int("version", version)); goto error_converting_v3; } if (!self->buffer || state->buffer_size < buffer_len) { gsize buffer_size = MAX(self->super.options->init_buffer_size, buffer_len); self->buffer = g_realloc(self->buffer, buffer_size); } serialize_archive_free(archive); memcpy(self->buffer, buffer, buffer_len); state->buffer_pos = 0; state->pending_buffer_end = buffer_len; g_free(buffer); state->header.version = 0; state->file_inode = cur_inode; state->raw_stream_pos = cur_pos; state->file_size = cur_size; return TRUE; error_converting_v3: serialize_archive_free(archive); } return FALSE; } static void _log_proto_buffered_server_swap_bytes_if_needed(PersistState *persist_state, PersistEntryHandle old_state_handle) { LogProtoBufferedServerState *state; state = (LogProtoBufferedServerState *)(persist_state_map_entry(persist_state, old_state_handle)); if ((state->header.big_endian && G_BYTE_ORDER == G_LITTLE_ENDIAN) || (!state->header.big_endian && G_BYTE_ORDER == G_BIG_ENDIAN)) { /* byte order conversion in order to avoid the hassle with scattered byte order conversions in the code */ state->header.big_endian = !state->header.big_endian; state->buffer_pos = GUINT32_SWAP_LE_BE(state->buffer_pos); state->pending_buffer_pos = GUINT32_SWAP_LE_BE(state->pending_buffer_pos); state->pending_buffer_end = GUINT32_SWAP_LE_BE(state->pending_buffer_end); state->buffer_size = GUINT32_SWAP_LE_BE(state->buffer_size); state->raw_stream_pos = GUINT64_SWAP_LE_BE(state->raw_stream_pos); state->raw_buffer_size = GUINT32_SWAP_LE_BE(state->raw_buffer_size); state->pending_raw_stream_pos = GUINT64_SWAP_LE_BE(state->pending_raw_stream_pos); state->pending_raw_buffer_size = GUINT32_SWAP_LE_BE(state->pending_raw_buffer_size); state->file_size = GUINT64_SWAP_LE_BE(state->file_size); state->file_inode = GUINT64_SWAP_LE_BE(state->file_inode); } persist_state_unmap_entry(persist_state, old_state_handle); } static gboolean _log_proto_buffered_server_convert_header_version(PersistState *persist_state, PersistEntryHandle old_state_handle) { LogProtoBufferedServerState *state; gboolean result = TRUE; state = persist_state_map_entry(persist_state, old_state_handle); if (state->header.version > 1) { msg_error("Internal error restoring log reader state, stored data is too new", evt_tag_int("version", state->header.version)); result = FALSE; } if (state->header.version == 1) { state->header.version = 0; } persist_state_unmap_entry(persist_state, old_state_handle); return result; } gboolean log_proto_buffered_server_restart_with_state(LogProtoServer *s, PersistState *persist_state, const gchar *persist_name) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; guint8 persist_version; PersistEntryHandle old_state_handle; gpointer old_state; gsize old_state_size; PersistEntryHandle new_state_handle = 0; gpointer new_state = NULL; gboolean success; self->persist_state = persist_state; old_state_handle = persist_state_lookup_entry(persist_state, persist_name, &old_state_size, &persist_version); if (!old_state_handle) { new_state_handle = log_proto_buffered_server_alloc_state(self, persist_state, persist_name); if (!new_state_handle) goto fallback_non_persistent; log_proto_buffered_server_apply_state(self, new_state_handle, persist_name); return TRUE; } if (persist_version < 4) { new_state_handle = log_proto_buffered_server_alloc_state(self, persist_state, persist_name); if (!new_state_handle) goto fallback_non_persistent; old_state = persist_state_map_entry(persist_state, old_state_handle); new_state = persist_state_map_entry(persist_state, new_state_handle); success = log_proto_buffered_server_convert_state(self, persist_version, old_state, old_state_size, new_state); persist_state_unmap_entry(persist_state, old_state_handle); persist_state_unmap_entry(persist_state, new_state_handle); /* we're using the newly allocated state structure regardless if * conversion succeeded. If the conversion went wrong then * new_state is still in its freshly initialized form since the * convert function will not touch the state in the error * branches. */ log_proto_buffered_server_apply_state(self, new_state_handle, persist_name); return success; } else if (persist_version == 4) { _log_proto_buffered_server_swap_bytes_if_needed(persist_state, old_state_handle); if (!_log_proto_buffered_server_convert_header_version(persist_state, old_state_handle)) { goto error; } log_proto_buffered_server_apply_state(self, old_state_handle, persist_name); return TRUE; } else { msg_error("Internal error restoring log reader state, stored data is too new", evt_tag_int("version", persist_version)); goto error; } return TRUE; fallback_non_persistent: new_state = g_new0(LogProtoBufferedServerState, 1); error: if (!new_state) { new_state_handle = log_proto_buffered_server_alloc_state(self, persist_state, persist_name); if (!new_state_handle) goto fallback_non_persistent; new_state = persist_state_map_entry(persist_state, new_state_handle); } if (new_state) { LogProtoBufferedServerState *state = new_state; /* error happened, restart the file from the beginning */ state->raw_stream_pos = 0; state->file_inode = 0; state->file_size = 0; if (new_state_handle) log_proto_buffered_server_apply_state(self, new_state_handle, persist_name); else { self->persist_state = NULL; self->state1 = new_state; } } if (new_state_handle) { persist_state_unmap_entry(persist_state, new_state_handle); } return FALSE; } LogProtoPrepareAction log_proto_buffered_server_prepare(LogProtoServer *s, GIOCondition *cond, gint *timeout G_GNUC_UNUSED) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; *cond = self->super.transport->cond; /* if there's no pending I/O in the transport layer, then we want to do a read */ if (*cond == 0) *cond = G_IO_IN; return LPPA_POLL_IO; } static gint log_proto_buffered_server_read_data_method(LogProtoBufferedServer *self, guchar *buf, gsize len, LogTransportAuxData *aux) { return log_transport_read(self->super.transport, buf, len, aux); } static void log_proto_buffered_server_maybe_realloc_reverse_buffer(LogProtoBufferedServer *self, gsize buffer_length) { if (self->reverse_buffer_len >= buffer_length) return; /* we free and malloc, since we never need the data still in reverse buffer */ g_free(self->reverse_buffer); self->reverse_buffer_len = buffer_length; self->reverse_buffer = g_malloc(buffer_length); } /* * returns the number of bytes that represent the UTF8 encoding buffer * in the original encoding that the user specified. * * NOTE: this is slow, but we only call this for the remainder of our * buffer (e.g. the partial line at the end of our last chunk of read * data). Also, this is only invoked if the file uses an encoding. */ static gsize log_proto_buffered_server_get_raw_size_of_buffer(LogProtoBufferedServer *self, const guchar *buffer, gsize buffer_len) { gchar *out; const guchar *in; gsize avail_out, avail_in; gint ret; if (self->reverse_convert == ((GIConv) -1) && !self->convert_scale) { /* try to speed up raw size calculation by recognizing the most * prominent character encodings and in the case the encoding * uses fixed size characters set that in self->convert_scale, * which in turn will speed up the reversal of the UTF8 buffer * size to raw buffer sizes. */ self->convert_scale = log_proto_get_char_size_for_fixed_encoding(self->super.options->encoding); if (self->convert_scale == 0) { /* this encoding is not known, do the conversion for real :( */ self->reverse_convert = g_iconv_open(self->super.options->encoding, "utf-8"); } } if (self->convert_scale) return g_utf8_strlen((gchar *) buffer, buffer_len) * self->convert_scale; /* Multiplied by 6, because 1 character can be maximum 6 bytes in UTF-8 encoding */ log_proto_buffered_server_maybe_realloc_reverse_buffer(self, buffer_len * 6); avail_out = self->reverse_buffer_len; out = self->reverse_buffer; avail_in = buffer_len; in = buffer; ret = g_iconv(self->reverse_convert, (gchar **) &in, &avail_in, &out, &avail_out); if (ret == (gsize) -1) { /* oops, we cannot reverse that we ourselves converted to UTF-8, * this is simply impossible, but never say never */ msg_error("Internal error, couldn't reverse the internal UTF8 string to the original encoding", evt_tag_mem("buffer", buffer, buffer_len)); return 0; } else { return self->reverse_buffer_len - avail_out; } } static void log_proto_buffered_server_split_buffer(LogProtoBufferedServer *self, LogProtoBufferedServerState *state, const guchar **buffer_start, gsize buffer_bytes) { if (*buffer_start == self->buffer) return; /* move partial message to the beginning of the buffer to make space for new data */ memmove(self->buffer, *buffer_start, buffer_bytes); state->pending_buffer_pos = 0; state->pending_buffer_end = buffer_bytes; *buffer_start = self->buffer; if (G_UNLIKELY(self->pos_tracking)) { /* NOTE: we modify the current file position _after_ updating buffer_pos, since if we crash right here, at least we won't lose data on the next restart, but rather we duplicate some data */ gsize raw_split_size; if (self->super.options->encoding) raw_split_size = log_proto_buffered_server_get_raw_size_of_buffer(self, *buffer_start, buffer_bytes); else raw_split_size = buffer_bytes; state->pending_raw_stream_pos += (gint64) (state->pending_raw_buffer_size - raw_split_size); state->pending_raw_buffer_size = raw_split_size; msg_trace("Buffer split", evt_tag_int("raw_split_size", raw_split_size), evt_tag_int("buffer_bytes", buffer_bytes)); } } static gboolean log_proto_buffered_server_fetch_from_buffer(LogProtoBufferedServer *self, const guchar **msg, gsize *msg_len, LogTransportAuxData *aux) { gsize buffer_bytes; const guchar *buffer_start; LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); gboolean success = FALSE; buffer_start = self->buffer + state->pending_buffer_pos; buffer_bytes = state->pending_buffer_end - state->pending_buffer_pos; if (buffer_bytes == 0) { /* if buffer_bytes is zero bytes, it means that we completely * processed our buffer without having a fraction of a line still * there. It is important to reset * pending_buffer_pos/pending_buffer_end to zero as the caller assumes * that if we return no message from the buffer, then buffer_pos is * _zero_. */ if (G_UNLIKELY(self->pos_tracking)) { state->pending_raw_stream_pos += state->pending_raw_buffer_size; state->pending_raw_buffer_size = 0; } state->pending_buffer_pos = state->pending_buffer_end = 0; goto exit; } success = self->fetch_from_buffer(self, buffer_start, buffer_bytes, msg, msg_len); if (!success) { log_proto_buffered_server_split_buffer(self, state, &buffer_start, buffer_bytes); } if (aux) log_transport_aux_data_copy(aux, &self->buffer_aux); exit: log_proto_buffered_server_put_state(self); return success; } static inline void log_proto_buffered_server_allocate_buffer(LogProtoBufferedServer *self, LogProtoBufferedServerState *state) { state->buffer_size = self->super.options->init_buffer_size; self->buffer = g_malloc(state->buffer_size); } static inline gint log_proto_buffered_server_read_data(LogProtoBufferedServer *self, gpointer buffer, gsize count) { gint rc; log_transport_aux_data_reinit(&self->buffer_aux); rc = self->read_data(self, buffer, count, &self->buffer_aux); return rc; } static GIOStatus log_proto_buffered_server_fetch_into_buffer(LogProtoBufferedServer *self) { guchar *raw_buffer = NULL; gint avail; gint rc; LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); GIOStatus result = G_IO_STATUS_NORMAL; if (G_UNLIKELY(!self->buffer)) log_proto_buffered_server_allocate_buffer(self, state); if (self->convert == (GIConv) -1) { /* no conversion, we read directly into our buffer */ raw_buffer = self->buffer + state->pending_buffer_end; avail = state->buffer_size - state->pending_buffer_end; } else { /* if conversion is needed, we first read into an on-stack * buffer, and then convert it into our internal buffer */ raw_buffer = g_alloca(self->super.options->init_buffer_size + state->raw_buffer_leftover_size); memcpy(raw_buffer, state->raw_buffer_leftover, state->raw_buffer_leftover_size); avail = self->super.options->init_buffer_size; } if (avail == 0) goto exit; rc = log_proto_buffered_server_read_data(self, raw_buffer + state->raw_buffer_leftover_size, avail); if (rc < 0) { if (errno == EAGAIN) { /* ok we don't have any more data to read, return to main poll loop */ result = G_IO_STATUS_AGAIN; } else { /* an error occurred while reading */ msg_error("I/O error occurred while reading", evt_tag_int(EVT_TAG_FD, self->super.transport->fd), evt_tag_error(EVT_TAG_OSERROR)); result = G_IO_STATUS_ERROR; } } else if (rc == 0) { /* EOF read */ msg_trace("EOF occurred while reading", evt_tag_int(EVT_TAG_FD, self->super.transport->fd)); if (state->raw_buffer_leftover_size > 0) { msg_error("EOF read on a channel with leftovers from previous character conversion, dropping input"); state->pending_buffer_pos = state->pending_buffer_end = 0; } result = G_IO_STATUS_EOF; } else { state->pending_raw_buffer_size += rc; rc += state->raw_buffer_leftover_size; state->raw_buffer_leftover_size = 0; if (self->convert == (GIConv) -1) { state->pending_buffer_end += rc; } else if (!log_proto_buffered_server_convert_from_raw(self, raw_buffer, rc)) { result = G_IO_STATUS_ERROR; } } exit: log_proto_buffered_server_put_state(self); return result; } static LogProtoStatus _convert_io_status_to_log_proto_status(GIOStatus io_status) { if (io_status == G_IO_STATUS_EOF) return LPS_EOF; else if (io_status == G_IO_STATUS_ERROR) return LPS_ERROR; g_assert_not_reached(); } static void _buffered_server_update_pos(LogProtoServer *s) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); if (state->pending_buffer_pos == state->pending_buffer_end) { state->pending_buffer_end = 0; state->pending_buffer_pos = 0; if (self->pos_tracking) { state->pending_raw_stream_pos += state->pending_raw_buffer_size; state->pending_raw_buffer_size = 0; } } log_proto_buffered_server_put_state(self); } static void _buffered_server_bookmark_save_non_persistent(Bookmark *bookmark) { msg_trace("Last message got confirmed, but we are in non persistent mode"); } static void _buffered_server_bookmark_save(Bookmark *bookmark) { BufferedServerBookmarkData *bookmark_data = (BufferedServerBookmarkData *)(&bookmark->container); LogProtoBufferedServerState *state = persist_state_map_entry(bookmark->persist_state, bookmark_data->persist_handle); state->buffer_pos = bookmark_data->pending_buffer_pos; state->raw_stream_pos = bookmark_data->pending_raw_stream_pos; state->raw_buffer_size = bookmark_data->pending_raw_buffer_size; msg_trace("Last message got confirmed", evt_tag_int("raw_stream_pos", state->raw_stream_pos), evt_tag_int("raw_buffer_len", state->raw_buffer_size), evt_tag_int("buffer_pos", state->buffer_pos), evt_tag_int("buffer_end", state->pending_buffer_end)); persist_state_unmap_entry(bookmark->persist_state, bookmark_data->persist_handle); } static void _buffered_server_bookmark_fill(LogProtoBufferedServer *self, Bookmark *bookmark) { if (G_UNLIKELY(_log_proto_buffered_server_fallback_non_persistent(self))) { bookmark->save = _buffered_server_bookmark_save_non_persistent; return; } LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); BufferedServerBookmarkData *data = (BufferedServerBookmarkData *)(&bookmark->container); data->pending_buffer_pos = state->pending_buffer_pos; data->pending_raw_stream_pos = state->pending_raw_stream_pos; data->pending_raw_buffer_size = state->pending_raw_buffer_size; data->persist_handle = self->persist_handle; bookmark->save = _buffered_server_bookmark_save; log_proto_buffered_server_put_state(self); } static void log_proto_buffered_server_flush(LogProtoBufferedServer *self, const guchar **msg, gsize *msg_len) { LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(self); const guchar *buffer_start = self->buffer + state->pending_buffer_pos; gsize buffer_bytes = state->pending_buffer_end - state->pending_buffer_pos; if (buffer_bytes == 0) { *msg = NULL; *msg_len = 0; log_proto_buffered_server_put_state(self); return; } *msg = buffer_start; *msg_len = buffer_bytes; state->pending_buffer_pos = state->pending_buffer_end; log_proto_buffered_server_put_state(self); if (self->flush) self->flush(self); } /** * Returns: TRUE to indicate success, FALSE otherwise. The returned * msg can be NULL even if no failure occurred. **/ LogProtoStatus log_proto_buffered_server_fetch(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; LogProtoStatus result = LPS_SUCCESS; if (G_UNLIKELY(self->flush_partial_message)) { log_proto_buffered_server_flush(self, msg, msg_len); self->flush_partial_message = FALSE; goto exit; } while (1) { if (self->fetch_state == LPBSF_FETCHING_FROM_BUFFER) { if (log_proto_buffered_server_fetch_from_buffer(self, msg, msg_len, aux)) goto exit; if (log_proto_buffered_server_is_input_closed(self)) { result = _convert_io_status_to_log_proto_status(self->io_status); goto exit; } else { self->fetch_state = LPBSF_FETCHING_FROM_INPUT; } } else if (self->fetch_state == LPBSF_FETCHING_FROM_INPUT) { GIOStatus io_status; if (!(*may_read)) goto exit; io_status = log_proto_buffered_server_fetch_into_buffer(self); switch (io_status) { case G_IO_STATUS_NORMAL: if (self->no_multi_read) *may_read = FALSE; break; case G_IO_STATUS_AGAIN: result = LPS_AGAIN; goto exit; case G_IO_STATUS_ERROR: case G_IO_STATUS_EOF: self->io_status = io_status; break; default: g_assert_not_reached(); } self->fetch_state = LPBSF_FETCHING_FROM_BUFFER; } } exit: /* result contains our result, but once an error happens, the error condition remains persistent */ if (result != LPS_SUCCESS && result != LPS_AGAIN) self->super.status = result; else { if (result == LPS_SUCCESS && bookmark && *msg) { _buffered_server_bookmark_fill(self, bookmark); _buffered_server_update_pos(&self->super); } } return result; } gboolean log_proto_buffered_server_validate_options_method(LogProtoServer *s) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; if (self->super.options->encoding && self->convert == (GIConv) -1) { msg_error("Unknown character set name specified", evt_tag_str("encoding", self->super.options->encoding)); return FALSE; } return log_proto_server_validate_options_method(s); } void log_proto_buffered_server_free_method(LogProtoServer *s) { LogProtoBufferedServer *self = (LogProtoBufferedServer *) s; if (self->reverse_convert != (GIConv) -1) g_iconv_close(self->reverse_convert); g_free(self->reverse_buffer); log_transport_aux_data_destroy(&self->buffer_aux); g_free(self->buffer); if (self->state1) { g_free(self->state1); } if (self->convert != (GIConv) -1) g_iconv_close(self->convert); log_proto_server_free_method(s); } void log_proto_buffered_server_init(LogProtoBufferedServer *self, LogTransport *transport, const LogProtoServerOptions *options) { log_proto_server_init(&self->super, transport, options); self->super.prepare = log_proto_buffered_server_prepare; self->super.fetch = log_proto_buffered_server_fetch; self->super.free_fn = log_proto_buffered_server_free_method; self->super.transport = transport; self->super.restart_with_state = log_proto_buffered_server_restart_with_state; self->super.validate_options = log_proto_buffered_server_validate_options_method; self->convert = (GIConv) -1; self->reverse_convert = (GIConv) -1; self->read_data = log_proto_buffered_server_read_data_method; self->io_status = G_IO_STATUS_NORMAL; if (options->encoding) self->convert = g_iconv_open("utf-8", options->encoding); else self->convert = (GIConv) -1; self->stream_based = TRUE; self->pos_tracking = log_proto_server_is_position_tracked(&self->super); } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-buffered-server.h000066400000000000000000000112211450431004300250650ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_BUFFERED_SERVER_H_INCLUDED #define LOGPROTO_BUFFERED_SERVER_H_INCLUDED #include "logproto-server.h" #include "persistable-state-header.h" enum { LPBSF_FETCHING_FROM_INPUT, LPBSF_FETCHING_FROM_BUFFER, }; typedef struct _LogProtoBufferedServerState { /* NOTE: that if you add/remove structure members you have to update * the byte order swap code in LogProtoFileReader for mulit-byte * members. */ PersistableStateHeader header; guint8 raw_buffer_leftover_size; guint8 __padding1[1]; guint32 buffer_pos; guint32 pending_buffer_end; guint32 buffer_size; guint32 __deprecated_buffer_cached_eol; guint32 pending_buffer_pos; /* the stream position where we converted out current buffer from (offset in file) */ gint64 raw_stream_pos; gint64 pending_raw_stream_pos; /* the size of raw data (measured in bytes) that got converted from raw_stream_pos into our buffer */ gint32 raw_buffer_size; gint32 pending_raw_buffer_size; guchar raw_buffer_leftover[8]; gint64 file_size; gint64 file_inode; } LogProtoBufferedServerState; typedef struct _LogProtoBufferedServer LogProtoBufferedServer; struct _LogProtoBufferedServer { LogProtoServer super; gboolean (*fetch_from_buffer)(LogProtoBufferedServer *self, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len); gint (*read_data)(LogProtoBufferedServer *self, guchar *buf, gsize len, LogTransportAuxData *aux); void (*flush)(LogProtoBufferedServer *self); guint /* track & record the position in the input, to be used for file * position tracking. It's not always on as it's expensive when * an encoding is specified and the last record in the input is * not complete. */ pos_tracking:1, /* specifies that the input is a stream of bytes, size of chunks * read split the input randomly. Non-stream based stuff is udp * or fixed-size records read from a file. */ stream_based:1, no_multi_read:1, flush_partial_message:1; gint fetch_state; GIOStatus io_status; LogProtoBufferedServerState *state1; PersistState *persist_state; PersistEntryHandle persist_handle; GIConv convert; guchar *buffer; GIConv reverse_convert; gchar *reverse_buffer; gsize reverse_buffer_len; gint convert_scale; /* auxiliary data (e.g. GSockAddr, other transport related meta * data) associated with the already buffered data */ LogTransportAuxData buffer_aux; }; static inline gboolean log_proto_buffered_server_is_input_closed(LogProtoBufferedServer *self) { return self->io_status != G_IO_STATUS_NORMAL; } static inline void log_proto_buffered_server_cue_flush(LogProtoBufferedServer *self) { self->flush_partial_message = TRUE; } LogProtoPrepareAction log_proto_buffered_server_prepare(LogProtoServer *s, GIOCondition *cond, gint *timeout G_GNUC_UNUSED); LogProtoBufferedServerState *log_proto_buffered_server_get_state(LogProtoBufferedServer *self); void log_proto_buffered_server_put_state(LogProtoBufferedServer *self); /* LogProtoBufferedServer */ gboolean log_proto_buffered_server_validate_options_method(LogProtoServer *s); void log_proto_buffered_server_init(LogProtoBufferedServer *self, LogTransport *transport, const LogProtoServerOptions *options); void log_proto_buffered_server_free_method(LogProtoServer *s); LogProtoStatus log_proto_buffered_server_fetch(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-builtins.c000066400000000000000000000051351450431004300236320ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-dgram-server.h" #include "logproto-text-client.h" #include "logproto-text-server.h" #include "logproto-proxied-text-server.h" #include "logproto-framed-client.h" #include "logproto-framed-server.h" #include "plugin.h" #include "plugin-types.h" /* This module defines various core-implemented LogProto implementations as * plugins, so that modules may find them, dynamically based on their plugin * name */ DEFINE_LOG_PROTO_SERVER(log_proto_dgram); DEFINE_LOG_PROTO_CLIENT(log_proto_text); DEFINE_LOG_PROTO_SERVER(log_proto_text); DEFINE_LOG_PROTO_SERVER(log_proto_text_with_nuls); DEFINE_LOG_PROTO_SERVER(log_proto_proxied_text); DEFINE_LOG_PROTO_SERVER(log_proto_proxied_text_tls_passthrough, .use_multitransport = TRUE); DEFINE_LOG_PROTO_CLIENT(log_proto_framed); DEFINE_LOG_PROTO_SERVER(log_proto_framed); static Plugin framed_server_plugins[] = { /* there's no separate client side for the 'dgram' transport */ LOG_PROTO_CLIENT_PLUGIN(log_proto_text, "dgram"), LOG_PROTO_SERVER_PLUGIN(log_proto_dgram, "dgram"), LOG_PROTO_CLIENT_PLUGIN(log_proto_text, "text"), LOG_PROTO_SERVER_PLUGIN(log_proto_text, "text"), LOG_PROTO_SERVER_PLUGIN(log_proto_text_with_nuls, "text-with-nuls"), LOG_PROTO_SERVER_PLUGIN(log_proto_proxied_text, "proxied-tcp"), LOG_PROTO_SERVER_PLUGIN(log_proto_proxied_text_tls_passthrough, "proxied-tls-passthrough"), LOG_PROTO_CLIENT_PLUGIN(log_proto_framed, "framed"), LOG_PROTO_SERVER_PLUGIN(log_proto_framed, "framed"), }; void log_proto_register_builtin_plugins(PluginContext *context) { plugin_register(context, framed_server_plugins, G_N_ELEMENTS(framed_server_plugins)); } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-builtins.h000066400000000000000000000022201450431004300236270ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_PLUGINS_H_INCLUDED #define LOGPROTO_PLUGINS_H_INCLUDED #include "cfg.h" void log_proto_register_builtin_plugins(PluginContext *context); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-client.c000066400000000000000000000051121450431004300232520ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-client.h" #include "messages.h" #include "cfg.h" #include "plugin.h" #include "plugin-types.h" gboolean log_proto_client_validate_options_method(LogProtoClient *s) { return TRUE; } void log_proto_client_free_method(LogProtoClient *s) { log_transport_free(s->transport); } void log_proto_client_free(LogProtoClient *s) { if (s->free_fn) s->free_fn(s); g_free(s); } void log_proto_client_init(LogProtoClient *self, LogTransport *transport, const LogProtoClientOptions *options) { self->validate_options = log_proto_client_validate_options_method; self->free_fn = log_proto_client_free_method; self->options = options; self->transport = transport; } void log_proto_client_options_set_drop_input(LogProtoClientOptions *options, gboolean drop_input) { options->drop_input = drop_input; } void log_proto_client_options_set_timeout(LogProtoClientOptions *options, gint timeout) { options->timeout = timeout; } gint log_proto_client_options_get_timeout(LogProtoClientOptions *options) { return options->timeout; } void log_proto_client_options_defaults(LogProtoClientOptions *options) { options->drop_input = FALSE; options->timeout = 0; } void log_proto_client_options_init(LogProtoClientOptions *options, GlobalConfig *cfg) { } void log_proto_client_options_destroy(LogProtoClientOptions *options) { } LogProtoClientFactory * log_proto_client_get_factory(PluginContext *context, const gchar *name) { Plugin *plugin; plugin = plugin_find(context, LL_CONTEXT_CLIENT_PROTO, name); if (plugin && plugin->construct) return plugin->construct(plugin); return NULL; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-client.h000066400000000000000000000175031450431004300232660ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_CLIENT_H_INCLUDED #define LOGPROTO_CLIENT_H_INCLUDED #include "logproto.h" #include "persist-state.h" typedef struct _LogProtoClient LogProtoClient; #define LOG_PROTO_CLIENT_OPTIONS_SIZE 128 typedef struct _LogProtoClientOptions { gboolean drop_input; gint timeout; } LogProtoClientOptions; typedef union _LogProtoClientOptionsStorage { LogProtoClientOptions super; gchar __padding[LOG_PROTO_CLIENT_OPTIONS_SIZE]; } LogProtoClientOptionsStorage; typedef void (*LogProtoClientAckCallback)(gint num_msg_acked, gpointer user_data); typedef void (*LogProtoClientRewindCallback)(gpointer user_data); typedef struct { LogProtoClientAckCallback ack_callback; LogProtoClientRewindCallback rewind_callback; gpointer user_data; } LogProtoClientFlowControlFuncs; void log_proto_client_options_set_drop_input(LogProtoClientOptions *options, gboolean drop_input); void log_proto_client_options_set_timeout(LogProtoClientOptions *options, gint timeout); gint log_proto_client_options_get_timeout(LogProtoClientOptions *options); void log_proto_client_options_defaults(LogProtoClientOptions *options); void log_proto_client_options_init(LogProtoClientOptions *options, GlobalConfig *cfg); void log_proto_client_options_destroy(LogProtoClientOptions *options); struct _LogProtoClient { LogProtoStatus status; const LogProtoClientOptions *options; LogTransport *transport; /* FIXME: rename to something else */ gboolean (*prepare)(LogProtoClient *s, gint *fd, GIOCondition *cond, gint *timeout); LogProtoStatus (*post)(LogProtoClient *s, LogMessage *logmsg, guchar *msg, gsize msg_len, gboolean *consumed); LogProtoStatus (*process_in)(LogProtoClient *s); LogProtoStatus (*flush)(LogProtoClient *s); gboolean (*validate_options)(LogProtoClient *s); gboolean (*handshake_in_progess)(LogProtoClient *s); LogProtoStatus (*handshake)(LogProtoClient *s); gboolean (*restart_with_state)(LogProtoClient *s, PersistState *state, const gchar *persist_name); void (*free_fn)(LogProtoClient *s); LogProtoClientFlowControlFuncs flow_control_funcs; }; static inline void log_proto_client_set_client_flow_control(LogProtoClient *self, LogProtoClientFlowControlFuncs *flow_control_funcs) { self->flow_control_funcs.ack_callback = flow_control_funcs->ack_callback; self->flow_control_funcs.rewind_callback = flow_control_funcs->rewind_callback; self->flow_control_funcs.user_data = flow_control_funcs->user_data; } static inline void log_proto_client_msg_ack(LogProtoClient *self, gint num_msg_acked) { if (self->flow_control_funcs.ack_callback) self->flow_control_funcs.ack_callback(num_msg_acked, self->flow_control_funcs.user_data); } static inline void log_proto_client_msg_rewind(LogProtoClient *self) { if (self->flow_control_funcs.rewind_callback) self->flow_control_funcs.rewind_callback(self->flow_control_funcs.user_data); } static inline void log_proto_client_set_options(LogProtoClient *self, const LogProtoClientOptions *options) { self->options = options; } static inline gboolean log_proto_client_validate_options(LogProtoClient *self) { return self->validate_options(self); } static inline gboolean log_proto_client_handshake_in_progress(LogProtoClient *s) { if (s->handshake_in_progess) { return s->handshake_in_progess(s); } return FALSE; } static inline LogProtoStatus log_proto_client_handshake(LogProtoClient *s) { if (s->handshake) { return s->handshake(s); } return LPS_SUCCESS; } static inline gboolean log_proto_client_prepare(LogProtoClient *s, gint *fd, GIOCondition *cond, gint *timeout) { return s->prepare(s, fd, cond, timeout); } static inline LogProtoStatus log_proto_client_flush(LogProtoClient *s) { if (s->flush) return s->flush(s); else return LPS_SUCCESS; } static inline LogProtoStatus log_proto_client_process_in(LogProtoClient *s) { if (s->process_in) return s->process_in(s); else if (s->flush) /* * In some clients, flush is used for input processing, but it should not be. * Fix these clients, than remove the flush call here. * * SSL_ERROR_WANT_READ in the TLS transport is also built upon this. */ return s->flush(s); else return LPS_SUCCESS; } static inline LogProtoStatus log_proto_client_post(LogProtoClient *s, LogMessage *logmsg, guchar *msg, gsize msg_len, gboolean *consumed) { return s->post(s, logmsg, msg, msg_len, consumed); } static inline gint log_proto_client_get_fd(LogProtoClient *s) { /* FIXME: Layering violation */ return s->transport->fd; } static inline void log_proto_client_reset_error(LogProtoClient *s) { s->status = LPS_SUCCESS; } static inline gboolean log_proto_client_restart_with_state(LogProtoClient *s, PersistState *state, const gchar *persist_name) { if (s->restart_with_state) return s->restart_with_state(s, state, persist_name); return FALSE; } gboolean log_proto_client_validate_options(LogProtoClient *self); void log_proto_client_init(LogProtoClient *s, LogTransport *transport, const LogProtoClientOptions *options); void log_proto_client_free(LogProtoClient *s); void log_proto_client_free_method(LogProtoClient *s); #define DEFINE_LOG_PROTO_CLIENT(prefix, options...) \ static gpointer \ prefix ## _client_plugin_construct(Plugin *self) \ { \ static LogProtoClientFactory proto = { \ .construct = prefix ## _client_new, \ .stateful = FALSE, \ ##options \ }; \ return &proto; \ } #define LOG_PROTO_CLIENT_PLUGIN(prefix, __name) \ { \ .type = LL_CONTEXT_CLIENT_PROTO, \ .name = __name, \ .construct = prefix ## _client_plugin_construct, \ } #define LOG_PROTO_CLIENT_PLUGIN_WITH_GRAMMAR(__parser, __name) \ { \ .type = LL_CONTEXT_CLIENT_PROTO, \ .name = __name, \ .parser = &__parser, \ } typedef struct _LogProtoClientFactory LogProtoClientFactory; struct _LogProtoClientFactory { LogProtoClient *(*construct)(LogTransport *transport, const LogProtoClientOptions *options); gint default_inet_port; gboolean use_multitransport; gboolean stateful; }; static inline LogProtoClient * log_proto_client_factory_construct(LogProtoClientFactory *self, LogTransport *transport, const LogProtoClientOptions *options) { return self->construct(transport, options); } static inline gboolean log_proto_client_factory_is_proto_stateful(LogProtoClientFactory *self) { return self->stateful; } LogProtoClientFactory *log_proto_client_get_factory(PluginContext *context, const gchar *name); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-dgram-server.c000066400000000000000000000042461450431004300244010ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-dgram-server.h" #include "logproto-buffered-server.h" /* proto that reads the input in datagrams (e.g. the underlying transport * determines record sizes, such as UDP) */ typedef struct _LogProtoDGramServer LogProtoDGramServer; struct _LogProtoDGramServer { LogProtoBufferedServer super; }; static gboolean log_proto_dgram_server_fetch_from_buffer(LogProtoBufferedServer *s, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(s); /* * we are set to packet terminating mode */ *msg = buffer_start; *msg_len = buffer_bytes; state->pending_buffer_pos = state->pending_buffer_end; log_proto_buffered_server_put_state(s); return TRUE; } LogProtoServer * log_proto_dgram_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoDGramServer *self = g_new0(LogProtoDGramServer, 1); log_proto_buffered_server_init(&self->super, transport, options); self->super.fetch_from_buffer = log_proto_dgram_server_fetch_from_buffer; self->super.stream_based = FALSE; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-dgram-server.h000066400000000000000000000025541450431004300244060ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_DGRAM_SERVER_H_INCLUDED #define LOGPROTO_DGRAM_SERVER_H_INCLUDED #include "logproto-server.h" /* * LogProtoDGramServer * * This class reads input as datagrams, each datagram is a separate * message, regardless of embedded EOL/NUL characters. */ LogProtoServer *log_proto_dgram_server_new(LogTransport *transport, const LogProtoServerOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-framed-client.c000066400000000000000000000055731450431004300245210ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-framed-client.h" #include "logproto-text-client.h" #include "messages.h" #define LPFCS_FRAME_SEND 0 #define LPFCS_MESSAGE_SEND 1 typedef struct _LogProtoFramedClient { LogProtoTextClient super; guchar frame_hdr_buf[9]; } LogProtoFramedClient; static LogProtoStatus log_proto_framed_client_post(LogProtoClient *s, LogMessage *logmsg, guchar *msg, gsize msg_len, gboolean *consumed) { LogProtoFramedClient *self = (LogProtoFramedClient *) s; gint frame_hdr_len; LogProtoStatus status; if (msg_len > 9999999) { static const guchar *warn_msg; if (warn_msg != msg) { msg_warning("Error, message length too large for framed protocol, truncated", evt_tag_int("length", msg_len)); warn_msg = msg; } msg_len = 9999999; } status = LPS_SUCCESS; while (status == LPS_SUCCESS && !(*consumed) && self->super.partial == NULL) { switch (self->super.state) { case LPFCS_FRAME_SEND: frame_hdr_len = g_snprintf((gchar *) self->frame_hdr_buf, sizeof(self->frame_hdr_buf), "%" G_GSIZE_FORMAT" ", msg_len); status = log_proto_text_client_submit_write(s, self->frame_hdr_buf, frame_hdr_len, NULL, LPFCS_MESSAGE_SEND); break; case LPFCS_MESSAGE_SEND: *consumed = TRUE; status = log_proto_text_client_submit_write(s, msg, msg_len, (GDestroyNotify) g_free, LPFCS_FRAME_SEND); break; default: g_assert_not_reached(); } } return status; } LogProtoClient * log_proto_framed_client_new(LogTransport *transport, const LogProtoClientOptions *options) { LogProtoFramedClient *self = g_new0(LogProtoFramedClient, 1); log_proto_text_client_init(&self->super, transport, options); self->super.super.post = log_proto_framed_client_post; self->super.state = LPFCS_FRAME_SEND; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-framed-client.h000066400000000000000000000023401450431004300245130ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_FRAMED_CLIENT_H_INCLUDED #define LOGPROTO_FRAMED_CLIENT_H_INCLUDED #include "logproto-client.h" /* framed */ LogProtoClient *log_proto_framed_client_new(LogTransport *transport, const LogProtoClientOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-framed-server.c000066400000000000000000000322051450431004300245410ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-framed-server.h" #include "messages.h" #include #include #include #define MAX_FRAME_LEN_DIGITS 10 static const guint MAX_FETCH_COUNT = 3; typedef enum { LPFSS_FRAME_READ, LPFSS_FRAME_EXTRACT, LPFSS_MESSAGE_READ, LPFSS_MESSAGE_EXTRACT, LPFSS_TRIM_MESSAGE, LPFSS_TRIM_MESSAGE_READ, LPFSS_CONSUME_TRIMMED } LogProtoFramedServerState; typedef enum { LPFSSCTRL_RETURN_WITH_STATUS, LPFSSCTRL_NEXT_STATE, } LogProtoFramedServerStateControl; typedef struct _LogProtoFramedServer { LogProtoServer super; LogProtoFramedServerState state; guchar *buffer; guint32 buffer_size, buffer_pos, buffer_end; guint32 frame_len; gboolean half_message_in_buffer; guint32 fetch_counter; } LogProtoFramedServer; static LogProtoPrepareAction log_proto_framed_server_prepare(LogProtoServer *s, GIOCondition *cond, gint *timeout G_GNUC_UNUSED) { LogProtoFramedServer *self = (LogProtoFramedServer *) s; *cond = self->super.transport->cond; /* there is a half message in our buffer so try to wait */ if (!self->half_message_in_buffer) { if (self->buffer_pos != self->buffer_end) { /* we have a full message in our buffer so parse it without reading new data from the transport layer */ return LPPA_FORCE_SCHEDULE_FETCH; } } /* if there's no pending I/O in the transport layer, then we want to do a read */ if (*cond == 0) *cond = G_IO_IN; return LPPA_POLL_IO; } /* Return value indicates if it was able to read any data from the input. * In case of error, resets aux data and sets status to indicate the root cause. */ static gboolean log_proto_framed_server_fetch_data(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { gint rc; *status = LPS_SUCCESS; if (self->buffer_pos == self->buffer_end) self->buffer_pos = self->buffer_end = 0; if (!(*may_read)) return FALSE; if (self->fetch_counter++ >= MAX_FETCH_COUNT) return FALSE; rc = log_transport_read(self->super.transport, &self->buffer[self->buffer_end], self->buffer_size - self->buffer_end, aux); if (rc < 0) { if (errno != EAGAIN) { msg_error("Error reading RFC6587 style framed data", evt_tag_int("fd", self->super.transport->fd), evt_tag_error("error")); log_transport_aux_data_reinit(aux); *status = LPS_ERROR; } else { /* we need more data to parse this message but the data is not available yet */ self->half_message_in_buffer = TRUE; } return FALSE; } if (rc == 0) { msg_trace("EOF occurred while reading", evt_tag_int(EVT_TAG_FD, self->super.transport->fd)); log_transport_aux_data_reinit(aux); *status = LPS_EOF; return FALSE; } self->buffer_end += rc; return TRUE; } static gboolean log_proto_framed_server_extract_frame_length(LogProtoFramedServer *self, gboolean *need_more_data) { gint i; *need_more_data = TRUE; self->frame_len = 0; for (i = self->buffer_pos; i < self->buffer_end; i++) { if (isdigit(self->buffer[i]) && (i - self->buffer_pos < MAX_FRAME_LEN_DIGITS)) { self->frame_len = self->frame_len * 10 + (self->buffer[i] - '0'); } else if (self->buffer[i] == ' ') { *need_more_data = FALSE; self->buffer_pos = i + 1; return TRUE; } else { msg_error("Invalid frame header", evt_tag_mem("header", &self->buffer[self->buffer_pos], (i - self->buffer_pos))); return FALSE; } } /* couldn't extract frame header, no error but need more data */ return TRUE; } static void _adjust_buffer_if_needed(LogProtoFramedServer *self, const gsize minimum_space_required) { /* We need at least minimum_space_required amount of free space in the buffer. * Since we already moving memory, move it to the beginning. */ if (self->buffer_size - self->buffer_pos < minimum_space_required) { memmove(self->buffer, &self->buffer[self->buffer_pos], self->buffer_end - self->buffer_pos); self->buffer_end = self->buffer_end - self->buffer_pos; self->buffer_pos = 0; } } static inline gboolean _is_trimmed_part_completely_fetched(LogProtoFramedServer *self) { return self->buffer_end >= self->frame_len; } /* Returns TRUE if successfully finished consuming the data. Otherwise it is not finished, but * there is nothing left to read (or there was a read error) and expects to be called again. */ static gboolean _consume_trimmed_part(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { /* Since trimming requires a full (buffer sized) message, the consuming * always starts at the beginning of the buffer, with a new read. */ g_assert(self->buffer_pos == 0 && self->buffer_end == 0); self->half_message_in_buffer = FALSE; while (1) { if (!log_proto_framed_server_fetch_data(self, may_read, aux, status)) return FALSE; if (_is_trimmed_part_completely_fetched(self)) { self->buffer_pos += self->frame_len; return TRUE; } self->frame_len -= self->buffer_end; self->buffer_end = 0; } } static void _ensure_buffer(LogProtoFramedServer *self) { if (G_LIKELY(self->buffer)) return; self->buffer_size = self->super.options->init_buffer_size; self->buffer = g_malloc(self->buffer_size); } static LogProtoFramedServerStateControl _on_frame_read(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { if (!log_proto_framed_server_fetch_data(self, may_read, aux, status)) return LPFSSCTRL_RETURN_WITH_STATUS; self->state = LPFSS_FRAME_EXTRACT; return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _on_frame_extract(LogProtoFramedServer *self, LogTransportAuxData *aux, LogProtoStatus *status) { gboolean need_more_data = FALSE; if (!log_proto_framed_server_extract_frame_length(self, &need_more_data)) { /* invalid frame header */ log_transport_aux_data_reinit(aux); *status = LPS_ERROR; return LPFSSCTRL_RETURN_WITH_STATUS; } if (need_more_data) { self->state = LPFSS_FRAME_READ; _adjust_buffer_if_needed(self, MAX_FRAME_LEN_DIGITS); return LPFSSCTRL_NEXT_STATE; } self->state = LPFSS_MESSAGE_EXTRACT; if (self->frame_len > self->super.options->max_msg_size) { if (self->super.options->trim_large_messages) { msg_debug("Incoming frame larger than log_msg_size(), need to trim.", evt_tag_int("log_msg_size", self->super.options->max_msg_size), evt_tag_int("frame_length", self->frame_len)); self->state = LPFSS_TRIM_MESSAGE_READ; } else { msg_error("Incoming frame larger than log_msg_size()", evt_tag_int("log_msg_size", self->super.options->max_msg_size), evt_tag_int("frame_length", self->frame_len)); log_transport_aux_data_reinit(aux); *status = LPS_ERROR; return LPFSSCTRL_RETURN_WITH_STATUS; } } _adjust_buffer_if_needed(self, self->frame_len); return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _on_trim_message_read(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { if (!log_proto_framed_server_fetch_data(self, may_read, aux, status)) return LPFSSCTRL_RETURN_WITH_STATUS; self->state = LPFSS_TRIM_MESSAGE; return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _on_trim_message(LogProtoFramedServer *self, const guchar **msg, gsize *msg_len, LogProtoStatus *status) { if (self->buffer_end == self->buffer_size) { /* The buffer is full */ *msg = &self->buffer[self->buffer_pos]; *msg_len = self->buffer_end - self->buffer_pos; self->frame_len -= *msg_len; self->state = LPFSS_CONSUME_TRIMMED; self->half_message_in_buffer = TRUE; self->buffer_pos = self->buffer_end = 0; *status = LPS_SUCCESS; return LPFSSCTRL_RETURN_WITH_STATUS; } self->state = LPFSS_TRIM_MESSAGE_READ; return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _on_consume_trimmed(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { if (_consume_trimmed_part(self, may_read, aux, status)) { self->state = LPFSS_FRAME_EXTRACT; /* If there is data in the buffer, try to process it immediately. * (or if we reached the end, than MIGHT be data waiting for read.) */ if ((self->buffer_pos != self->buffer_end) || (self->buffer_end == self->buffer_size)) { return LPFSSCTRL_NEXT_STATE; } } return LPFSSCTRL_RETURN_WITH_STATUS; } static LogProtoFramedServerStateControl _on_message_read(LogProtoFramedServer *self, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { if (!log_proto_framed_server_fetch_data(self, may_read, aux, status)) return LPFSSCTRL_RETURN_WITH_STATUS; self->state = LPFSS_MESSAGE_EXTRACT; return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _on_message_extract(LogProtoFramedServer *self, const guchar **msg, gsize *msg_len, LogProtoStatus *status) { /* NOTE: here we can assume that the complete message fits into * the buffer because of the checks/move operation in the * LPFSS_FRAME_READ state */ if (self->buffer_end - self->buffer_pos >= self->frame_len) { /* ok, we already have the complete message */ *msg = &self->buffer[self->buffer_pos]; *msg_len = self->frame_len; self->buffer_pos += self->frame_len; self->state = LPFSS_FRAME_EXTRACT; /* we have the full message here so reset the half message flag */ self->half_message_in_buffer = FALSE; *status = LPS_SUCCESS; return LPFSSCTRL_RETURN_WITH_STATUS; } self->state = LPFSS_MESSAGE_READ; return LPFSSCTRL_NEXT_STATE; } static LogProtoFramedServerStateControl _step_state_machine(LogProtoFramedServer *self, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, LogProtoStatus *status) { switch (self->state) { case LPFSS_FRAME_READ: return _on_frame_read(self, may_read, aux, status); case LPFSS_FRAME_EXTRACT: return _on_frame_extract(self, aux, status); case LPFSS_TRIM_MESSAGE_READ: return _on_trim_message_read(self, may_read, aux, status); case LPFSS_TRIM_MESSAGE: return _on_trim_message(self, msg, msg_len, status); case LPFSS_CONSUME_TRIMMED: return _on_consume_trimmed(self, may_read, aux, status); case LPFSS_MESSAGE_READ: return _on_message_read(self, may_read, aux, status); case LPFSS_MESSAGE_EXTRACT: return _on_message_extract(self, msg, msg_len, status); default: return LPFSSCTRL_NEXT_STATE; } } static LogProtoStatus log_proto_framed_server_fetch(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark) { LogProtoFramedServer *self = (LogProtoFramedServer *) s; LogProtoStatus status; _ensure_buffer(self); self->fetch_counter = 0; while (_step_state_machine(self, msg, msg_len, may_read, aux, &status) != LPFSSCTRL_RETURN_WITH_STATUS) ; return status; } static void log_proto_framed_server_free(LogProtoServer *s) { LogProtoFramedServer *self = (LogProtoFramedServer *) s; g_free(self->buffer); log_proto_server_free_method(s); } LogProtoServer * log_proto_framed_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoFramedServer *self = g_new0(LogProtoFramedServer, 1); log_proto_server_init(&self->super, transport, options); self->super.prepare = log_proto_framed_server_prepare; self->super.fetch = log_proto_framed_server_fetch; self->super.free_fn = log_proto_framed_server_free; self->half_message_in_buffer = FALSE; self->state = LPFSS_FRAME_READ; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-framed-server.h000066400000000000000000000023231450431004300245440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_FRAMED_SERVER_H_INCLUDED #define LOGPROTO_FRAMED_SERVER_H_INCLUDED #include "logproto-server.h" LogProtoServer *log_proto_framed_server_new(LogTransport *transport, const LogProtoServerOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-multiline-server.c000066400000000000000000000031451450431004300253060ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto/logproto-multiline-server.h" #include "logproto/logproto-text-server.h" #include "multi-line/multi-line-logic.h" /* * This is basically a factory that takes multi-line related options and * constructs the appropriate LogProtoServer instance. */ LogProtoServer * log_proto_multiline_server_new(LogTransport *transport, const LogProtoServerOptions *options, MultiLineLogic *multi_line) { LogProtoServer *server = log_proto_text_server_new(transport, options); log_proto_text_server_set_multi_line(server, multi_line); return server; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-multiline-server.h000066400000000000000000000025551450431004300253170ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_MULTILINE_SERVER_INCLUDED #define LOGPROTO_MULTILINE_SERVER_INCLUDED #include "logproto/logproto-server.h" #include "multi-line/multi-line-logic.h" LogProtoServer * log_proto_multiline_server_new(LogTransport *transport, const LogProtoServerOptions *options, MultiLineLogic *multi_line); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-proxied-text-server.c000066400000000000000000000470671450431004300257530ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "messages.h" #include "logproto-proxied-text-server.h" #include "transport/multitransport.h" #include "transport/transport-factory-tls.h" #include "str-utils.h" #define IP_BUF_SIZE 64 /* This file implements: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt */ /* PROXYv1 line without newlines or terminating zero character. The * protocol specification contains the number 108 that includes both the * CRLF sequence and the NUL */ #define PROXY_PROTO_HDR_MAX_LEN_RFC 105 /* the size of the buffer we use to fetch the PROXY header into */ #define PROXY_PROTO_HDR_BUFFER_SIZE 1500 /* the amount of bytes we need from the client to detect protocol version */ #define PROXY_PROTO_HDR_MAGIC_LEN 5 typedef struct _LogProtoProxiedTextServer { LogProtoTextServer super; // Info received from the proxied that should be added as LogTransportAuxData to // any message received through this server instance. struct { gboolean unknown; gchar src_ip[IP_BUF_SIZE]; gchar dst_ip[IP_BUF_SIZE]; int ip_version; int src_port; int dst_port; } info; // Flag to only run handshake() once gboolean handshake_done; gboolean has_to_switch_to_tls; enum { LPPTS_INITIAL, LPPTS_DETERMINE_VERSION, LPPTS_PROXY_V1_READ_LINE, LPPTS_PROXY_V2_READ_HEADER, LPPTS_PROXY_V2_READ_PAYLOAD, } header_fetch_state; /* 0 unknown, 1 or 2 indicate proxy header version */ gint proxy_header_version; guchar proxy_header_buff[PROXY_PROTO_HDR_BUFFER_SIZE]; gsize proxy_header_buff_len; } LogProtoProxiedTextServer; struct proxy_hdr_v2 { uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */ uint8_t ver_cmd; /* protocol version and command */ uint8_t fam; /* protocol family and address */ uint16_t len; /* number of following bytes part of the header */ }; union proxy_addr { struct { /* for TCP/UDP over IPv4, len = 12 */ uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port; } ipv4_addr; struct { /* for TCP/UDP over IPv6, len = 36 */ uint8_t src_addr[16]; uint8_t dst_addr[16]; uint16_t src_port; uint16_t dst_port; } ipv6_addr; struct { /* for AF_UNIX sockets, len = 216 */ uint8_t src_addr[108]; uint8_t dst_addr[108]; } unix_addr; }; #define PROXY_HDR_TCP4 "PROXY TCP4 " #define PROXY_HDR_TCP6 "PROXY TCP6 " #define PROXY_HDR_UNKNOWN "PROXY UNKNOWN" static gboolean _check_proxy_v1_header_length(const guchar *msg, gsize msg_len) { if (msg_len > PROXY_PROTO_HDR_MAX_LEN_RFC) { msg_error("PROXY proto header length exceeds max length defined by the specification", evt_tag_long("length", msg_len), evt_tag_str("header", (const gchar *)msg)); return FALSE; } return TRUE; } static gboolean _check_proxy_v1_header(const guchar *msg, gsize msg_len, const gchar *expected_header, gsize *header_len) { gsize expected_header_length = strlen(expected_header); if (msg_len < expected_header_length) return FALSE; *header_len = expected_header_length; return strncmp((const gchar *)msg, expected_header, expected_header_length) == 0; } static gboolean _is_proxy_v1_proto_tcp4(const guchar *msg, gsize msg_len, gsize *header_len) { return _check_proxy_v1_header(msg, msg_len, PROXY_HDR_TCP4, header_len); } static gboolean _is_proxy_v1_proto_tcp6(const guchar *msg, gsize msg_len, gsize *header_len) { return _check_proxy_v1_header(msg, msg_len, PROXY_HDR_TCP6, header_len); } static gboolean _is_proxy_v1_unknown(const guchar *msg, gsize msg_len, gsize *header_len) { return _check_proxy_v1_header(msg, msg_len, PROXY_HDR_UNKNOWN, header_len); } static gboolean _parse_proxy_v1_unknown_header(LogProtoProxiedTextServer *self, const guchar *msg, gsize msg_len) { if (msg_len == 0) return TRUE; msg_warning("PROXY UNKNOWN header contains unexpected parameters", evt_tag_mem("parameters", msg, msg_len)); return TRUE; } static gboolean _parse_proxy_v1_tcp_header(LogProtoProxiedTextServer *self, const guchar *msg, gsize msg_len) { if (msg_len == 0) return FALSE; GString *params_str = g_string_new_len((const gchar *)msg, msg_len); gboolean result = FALSE; msg_debug("PROXY header params", evt_tag_str("params", (const gchar *)msg)); gchar **params = strsplit(params_str->str, ' ', 5); gint params_n = g_strv_length(params); if (params_n < 4) goto ret; g_strlcpy(self->info.src_ip, params[0], IP_BUF_SIZE); g_strlcpy(self->info.dst_ip, params[1], IP_BUF_SIZE); self->info.src_port = atoi(params[2]); if (self->info.src_port > 65535 || self->info.src_port < 0) msg_warning("PROXT TCP header contains invalid src port", evt_tag_str("src port", params[2])); self->info.dst_port = atoi(params[3]); if (self->info.dst_port > 65535 || self->info.dst_port < 0) msg_warning("PROXT TCP header contains invalid dst port", evt_tag_str("dst port", params[2])); if (params_n > 4) msg_warning("PROXY TCP header contains unexpected paramaters", evt_tag_str("parameters", params[4])); result = TRUE; ret: if (params) g_strfreev(params); g_string_free(params_str, TRUE); return result; } static gboolean _extract_proxy_v1_header(LogProtoProxiedTextServer *self, guchar **msg, gsize *msg_len) { if (self->proxy_header_buff[self->proxy_header_buff_len - 1] == '\n') self->proxy_header_buff_len--; if (self->proxy_header_buff[self->proxy_header_buff_len - 1] == '\r') self->proxy_header_buff_len--; self->proxy_header_buff[self->proxy_header_buff_len] = 0; *msg = self->proxy_header_buff; *msg_len = self->proxy_header_buff_len; return TRUE; } static gboolean _parse_proxy_v1_header(LogProtoProxiedTextServer *self) { guchar *proxy_line; gsize proxy_line_len; if (!_extract_proxy_v1_header(self, &proxy_line, &proxy_line_len)) return FALSE; gsize header_len = 0; if (!_check_proxy_v1_header_length(proxy_line, proxy_line_len)) return FALSE; if (_is_proxy_v1_unknown(proxy_line, proxy_line_len, &header_len)) { self->info.unknown = TRUE; return _parse_proxy_v1_unknown_header(self, proxy_line + header_len, proxy_line_len - header_len); } if (_is_proxy_v1_proto_tcp4(proxy_line, proxy_line_len, &header_len)) { self->info.ip_version = 4; return _parse_proxy_v1_tcp_header(self, proxy_line + header_len, proxy_line_len - header_len); } if (_is_proxy_v1_proto_tcp6(proxy_line, proxy_line_len, &header_len)) { self->info.ip_version = 6; return _parse_proxy_v1_tcp_header(self, proxy_line + header_len, proxy_line_len - header_len); } return FALSE; } static gboolean _parse_proxy_v2_proxy_address(LogProtoProxiedTextServer *self, struct proxy_hdr_v2 *proxy_hdr, union proxy_addr *proxy_addr) { gint address_family = (proxy_hdr->fam & 0xF0) >> 4; gint proxy_header_len = ntohs(proxy_hdr->len); if (address_family == 1 && proxy_header_len >= sizeof(proxy_addr->ipv4_addr)) { /* AF_INET */ inet_ntop(AF_INET, (gchar *) &proxy_addr->ipv4_addr.src_addr, self->info.src_ip, sizeof(self->info.src_ip)); inet_ntop(AF_INET, (gchar *) &proxy_addr->ipv4_addr.dst_addr, self->info.dst_ip, sizeof(self->info.dst_ip)); self->info.src_port = ntohs(proxy_addr->ipv4_addr.src_port); self->info.dst_port = ntohs(proxy_addr->ipv4_addr.dst_port); self->info.ip_version = 4; return TRUE; } else if (address_family == 2 && proxy_header_len >= sizeof(proxy_addr->ipv6_addr)) { /* AF_INET6 */ inet_ntop(AF_INET6, (gchar *) &proxy_addr->ipv6_addr.src_addr, self->info.src_ip, sizeof(self->info.src_ip)); inet_ntop(AF_INET6, (gchar *) &proxy_addr->ipv6_addr.dst_addr, self->info.dst_ip, sizeof(self->info.dst_ip)); self->info.src_port = ntohs(proxy_addr->ipv6_addr.src_port); self->info.dst_port = ntohs(proxy_addr->ipv6_addr.dst_port); self->info.ip_version = 6; } else if (address_family == 0) { /* AF_UNSPEC */ self->info.unknown = TRUE; return TRUE; } msg_error("PROXYv2 header does not have enough bytes to represent endpoint addresses or unknown address_family", evt_tag_int("proxy_header_len", proxy_header_len), evt_tag_int("address_family", address_family)); return FALSE; } static gboolean _parse_proxy_v2_header(LogProtoProxiedTextServer *self) { struct proxy_hdr_v2 *proxy_hdr = (struct proxy_hdr_v2 *) self->proxy_header_buff; union proxy_addr *proxy_addr = (union proxy_addr *)(proxy_hdr + 1); /* is this proxy v2 */ if ((proxy_hdr->ver_cmd & 0xF0) != 0x20) return FALSE; if ((proxy_hdr->ver_cmd & 0xF) == 0) { /* LOCAL connection */ return TRUE; } else if ((proxy_hdr->ver_cmd & 0xF) == 1) { /* PROXY connection */ return _parse_proxy_v2_proxy_address(self, proxy_hdr, proxy_addr); } return FALSE; } static gboolean _parse_proxy_header(LogProtoProxiedTextServer *self) { if (self->proxy_header_version == 1) return _parse_proxy_v1_header(self); else if (self->proxy_header_version == 2) return _parse_proxy_v2_header(self); else g_assert_not_reached(); } static LogProtoStatus _fetch_chunk(LogProtoProxiedTextServer *self, gsize upto_bytes) { g_assert(upto_bytes < sizeof(self->proxy_header_buff)); if (self->proxy_header_buff_len < upto_bytes) { gssize rc = log_transport_read(self->super.super.super.transport, &(self->proxy_header_buff[self->proxy_header_buff_len]), upto_bytes - self->proxy_header_buff_len, NULL); if (rc < 0) { if (errno == EAGAIN) return LPS_AGAIN; else { msg_error("I/O error occurred while reading proxy header", evt_tag_int(EVT_TAG_FD, self->super.super.super.transport->fd), evt_tag_error(EVT_TAG_OSERROR)); return LPS_ERROR; } } /* EOF without data */ if (rc == 0) { return LPS_EOF; } self->proxy_header_buff_len += rc; } if (self->proxy_header_buff_len == upto_bytes) return LPS_SUCCESS; return LPS_AGAIN; } static inline LogProtoStatus _fetch_until_newline(LogProtoProxiedTextServer *self) { /* leave 1 character for terminating zero. We should have plenty of space * in our buffer, as the longest line we need to fetch is 107 bytes * including the line terminator characters. */ while (self->proxy_header_buff_len < sizeof(self->proxy_header_buff) - 1) { LogProtoStatus status = _fetch_chunk(self, self->proxy_header_buff_len + 1); if (status != LPS_SUCCESS) return status; if (self->proxy_header_buff[self->proxy_header_buff_len - 1] == '\n') { return LPS_SUCCESS; } } msg_error("PROXY proto header with invalid header length", evt_tag_int("max_parsable_length", sizeof(self->proxy_header_buff)-1), evt_tag_int("max_length_by_spec", PROXY_PROTO_HDR_MAX_LEN_RFC), evt_tag_long("length", self->proxy_header_buff_len), evt_tag_str("header", (const gchar *)self->proxy_header_buff)); return LPS_ERROR; } static LogProtoStatus _fetch_proxy_v2_payload(LogProtoProxiedTextServer *self) { struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *) self->proxy_header_buff; gint proxy_header_len = ntohs(hdr->len); if (self->proxy_header_buff_len + proxy_header_len > sizeof(self->proxy_header_buff)) { msg_error("PROXYv2 proto header with invalid header length", evt_tag_int("max_parsable_length", sizeof(self->proxy_header_buff)), evt_tag_long("length", proxy_header_len)); return LPS_ERROR; } return _fetch_chunk(self, self->proxy_header_buff_len + proxy_header_len); } static gboolean _is_proxy_version_v1(LogProtoProxiedTextServer *self) { if (self->proxy_header_buff_len < PROXY_PROTO_HDR_MAGIC_LEN) return FALSE; return memcmp(self->proxy_header_buff, "PROXY", PROXY_PROTO_HDR_MAGIC_LEN) == 0; } static gboolean _is_proxy_version_v2(LogProtoProxiedTextServer *self) { if (self->proxy_header_buff_len < PROXY_PROTO_HDR_MAGIC_LEN) return FALSE; return memcmp(self->proxy_header_buff, "\x0D\x0A\x0D\x0A\x00", PROXY_PROTO_HDR_MAGIC_LEN) == 0; } static inline LogProtoStatus _fetch_into_proxy_buffer(LogProtoProxiedTextServer *self) { LogProtoStatus status; switch (self->header_fetch_state) { case LPPTS_INITIAL: self->header_fetch_state = LPPTS_DETERMINE_VERSION; /* fallthrough */ case LPPTS_DETERMINE_VERSION: status = _fetch_chunk(self, PROXY_PROTO_HDR_MAGIC_LEN); if (status != LPS_SUCCESS) return status; if (_is_proxy_version_v1(self)) { self->header_fetch_state = LPPTS_PROXY_V1_READ_LINE; self->proxy_header_version = 1; goto process_proxy_v1; } else if (_is_proxy_version_v2(self)) { self->header_fetch_state = LPPTS_PROXY_V2_READ_HEADER; self->proxy_header_version = 2; goto process_proxy_v2; } else { msg_error("Unable to determine PROXY protocol version", evt_tag_int(EVT_TAG_FD, self->super.super.super.transport->fd)); return LPS_ERROR; } g_assert_not_reached(); case LPPTS_PROXY_V1_READ_LINE: process_proxy_v1: return _fetch_until_newline(self); case LPPTS_PROXY_V2_READ_HEADER: process_proxy_v2: status = _fetch_chunk(self, sizeof(struct proxy_hdr_v2)); if (status != LPS_SUCCESS) return status; self->header_fetch_state = LPPTS_PROXY_V2_READ_PAYLOAD; /* fallthrough */ case LPPTS_PROXY_V2_READ_PAYLOAD: return _fetch_proxy_v2_payload(self); default: g_assert_not_reached(); } } static gboolean _switch_to_tls(LogProtoProxiedTextServer *self) { if (!multitransport_switch((MultiTransport *)self->super.super.super.transport, transport_factory_tls_id())) { msg_error("proxied-tls failed to switch to TLS"); return FALSE; } msg_debug("proxied-tls switch to TLS: OK"); return TRUE; } static LogProtoPrepareAction log_proto_proxied_text_server_prepare(LogProtoServer *s, GIOCondition *cond, gint *timeout) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) s; *cond = s->transport->cond; if(self->handshake_done) return log_proto_text_server_prepare_method(s, cond, timeout); /* if there's no pending I/O in the transport layer, then we want to do a read */ if (*cond == 0) *cond = G_IO_IN; return LPPA_POLL_IO; } static LogProtoStatus log_proto_proxied_text_server_handshake(LogProtoServer *s) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) s; LogProtoStatus status = _fetch_into_proxy_buffer(self); self->handshake_done = (status == LPS_SUCCESS); if (status != LPS_SUCCESS) return status; gboolean parsable = _parse_proxy_header(self); msg_debug("PROXY protocol header received", evt_tag_int("version", self->proxy_header_version), self->proxy_header_version == 1 ? evt_tag_mem("header", self->proxy_header_buff, self->proxy_header_buff_len) : evt_tag_str("header", "")); if (parsable) { msg_trace("PROXY protocol header parsed successfully"); if (self->has_to_switch_to_tls && !_switch_to_tls(self)) return LPS_ERROR; return LPS_SUCCESS; } else { msg_error("Error parsing PROXY protocol header"); return LPS_ERROR; } } static gboolean log_proto_proxied_text_server_handshake_in_progress(LogProtoServer *s) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) s; return !self->handshake_done; } static void _augment_aux_data(LogProtoProxiedTextServer *self, LogTransportAuxData *aux) { gchar buf1[8]; gchar buf2[8]; gchar buf3[8]; if (self->info.unknown) return; snprintf(buf1, 8, "%i", self->info.src_port); snprintf(buf2, 8, "%i", self->info.dst_port); snprintf(buf3, 8, "%i", self->info.ip_version); log_transport_aux_data_add_nv_pair(aux, "PROXIED_SRCIP", self->info.src_ip); log_transport_aux_data_add_nv_pair(aux, "PROXIED_DSTIP", self->info.dst_ip); log_transport_aux_data_add_nv_pair(aux, "PROXIED_SRCPORT", buf1); log_transport_aux_data_add_nv_pair(aux, "PROXIED_DSTPORT", buf2); log_transport_aux_data_add_nv_pair(aux, "PROXIED_IP_VERSION", buf3); return; } static LogProtoStatus log_proto_proxied_text_server_fetch(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) s; LogProtoStatus status = log_proto_buffered_server_fetch(&self->super.super.super, msg, msg_len, may_read, aux, bookmark); if (status != LPS_SUCCESS) return status; _augment_aux_data(self, aux); return LPS_SUCCESS; } static void log_proto_proxied_text_server_free(LogProtoServer *s) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) s; msg_debug("Freeing PROXY protocol source driver", evt_tag_printf("driver", "%p", self)); log_proto_text_server_free(&self->super.super.super); return; } static void log_proto_proxied_text_server_init(LogProtoProxiedTextServer *self, LogTransport *transport, const LogProtoServerOptions *options) { msg_info("Initializing PROXY protocol source driver", evt_tag_printf("driver", "%p", self)); log_proto_text_server_init(&self->super, transport, options); self->super.super.super.prepare = log_proto_proxied_text_server_prepare; self->super.super.super.handshake_in_progess = log_proto_proxied_text_server_handshake_in_progress; self->super.super.super.handshake = log_proto_proxied_text_server_handshake; self->super.super.super.fetch = log_proto_proxied_text_server_fetch; self->super.super.super.free_fn = log_proto_proxied_text_server_free; return; } LogProtoServer * log_proto_proxied_text_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoProxiedTextServer *self = g_new0(LogProtoProxiedTextServer, 1); log_proto_proxied_text_server_init(self, transport, options); return &self->super.super.super; } LogProtoServer * log_proto_proxied_text_tls_passthrough_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoProxiedTextServer *self = (LogProtoProxiedTextServer *) log_proto_proxied_text_server_new(transport, options); self->has_to_switch_to_tls = TRUE; return &self->super.super.super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-proxied-text-server.h000066400000000000000000000024561450431004300257510ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_PROXIED_TEXT_SERVER #define LOGPROTO_PROXIED_TEXT_SERVER #include "logproto-text-server.h" LogProtoServer *log_proto_proxied_text_server_new(LogTransport *transport, const LogProtoServerOptions *options); LogProtoServer *log_proto_proxied_text_tls_passthrough_server_new(LogTransport *transport, const LogProtoServerOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-record-server.c000066400000000000000000000115451450431004300245650ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-record-server.h" #include "logproto-buffered-server.h" #include "messages.h" #include /* proto that reads the stream in even sized chunks */ typedef struct _LogProtoRecordServer LogProtoRecordServer; struct _LogProtoRecordServer { LogProtoBufferedServer super; gint record_size; }; static gboolean log_proto_record_server_validate_options(LogProtoServer *s) { LogProtoRecordServer *self = (LogProtoRecordServer *) s; if (s->options->max_buffer_size < self->record_size) { msg_error("Buffer is too small to hold the number of bytes required for a record, please make sure log-msg-size() is greater than equal to record-size", evt_tag_int("record_size", self->record_size), evt_tag_int("max_buffer_size", s->options->max_buffer_size)); return FALSE; } return log_proto_buffered_server_validate_options_method(s); } static gint log_proto_record_server_read_data(LogProtoBufferedServer *s, guchar *buf, gsize len, LogTransportAuxData *aux) { LogProtoRecordServer *self = (LogProtoRecordServer *) s; gint rc; /* assert that we have enough space in the buffer to read record_size bytes */ g_assert(len >= self->record_size); len = self->record_size; rc = log_transport_read(self->super.super.transport, buf, len, aux); if (rc > 0 && rc != self->record_size) { msg_error("Record size was set, and couldn't read enough bytes", evt_tag_int(EVT_TAG_FD, self->super.super.transport->fd), evt_tag_int("record_size", self->record_size), evt_tag_int("read", rc)); errno = EIO; return -1; } return rc; } static void log_proto_record_server_init(LogProtoRecordServer *self, LogTransport *transport, const LogProtoServerOptions *options, gint record_size) { log_proto_buffered_server_init(&self->super, transport, options); self->super.super.validate_options = log_proto_record_server_validate_options; self->super.read_data = log_proto_record_server_read_data; self->super.stream_based = FALSE; self->record_size = record_size; } static gboolean log_proto_binary_record_server_fetch_from_buffer(LogProtoBufferedServer *s, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(s); *msg_len = buffer_bytes; state->pending_buffer_pos = state->pending_buffer_end; *msg = buffer_start; log_proto_buffered_server_put_state(s); return TRUE; } LogProtoServer * log_proto_binary_record_server_new(LogTransport *transport, const LogProtoServerOptions *options, gint record_size) { LogProtoRecordServer *self = g_new0(LogProtoRecordServer, 1); log_proto_record_server_init(self, transport, options, record_size); self->super.fetch_from_buffer = log_proto_binary_record_server_fetch_from_buffer; return &self->super.super; } static gboolean log_proto_padded_record_server_fetch_from_buffer(LogProtoBufferedServer *s, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(s); const guchar *eol; eol = find_eom(buffer_start, buffer_bytes); *msg_len = (eol ? eol - buffer_start : buffer_bytes); state->pending_buffer_pos = state->pending_buffer_end; *msg = buffer_start; log_proto_buffered_server_put_state(s); return TRUE; } LogProtoServer * log_proto_padded_record_server_new(LogTransport *transport, const LogProtoServerOptions *options, gint record_size) { LogProtoRecordServer *self = g_new0(LogProtoRecordServer, 1); log_proto_record_server_init(self, transport, options, record_size); self->super.fetch_from_buffer = log_proto_padded_record_server_fetch_from_buffer; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-record-server.h000066400000000000000000000034461450431004300245730ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_RECORD_SERVER_H_INCLUDED #define LOGPROTO_RECORD_SERVER_H_INCLUDED #include "logproto-server.h" /* * LogProtoBinaryRecordServer * * This class reads input in equally sized chunks. The message is the * whole record, regardless of embedded NUL/NL characters. */ LogProtoServer *log_proto_binary_record_server_new(LogTransport *transport, const LogProtoServerOptions *options, gint record_size); /* * LogProtoPaddedRecordServer * * This class reads input in equally sized chunks. The message lasts * until the first EOL/NUL character within the chunk. */ LogProtoServer *log_proto_padded_record_server_new(LogTransport *transport, const LogProtoServerOptions *options, gint record_size); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-server.c000066400000000000000000000146641450431004300233160ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-server.h" #include "messages.h" #include "cfg.h" #include "plugin.h" #include "plugin-types.h" #include "ack-tracker/ack_tracker_factory.h" /** * Find the character terminating the buffer. * * NOTE: when looking for the end-of-message here, it either needs to be * terminated via NUL or via NL, when terminating via NL we have to make * sure that there's no NUL left in the message. This function iterates over * the input data and returns a pointer to the first occurrence of NL or NUL. * * It uses an algorithm similar to what there's in libc memchr/strchr. * * NOTE: find_eom is not static as it is used by a unit test program. **/ const guchar * find_eom(const guchar *s, gsize n) { const guchar *char_ptr; const gulong *longword_ptr; gulong longword, magic_bits, charmask; gchar c; c = '\n'; /* align input to long boundary */ for (char_ptr = s; n > 0 && ((gulong) char_ptr & (sizeof(longword) - 1)) != 0; ++char_ptr, n--) { if (*char_ptr == c || *char_ptr == '\0') return char_ptr; } longword_ptr = (gulong *) char_ptr; #if GLIB_SIZEOF_LONG == 8 magic_bits = 0x7efefefefefefeffL; #elif GLIB_SIZEOF_LONG == 4 magic_bits = 0x7efefeffL; #else #error "unknown architecture" #endif memset(&charmask, c, sizeof(charmask)); while (n > sizeof(longword)) { longword = *longword_ptr++; if ((((longword + magic_bits) ^ ~longword) & ~magic_bits) != 0 || ((((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask)) & ~magic_bits) != 0) { gint i; char_ptr = (const guchar *) (longword_ptr - 1); for (i = 0; i < sizeof(longword); i++) { if (*char_ptr == c || *char_ptr == '\0') return char_ptr; char_ptr++; } } n -= sizeof(longword); } char_ptr = (const guchar *) longword_ptr; while (n-- > 0) { if (*char_ptr == c || *char_ptr == '\0') return char_ptr; ++char_ptr; } return NULL; } AckTrackerFactory * log_proto_server_get_ack_tracker_factory(LogProtoServer *s) { return s->options->ack_tracker_factory; } gboolean log_proto_server_is_position_tracked(LogProtoServer *s) { AckTrackerType type = ack_tracker_factory_get_type(log_proto_server_get_ack_tracker_factory(s)); return ack_tracker_type_is_position_tracked(type); } gboolean log_proto_server_validate_options_method(LogProtoServer *s) { return TRUE; } void log_proto_server_free_method(LogProtoServer *s) { log_transport_free(s->transport); } void log_proto_server_free(LogProtoServer *s) { if (s->free_fn) s->free_fn(s); g_free(s); } void log_proto_server_init(LogProtoServer *self, LogTransport *transport, const LogProtoServerOptions *options) { self->validate_options = log_proto_server_validate_options_method; self->free_fn = log_proto_server_free_method; self->options = options; self->transport = transport; } gboolean log_proto_server_options_set_encoding(LogProtoServerOptions *self, const gchar *encoding) { GIConv convert; g_free(self->encoding); self->encoding = g_strdup(encoding); /* validate encoding */ convert = g_iconv_open("utf-8", encoding); if (convert == (GIConv) -1) return FALSE; g_iconv_close(convert); return TRUE; } void log_proto_server_options_set_ack_tracker_factory(LogProtoServerOptions *self, AckTrackerFactory *factory) { ack_tracker_factory_unref(self->ack_tracker_factory); self->ack_tracker_factory = factory; } void log_proto_server_options_defaults(LogProtoServerOptions *options) { memset(options, 0, sizeof(*options)); options->max_msg_size = -1; options->trim_large_messages = -1; options->init_buffer_size = -1; options->max_buffer_size = -1; options->ack_tracker_factory = instant_ack_tracker_bookmarkless_factory_new(); } void log_proto_server_options_init(LogProtoServerOptions *options, GlobalConfig *cfg) { if (options->initialized) return; if (options->max_msg_size == -1) { options->max_msg_size = cfg->log_msg_size; } if (options->trim_large_messages == -1) { options->trim_large_messages = cfg->trim_large_messages; } if (options->max_buffer_size == -1) { if (options->encoding) { /* Based on the implementation of LogProtoTextServer, the buffer is yielded as a complete message when max_msg_size is reached and there is no EOM in the buffer. In worst case, the buffer contains max_msg_size - 1 bytes before the next fetch, which can be 6 times max_msg_size due to the utf8 conversion. And additional space is required because of the possible leftover bytes. */ options->max_buffer_size = 8 * options->max_msg_size; } else options->max_buffer_size = options->max_msg_size; } if (options->init_buffer_size == -1) options->init_buffer_size = MIN(options->max_msg_size, options->max_buffer_size); options->initialized = TRUE; } void log_proto_server_options_destroy(LogProtoServerOptions *options) { g_free(options->encoding); ack_tracker_factory_unref(options->ack_tracker_factory); if (options->destroy) options->destroy(options); options->initialized = FALSE; } LogProtoServerFactory * log_proto_server_get_factory(PluginContext *context, const gchar *name) { Plugin *plugin; plugin = plugin_find(context, LL_CONTEXT_SERVER_PROTO, name); if (plugin && plugin->construct) return plugin->construct(plugin); return NULL; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-server.h000066400000000000000000000166471450431004300233260ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_SERVER_H_INCLUDED #define LOGPROTO_SERVER_H_INCLUDED #include "logproto.h" #include "persist-state.h" #include "transport/transport-aux-data.h" #include "ack-tracker/bookmark.h" typedef struct _LogProtoServer LogProtoServer; typedef struct _LogProtoServerOptions LogProtoServerOptions; typedef enum { LPPA_POLL_IO, LPPA_FORCE_SCHEDULE_FETCH, LPPA_SUSPEND } LogProtoPrepareAction; #define LOG_PROTO_SERVER_OPTIONS_SIZE 128 struct _LogProtoServerOptions { void (*destroy)(LogProtoServerOptions *self); gboolean initialized; gchar *encoding; /* maximum message length in bytes */ gint max_msg_size; gboolean trim_large_messages; gint max_buffer_size; gint init_buffer_size; AckTrackerFactory *ack_tracker_factory; }; typedef union LogProtoServerOptionsStorage { LogProtoServerOptions super; gchar __padding[LOG_PROTO_SERVER_OPTIONS_SIZE]; } LogProtoServerOptionsStorage; gboolean log_proto_server_options_set_encoding(LogProtoServerOptions *s, const gchar *encoding); void log_proto_server_options_set_ack_tracker_factory(LogProtoServerOptions *s, AckTrackerFactory *factory); void log_proto_server_options_defaults(LogProtoServerOptions *options); void log_proto_server_options_init(LogProtoServerOptions *options, GlobalConfig *cfg); void log_proto_server_options_destroy(LogProtoServerOptions *options); typedef void (*LogProtoServerWakeupFunc)(gpointer user_data); typedef struct _LogProtoServerWakeupCallback { LogProtoServerWakeupFunc func; gpointer user_data; } LogProtoServerWakeupCallback; struct _LogProtoServer { LogProtoStatus status; const LogProtoServerOptions *options; LogTransport *transport; AckTracker *ack_tracker; LogProtoServerWakeupCallback wakeup_callback; /* FIXME: rename to something else */ LogProtoPrepareAction (*prepare)(LogProtoServer *s, GIOCondition *cond, gint *timeout); gboolean (*restart_with_state)(LogProtoServer *s, PersistState *state, const gchar *persist_name); LogProtoStatus (*fetch)(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark); gboolean (*validate_options)(LogProtoServer *s); gboolean (*handshake_in_progess)(LogProtoServer *s); LogProtoStatus (*handshake)(LogProtoServer *s); void (*free_fn)(LogProtoServer *s); }; static inline gboolean log_proto_server_validate_options(LogProtoServer *self) { return self->validate_options(self); } static inline gboolean log_proto_server_handshake_in_progress(LogProtoServer *s) { if (s->handshake_in_progess) { return s->handshake_in_progess(s); } return FALSE; } static inline LogProtoStatus log_proto_server_handshake(LogProtoServer *s) { if (s->handshake) { return s->handshake(s); } return LPS_SUCCESS; } static inline void log_proto_server_set_options(LogProtoServer *self, const LogProtoServerOptions *options) { self->options = options; } static inline gboolean log_proto_server_prepare(LogProtoServer *s, GIOCondition *cond, gint *timeout) { return s->prepare(s, cond, timeout); } static inline gboolean log_proto_server_restart_with_state(LogProtoServer *s, PersistState *state, const gchar *persist_name) { if (s->restart_with_state) return s->restart_with_state(s, state, persist_name); return FALSE; } static inline LogProtoStatus log_proto_server_fetch(LogProtoServer *s, const guchar **msg, gsize *msg_len, gboolean *may_read, LogTransportAuxData *aux, Bookmark *bookmark) { if (s->status == LPS_SUCCESS) return s->fetch(s, msg, msg_len, may_read, aux, bookmark); return s->status; } static inline gint log_proto_server_get_fd(LogProtoServer *s) { /* FIXME: Layering violation, as transport may not be fd based at all. * But LogReader assumes it is. */ return s->transport->fd; } static inline void log_proto_server_reset_error(LogProtoServer *s) { s->status = LPS_SUCCESS; } static inline void log_proto_server_set_wakeup_cb(LogProtoServer *s, LogProtoServerWakeupFunc wakeup, gpointer user_data) { s->wakeup_callback.user_data = user_data; s->wakeup_callback.func = wakeup; } static inline void log_proto_server_wakeup_cb_call(LogProtoServerWakeupCallback *wakeup_callback) { if (wakeup_callback->func) wakeup_callback->func(wakeup_callback->user_data); } AckTrackerFactory *log_proto_server_get_ack_tracker_factory(LogProtoServer *s); gboolean log_proto_server_is_position_tracked(LogProtoServer *s); gboolean log_proto_server_validate_options_method(LogProtoServer *s); void log_proto_server_init(LogProtoServer *s, LogTransport *transport, const LogProtoServerOptions *options); void log_proto_server_free_method(LogProtoServer *s); void log_proto_server_free(LogProtoServer *s); static inline void log_proto_server_set_ack_tracker(LogProtoServer *s, AckTracker *ack_tracker) { g_assert(ack_tracker); s->ack_tracker = ack_tracker; } #define DEFINE_LOG_PROTO_SERVER(prefix, options...) \ static gpointer \ prefix ## _server_plugin_construct(Plugin *self) \ { \ static LogProtoServerFactory proto = { \ .construct = prefix ## _server_new, \ ##options \ }; \ return &proto; \ } #define LOG_PROTO_SERVER_PLUGIN(prefix, __name) \ { \ .type = LL_CONTEXT_SERVER_PROTO, \ .name = __name, \ .construct = prefix ## _server_plugin_construct, \ } #define LOG_PROTO_SERVER_PLUGIN_WITH_GRAMMAR(__parser, __name) \ { \ .type = LL_CONTEXT_SERVER_PROTO, \ .name = __name, \ .parser = &__parser, \ } typedef struct _LogProtoServerFactory LogProtoServerFactory; struct _LogProtoServerFactory { LogProtoServer *(*construct)(LogTransport *transport, const LogProtoServerOptions *options); gint default_inet_port; gboolean use_multitransport; }; static inline LogProtoServer * log_proto_server_factory_construct(LogProtoServerFactory *self, LogTransport *transport, const LogProtoServerOptions *options) { return self->construct(transport, options); } LogProtoServerFactory *log_proto_server_get_factory(PluginContext *context, const gchar *name); const guchar *find_eom(const guchar *s, gsize n); #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-text-client.c000066400000000000000000000147231450431004300242440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-text-client.h" #include "messages.h" #include static gboolean log_proto_text_client_prepare(LogProtoClient *s, gint *fd, GIOCondition *cond, gint *timeout) { LogProtoTextClient *self = (LogProtoTextClient *) s; *fd = self->super.transport->fd; *cond = self->super.transport->cond; /* if there's no pending I/O in the transport layer, then we want to do a write */ if (*cond == 0) *cond = G_IO_OUT; const gboolean pending_write = self->partial != NULL; if (!pending_write && s->options->timeout > 0) *timeout = s->options->timeout; return pending_write; } static LogProtoStatus log_proto_text_client_drop_input(LogProtoClient *s) { LogProtoTextClient *self = (LogProtoTextClient *) s; guchar buf[1024]; gint rc = -1; do { rc = log_transport_read(self->super.transport, buf, sizeof(buf), NULL); } while (rc > 0); if (rc == -1 && errno != EAGAIN) { msg_error("Error reading data", evt_tag_int("fd", self->super.transport->fd), evt_tag_error("error")); return LPS_ERROR; } else if (rc == 0) { msg_error("EOF occurred while idle", evt_tag_int("fd", log_proto_client_get_fd(&self->super))); return LPS_ERROR; } return LPS_SUCCESS; } static LogProtoStatus log_proto_text_client_flush(LogProtoClient *s) { LogProtoTextClient *self = (LogProtoTextClient *) s; gint rc; if (!self->partial) { return LPS_SUCCESS; } /* attempt to flush previously buffered data */ gint len = self->partial_len - self->partial_pos; rc = log_transport_write(self->super.transport, &self->partial[self->partial_pos], len); if (rc < 0) { if (errno != EAGAIN && errno != EINTR) { msg_error("I/O error occurred while writing", evt_tag_int("fd", self->super.transport->fd), evt_tag_error(EVT_TAG_OSERROR)); return LPS_ERROR; } return LPS_SUCCESS; } if (rc != len) { self->partial_pos += rc; return LPS_PARTIAL; } if (self->partial_free) self->partial_free(self->partial); self->partial = NULL; if (self->next_state >= 0) { self->state = self->next_state; self->next_state = -1; } log_proto_client_msg_ack(&self->super, 1); /* NOTE: we return here to give a chance to the framed protocol to send the frame header. */ return LPS_SUCCESS; } LogProtoStatus log_proto_text_client_submit_write(LogProtoClient *s, guchar *msg, gsize msg_len, GDestroyNotify msg_free, gint next_state) { LogProtoTextClient *self = (LogProtoTextClient *) s; g_assert(self->partial == NULL); self->partial = msg; self->partial_len = msg_len; self->partial_pos = 0; self->partial_free = msg_free; self->next_state = next_state; return log_proto_text_client_flush(s); } /* * log_proto_text_client_post: * @msg: formatted log message to send (this might be consumed by this function) * @msg_len: length of @msg * @consumed: pointer to a gboolean that gets set if the message was consumed by this function * @error: error information, if any * * This function posts a message to the log transport, performing buffering * of partially sent data if needed. The return value indicates whether we * successfully sent this message, or if it should be resent by the caller. **/ static LogProtoStatus log_proto_text_client_post(LogProtoClient *s, LogMessage *logmsg, guchar *msg, gsize msg_len, gboolean *consumed) { LogProtoTextClient *self = (LogProtoTextClient *) s; /* try to flush already buffered data */ *consumed = FALSE; const LogProtoStatus status = log_proto_text_client_flush(s); if (status == LPS_ERROR) { /* log_proto_flush() already logs in the case of an error */ return status; } if (self->partial || LPS_PARTIAL == status) { /* NOTE: the partial buffer has not been emptied yet even with the * flush above, we shouldn't attempt to write again. * * Otherwise: with the framed protocol this could case the frame * header to be split, and interleaved with message payload, as in: * * First bytes of frame header || payload || tail of frame header. * * This obviously would cause the framing to break. Also libssl * returns an error in this case, which is how this was discovered. */ return LPS_PARTIAL; } *consumed = TRUE; return log_proto_text_client_submit_write(s, msg, msg_len, (GDestroyNotify) g_free, -1); } void log_proto_text_client_free(LogProtoClient *s) { LogProtoTextClient *self = (LogProtoTextClient *)s; if (self->partial_free) self->partial_free(self->partial); self->partial = NULL; log_proto_client_free_method(s); }; void log_proto_text_client_init(LogProtoTextClient *self, LogTransport *transport, const LogProtoClientOptions *options) { log_proto_client_init(&self->super, transport, options); self->super.prepare = log_proto_text_client_prepare; self->super.flush = log_proto_text_client_flush; if (options->drop_input) self->super.process_in = log_proto_text_client_drop_input; self->super.post = log_proto_text_client_post; self->super.free_fn = log_proto_text_client_free; self->super.transport = transport; self->next_state = -1; } LogProtoClient * log_proto_text_client_new(LogTransport *transport, const LogProtoClientOptions *options) { LogProtoTextClient *self = g_new0(LogProtoTextClient, 1); log_proto_text_client_init(self, transport, options); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-text-client.h000066400000000000000000000034571450431004300242530ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_TEXT_CLIENT_H_INCLUDED #define LOGPROTO_TEXT_CLIENT_H_INCLUDED #include "logproto-client.h" typedef struct _LogProtoTextClient { LogProtoClient super; gint state, next_state; guchar *partial; GDestroyNotify partial_free; gsize partial_len, partial_pos; } LogProtoTextClient; LogProtoStatus log_proto_text_client_submit_write(LogProtoClient *s, guchar *msg, gsize msg_len, GDestroyNotify msg_free, gint next_state); void log_proto_text_client_init(LogProtoTextClient *self, LogTransport *transport, const LogProtoClientOptions *options); LogProtoClient *log_proto_text_client_new(LogTransport *transport, const LogProtoClientOptions *options); #define log_proto_text_client_free_method log_proto_client_free_method #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-text-server.c000066400000000000000000000263061450431004300242740ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-text-server.h" #include "messages.h" #include LogProtoPrepareAction log_proto_text_server_prepare_method(LogProtoServer *s, GIOCondition *cond, gint *timeout) { LogProtoTextServer *self = (LogProtoTextServer *) s; gboolean avail; LogProtoPrepareAction action = log_proto_buffered_server_prepare(s, cond, timeout); if (action != LPPA_POLL_IO) return action; avail = (self->cached_eol_pos != 0); return avail ? LPPA_FORCE_SCHEDULE_FETCH : LPPA_POLL_IO; } static gint log_proto_text_server_accumulate_line(LogProtoTextServer *self, const guchar *msg, gsize msg_len, gssize consumed_len) { if (self->multi_line) { const guchar *segment = &msg[consumed_len + 1]; gsize segment_len = msg_len - (segment - msg); return multi_line_logic_accumulate_line(self->multi_line, msg, consumed_len < 0 ? 0 : consumed_len, segment, segment_len); } return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } static gboolean log_proto_text_server_try_extract(LogProtoTextServer *self, LogProtoBufferedServerState *state, const guchar *buffer_start, gsize buffer_bytes, const guchar *eol, const guchar **msg, gsize *msg_len) { gint verdict; guint32 next_line_pos; guint32 next_eol_pos = 0; next_line_pos = eol + 1 - self->super.buffer; if (state->pending_buffer_end != next_line_pos) { const guchar *eom; /* we have some more data in the buffer, check if we have a * subsequent EOL there. It indicates whether we need to * read further data, or the buffer already contains a * complete line */ eom = self->find_eom(self->super.buffer + next_line_pos, state->pending_buffer_end - next_line_pos); if (eom) next_eol_pos = eom - self->super.buffer; } *msg_len = eol - buffer_start; *msg = buffer_start; verdict = log_proto_text_server_accumulate_line(self, *msg, *msg_len, self->consumed_len); if (verdict & MLL_EXTRACTED) { if (verdict & MLL_CONSUME_SEGMENT) { gint drop_length = (verdict & MLL_CONSUME_PARTIAL_AMOUNT_MASK) >> MLL_CONSUME_PARTIAL_AMOUNT_SHIFT; state->pending_buffer_pos = next_line_pos; self->cached_eol_pos = next_eol_pos; if (drop_length) *msg_len -= drop_length; } else if (verdict & MLL_REWIND_SEGMENT) { if (self->consumed_len >= 0) *msg_len = self->consumed_len; else *msg_len = 0; state->pending_buffer_pos = (buffer_start + self->consumed_len + 1) - self->super.buffer; self->cached_eol_pos = eol - self->super.buffer; } else g_assert_not_reached(); self->consumed_len = -1; } else if (verdict & MLL_WAITING) { *msg = NULL; *msg_len = 0; if (verdict & MLL_CONSUME_SEGMENT) { gint drop_length = (verdict & MLL_CONSUME_PARTIAL_AMOUNT_MASK) >> MLL_CONSUME_PARTIAL_AMOUNT_SHIFT; /* NOTE: we can't partially consume a line at the middle of a * multi-line construct, as that would mean we would have to copy * stuff to a separate buffer, which we don't at the moment for * performance reasons. * * No implementation of the MultiLineLogic interface does that and * honestly I can't even see a use-case at the moment: we only use * MLL_CONSUME_PARTIALLY() to truncate the end of the last line * (when "garbage" is found). Should we ever want to add an * implementation that extracts only parts of the incoming lines, * even in the middle, we would probably have to check the * interface, and validate at init() time that LogProtoTextBuffer * is unable to work with something that does that. * * At the moment we will violently crash if this happens with a * SIGABRT. */ g_assert(drop_length == 0); self->cached_eol_pos = next_eol_pos; self->consumed_len = eol - buffer_start; } else if (verdict & MLL_REWIND_SEGMENT) { /* when we are waiting for another line, the current one * can't be rewinded, so MLL_REWIND_SEGMENT is not valid */ g_assert_not_reached(); } else { g_assert_not_reached(); } return FALSE; } else g_assert_not_reached(); return TRUE; } static gboolean log_proto_text_server_extract(LogProtoTextServer *self, LogProtoBufferedServerState *state, const guchar *buffer_start, gsize buffer_bytes, const guchar *eol, const guchar **msg, gsize *msg_len) { do { if (log_proto_text_server_try_extract(self, state, buffer_start, buffer_bytes, eol, msg, msg_len)) return TRUE; eol = self->super.buffer + self->cached_eol_pos; } while (self->cached_eol_pos > 0); return FALSE; } static void log_proto_text_server_remove_trailing_newline(const guchar **msg, gsize *msg_len) { const guchar *msg_start = (*msg); const guchar *msg_end = msg_start + (*msg_len); /* msg_end points at the newline character. A \r or \0 may precede * this which should be removed from the message body */ while ((msg_end > msg_start) && (msg_end[-1] == '\r' || msg_end[-1] == '\n' || msg_end[-1] == 0)) msg_end--; *msg_len = msg_end - msg_start; } static inline void log_proto_text_server_yield_whole_buffer_as_message(LogProtoTextServer *self, LogProtoBufferedServerState *state, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { /* no EOL, our buffer is full, no way to move forward, return * everything we have in our buffer. */ *msg = buffer_start; *msg_len = buffer_bytes; self->consumed_len = -1; state->pending_buffer_pos = (*msg) + (*msg_len) - self->super.buffer; } static inline const guchar * log_proto_text_server_locate_next_eol(LogProtoTextServer *self, LogProtoBufferedServerState *state, const guchar *buffer_start, gsize buffer_bytes) { const guchar *eol; if (self->cached_eol_pos) { /* previous invocation was nice enough to save a cached EOL * pointer, no need to look it up again */ eol = self->super.buffer + self->cached_eol_pos; self->cached_eol_pos = 0; } else { eol = self->find_eom(buffer_start + self->consumed_len + 1, buffer_bytes - self->consumed_len - 1); } return eol; } static gboolean log_proto_text_server_message_size_too_large(LogProtoTextServer *self, gsize buffer_bytes) { return buffer_bytes >= self->super.super.options->max_msg_size; } static inline gboolean _fetch_msg_from_buffer(LogProtoTextServer *self, LogProtoBufferedServerState *state, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { const guchar *eol = log_proto_text_server_locate_next_eol(self, state, buffer_start, buffer_bytes); if (!eol) { if (log_proto_text_server_message_size_too_large(self, buffer_bytes) || log_proto_buffered_server_is_input_closed(&self->super)) { log_proto_text_server_yield_whole_buffer_as_message(self, state, buffer_start, buffer_bytes, msg, msg_len); goto success; } return FALSE; } if (log_proto_text_server_extract(self, state, buffer_start, buffer_bytes, eol, msg, msg_len)) goto success; if (log_proto_text_server_message_size_too_large(self, buffer_bytes)) { log_proto_text_server_yield_whole_buffer_as_message(self, state, buffer_start, buffer_bytes, msg, msg_len); goto success; } return FALSE; success: log_proto_text_server_remove_trailing_newline(msg, msg_len); return TRUE; } static gboolean log_proto_text_server_fetch_from_buffer(LogProtoBufferedServer *s, const guchar *buffer_start, gsize buffer_bytes, const guchar **msg, gsize *msg_len) { LogProtoTextServer *self = (LogProtoTextServer *) s; LogProtoBufferedServerState *state = log_proto_buffered_server_get_state(&self->super); gboolean result = _fetch_msg_from_buffer(self, state, buffer_start, buffer_bytes, msg, msg_len); log_proto_buffered_server_put_state(&self->super); return result; } static void log_proto_text_server_flush(LogProtoBufferedServer *s) { LogProtoTextServer *self = (LogProtoTextServer *) s; self->consumed_len = -1; self->cached_eol_pos = 0; } void log_proto_text_server_set_multi_line(LogProtoServer *s, MultiLineLogic *multi_line) { LogProtoTextServer *self = (LogProtoTextServer *) s; if (self->multi_line) multi_line_logic_free(self->multi_line); self->multi_line = multi_line; } void log_proto_text_server_free(LogProtoServer *s) { LogProtoTextServer *self = (LogProtoTextServer *) s; if (self->multi_line) multi_line_logic_free(self->multi_line); log_proto_buffered_server_free_method(&self->super.super); } void log_proto_text_server_init(LogProtoTextServer *self, LogTransport *transport, const LogProtoServerOptions *options) { log_proto_buffered_server_init(&self->super, transport, options); self->super.super.prepare = log_proto_text_server_prepare_method; self->super.super.free_fn = log_proto_text_server_free; self->super.fetch_from_buffer = log_proto_text_server_fetch_from_buffer; self->super.flush = log_proto_text_server_flush; self->find_eom = find_eom; self->super.stream_based = TRUE; self->consumed_len = -1; } LogProtoServer * log_proto_text_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoTextServer *self = g_new0(LogProtoTextServer, 1); log_proto_text_server_init(self, transport, options); return &self->super.super; } static const guchar * _find_nl_as_eom(const guchar *s, gsize n) { return memchr(s, '\n', n); } LogProtoServer * log_proto_text_with_nuls_server_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoTextServer *self = g_new0(LogProtoTextServer, 1); log_proto_text_server_init(self, transport, options); self->find_eom = _find_nl_as_eom; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto-text-server.h000066400000000000000000000044411450431004300242750ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_TEXT_SERVER_INCLUDED #define LOGPROTO_TEXT_SERVER_INCLUDED #include "logproto-buffered-server.h" #include "multi-line/multi-line-logic.h" typedef struct _LogProtoTextServer LogProtoTextServer; struct _LogProtoTextServer { LogProtoBufferedServer super; MultiLineLogic *multi_line; const guchar *(*find_eom)(const guchar *s, gsize n); gint32 consumed_len; gint32 cached_eol_pos; }; void log_proto_text_server_set_multi_line(LogProtoServer *s, MultiLineLogic *multi_line); /* LogProtoTextServer * * This class processes text files/streams. Each record is terminated via an EOL character. */ LogProtoServer *log_proto_text_server_new(LogTransport *transport, const LogProtoServerOptions *options); LogProtoServer *log_proto_text_with_nuls_server_new(LogTransport *transport, const LogProtoServerOptions *options); void log_proto_text_server_free(LogProtoServer *self); void log_proto_text_server_init(LogProtoTextServer *self, LogTransport *transport, const LogProtoServerOptions *options); LogProtoPrepareAction log_proto_text_server_prepare_method(LogProtoServer *s, GIOCondition *cond, gint *timeout); static inline gboolean log_proto_text_server_validate_options_method(LogProtoServer *s) { return log_proto_buffered_server_validate_options_method(s); } #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/logproto.h000066400000000000000000000054331450431004300220110ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPROTO_H_INCLUDED #define LOGPROTO_H_INCLUDED #include "transport/logtransport.h" typedef enum { LPS_SUCCESS, LPS_ERROR, LPS_EOF, LPS_PARTIAL, LPS_AGAIN, } LogProtoStatus; /* * log_proto_get_char_size_for_fixed_encoding: * * This function returns the number of bytes of a single character in the * encoding specified by the @encoding parameter, provided it is listed in * the limited set hard-wired in the fixed_encodings array above. * * syslog-ng sometimes needs to calculate the size of the original, raw data * that relates to its already utf8 converted input buffer. For that the * slow solution is to actually perform the utf8 -> raw conversion, however * since we don't really need the actual conversion, just the size of the * data in bytes we can be faster than that by multiplying the number of * input characters with the size of the character in the known * fixed-length-encodings in the list above. * * This function returns 0 if the encoding is not known, in which case the * slow path is to be executed. */ static inline gint log_proto_get_char_size_for_fixed_encoding(const gchar *encoding) { static struct { const gchar *prefix; gint scale; } fixed_encodings[] = { { "ascii", 1 }, { "us-ascii", 1 }, { "iso-8859", 1 }, { "iso8859", 1 }, { "latin", 1 }, { "ucs2", 2 }, { "ucs-2", 2 }, { "ucs4", 4 }, { "ucs-4", 4 }, { "koi", 1 }, { "unicode", 2 }, { "windows", 1 }, { "wchar_t", sizeof(wchar_t) }, { NULL, 0 } }; gint scale = 0; gint i; for (i = 0; fixed_encodings[i].prefix; i++) { if (strncasecmp(encoding, fixed_encodings[i].prefix, strlen(fixed_encodings[i].prefix)) == 0) { scale = fixed_encodings[i].scale; break; } } return scale; } #endif syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/000077500000000000000000000000001450431004300211305ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/CMakeLists.txt000066400000000000000000000006031450431004300236670ustar00rootroot00000000000000set(TEST_LOGPROTO_SOURCES test_logproto.c test-server-options.c test-record-server.c test-text-server.c test-dgram-server.c test-framed-server.c test-indented-multiline-server.c test-regexp-multiline-server.c test-proxy-proto.c) add_unit_test(LIBTEST CRITERION TARGET test_logproto SOURCES "${TEST_LOGPROTO_SOURCES}") add_unit_test(CRITERION TARGET test_findeom) syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/Makefile.am000066400000000000000000000021741450431004300231700ustar00rootroot00000000000000lib_logproto_tests_TESTS = \ lib/logproto/tests/test_logproto \ lib/logproto/tests/test_findeom EXTRA_DIST += lib/logproto/tests/CMakeLists.txt check_PROGRAMS += ${lib_logproto_tests_TESTS} lib_logproto_tests_test_logproto_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/logproto/tests lib_logproto_tests_test_logproto_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_logproto_tests_test_logproto_SOURCES = \ lib/logproto/tests/test_logproto.c \ lib/logproto/tests/test-server-options.c \ lib/logproto/tests/test-record-server.c \ lib/logproto/tests/test-text-server.c \ lib/logproto/tests/test-dgram-server.c \ lib/logproto/tests/test-framed-server.c \ lib/logproto/tests/test-indented-multiline-server.c \ lib/logproto/tests/test-regexp-multiline-server.c \ lib/logproto/tests/test-proxy-proto.c lib_logproto_tests_test_findeom_CFLAGS = \ $(TEST_CFLAGS) \ -I${top_srcdir}/libtest lib_logproto_tests_test_findeom_LDADD = \ ${top_builddir}/lib/libsyslog-ng.la \ ${top_builddir}/libtest/libsyslog-ng-test.a \ $(TEST_LDADD) lib_logproto_tests_test_findeom_SOURCES = \ lib/logproto/tests/test_findeom.c syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-dgram-server.c000066400000000000000000000153071450431004300246550ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "logproto/logproto-dgram-server.h" Test(log_proto, test_log_proto_dgram_server_no_encoding) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_dgram_server_new( log_transport_mock_endless_records_new( "0123456789ABCDEF0123456789ABCDEF", -1, "01234567\n", -1, "01234567\0", 9, /* utf8 */ "árvíztűrőtükörfúrógép\n\n", 32, /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n", -1, /* |rógép| */ /* ucs4 */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ "01234", 5, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567\n", -1); assert_proto_server_fetch(proto, "01234567\0", 9); /* no encoding: utf8 remains utf8 */ assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép\n\n", -1); /* no encoding: iso-8859-2 remains iso-8859-2 */ assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |.rv.zt.r.t.k.rf.| */ "\x72\xf3\x67\xe9\x70\n", /* |r.g.p| */ -1); /* no encoding, ucs4 becomes a string with embedded NULs */ assert_proto_server_fetch(proto, "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32); /* |...z...t...ű...r| */ assert_proto_server_fetch(proto, "01234", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_dgram_server_ucs4) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_dgram_server_new( log_transport_mock_endless_records_new( /* ucs4, terminated by record size */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ /* ucs4, terminated by ucs4 encododed NL at the end */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\n", 32, /* |...z...t...ű| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "árvíztűr", -1); assert_proto_server_fetch(proto, "árvíztű\n", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_dgram_server_invalid_ucs4) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_dgram_server_new( /* 31 bytes record size */ log_transport_mock_endless_records_new( /* invalid ucs4, trailing zeroes at the end */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00", 31, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Byte sequence too short, cannot convert an individual frame in its entirety"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_dgram_server_iso_8859_2) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; log_proto_server_options_set_encoding(&proto_server_options, "iso-8859-2"); proto = log_proto_dgram_server_new( log_transport_mock_endless_records_new( /* iso-8859-2, deliberately contains * accented chars so utf8 representation * becomes longer than the record size */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9", -1, /* |rógépééééééééééé| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógépééééééééééé", -1); assert_proto_server_fetch_ignored_eof(proto); log_proto_server_free(proto); } Test(log_proto, test_log_proto_dgram_server_eof_handling) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_dgram_server_new( log_transport_mock_endless_records_new( /* no eol before EOF */ "01234567", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch_ignored_eof(proto); assert_proto_server_fetch_ignored_eof(proto); assert_proto_server_fetch_ignored_eof(proto); log_proto_server_free(proto); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-framed-server.c000066400000000000000000000255071450431004300250240ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "logproto/logproto-framed-server.h" #include Test(log_proto, test_log_proto_framed_server_simple_messages) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "32 0123456789ABCDEF0123456789ABCDEF", -1, "10 01234567\n\n", -1, "10 01234567\0\0", 13, /* utf8 */ "30 árvíztűrőtükörfúrógép", -1, /* iso-8859-2 */ "21 \xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70", -1, /* |rógép| */ /* ucs4 */ "32 \x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 35, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567\n\n", -1); assert_proto_server_fetch(proto, "01234567\0\0", 10); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |.rv.zt.r.t.k.rf.| */ "\x72\xf3\x67\xe9\x70", -1); /* |r.g.p| */ assert_proto_server_fetch(proto, "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32); /* |...z...t...q...r| */ assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_io_error) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "32 0123456789ABCDEF0123456789ABCDEF", -1, LTM_INJECT_ERROR(EIO), LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Error reading RFC6587 style framed data"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_invalid_header) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "1q 0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Invalid frame header"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_too_long_line) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "48 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Incoming frame larger than log_msg_size()"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed) { LogProtoServer *proto; /* the simplest trimming scenario as a base test */ proto_server_options.max_msg_size = 32; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "48 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", 32); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed_multiple_cycles) { LogProtoServer *proto; /* - accepting one normal sized message * - trimming a "multi buffer size" message * - checking with a normal message, that the buffer is still handled correctly. */ proto_server_options.max_msg_size = 2; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_records_new( "1 0", -1, "7 1abcdef", -1, "1 2", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0", 1); assert_proto_server_fetch(proto, "1a", 2); assert_proto_server_fetch(proto, "2", 1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed_frame_at_the_end) { LogProtoServer *proto; /* - accepting one normal sized message, which fills the buffer partially * - receiving a message which has to be trimmed * -> despite we have one part of the message in the buffer, * we had to memmove it so we can read one 'max_msg_size' message * - consume the end of the trimmed message, but the trimming will already read the * first character of the next 'frame length'. * -> need to memmove the partial data, so we can read the 'frame length' properly * - checking with a normal message, that the buffer is still handled correctly */ proto_server_options.max_msg_size = 8; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_records_new( "3 01\n15 ", -1, "1abcdefg", -1, "12345674", -1, " 2abc", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01\n", 3); assert_proto_server_fetch(proto, "1abcdefg", 8); // dropping: 1234567 assert_proto_server_fetch(proto, "2abc", 4); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_too_long_line_trimmed_one_big_message) { /* Input is bigger than the buffer size. With a small and a bigger (expected to be trimmed) message. * There is a small message and a large message.*/ LogProtoServer *proto; proto_server_options.max_msg_size = 10; proto_server_options.trim_large_messages = TRUE; proto = log_proto_framed_server_new( log_transport_mock_stream_new( "2 ab16 0123456789ABCDEF", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "ab", 2); assert_proto_server_fetch(proto, "0123456789", 10); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_message_exceeds_buffer) { LogProtoServer *proto; /* should cause the buffer to be extended, shifted, as the first message * resizes the buffer to 16+10 == 26 bytes. */ proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_records_new( "16 0123456789ABCDE\n16 0123456789ABCDE\n", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0123456789ABCDE\n", -1); assert_proto_server_fetch(proto, "0123456789ABCDE\n", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_buffer_shift_before_fetch) { LogProtoServer *proto; /* this testcase fills the initially 10 byte buffer with data, which * causes a shift in log_proto_framed_server_fetch() */ proto_server_options.max_msg_size = 32; proto_server_options.init_buffer_size = 10; proto_server_options.max_buffer_size = 10; proto = log_proto_framed_server_new( log_transport_mock_records_new( "7 012345\n4", 10, " 123\n", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "012345\n", -1); assert_proto_server_fetch(proto, "123\n", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_buffer_shift_to_make_space_for_a_frame) { LogProtoServer *proto; /* this testcase fills the initially 10 byte buffer with data, which * causes a shift in log_proto_framed_server_fetch() */ proto_server_options.max_msg_size = 32; proto_server_options.init_buffer_size = 10; proto_server_options.max_buffer_size = 10; proto = log_proto_framed_server_new( log_transport_mock_records_new( "6 01234\n4 ", 10, "123\n", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01234\n", -1); assert_proto_server_fetch(proto, "123\n", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_framed_server_multi_read) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_framed_server_new( log_transport_mock_records_new( "7 foobar\n", -1, /* no EOL, proto implementation would read another chunk */ "6 fooba", -1, LTM_INJECT_ERROR(EIO), LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "foobar\n", -1); /* with multi-read, we get the injected failure at the 2nd fetch */ assert_proto_server_fetch_failure(proto, LPS_ERROR, "Error reading RFC6587 style framed data"); log_proto_server_free(proto); /* NOTE: LPBS_NOMREAD is not implemented for framed protocol */ } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-indented-multiline-server.c000066400000000000000000000112371450431004300273530ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "multi-line/indented-multi-line.h" #include "logproto/logproto-multiline-server.h" LogProtoServer * log_proto_indented_multiline_server_new(LogTransport *transport, const LogProtoServerOptions *options) { return log_proto_multiline_server_new(transport, options, indented_multi_line_new()); } static void test_proper_multiline(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_indented_multiline_server_new( /* 32 bytes max line length */ log_transport_mock_new( "0\n" " 1=2\n" " 3=4\n" "newline\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "0\n" " 1=2\n" " 3=4", -1); log_proto_server_free(proto); } Test(log_proto, test_proper_multiline) { test_proper_multiline(log_transport_mock_stream_new); test_proper_multiline(log_transport_mock_records_new); } static void test_line_without_continuation(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_indented_multiline_server_new( /* 32 bytes max line length */ log_transport_mock_new( "01234567\n", -1, "01234567\n", -1, "newline\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); log_proto_server_free(proto); } Test(log_proto, test_line_without_continuation) { test_line_without_continuation(log_transport_mock_stream_new); test_line_without_continuation(log_transport_mock_records_new); } static void test_input_starts_with_continuation(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_indented_multiline_server_new( /* 32 bytes max line length */ log_transport_mock_new( " 01234567\n", -1, "01234567\n", -1, "newline\n", -1, LTM_PADDING, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, " 01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); log_proto_server_free(proto); } Test(log_proto, test_input_starts_with_continuation) { test_input_starts_with_continuation(log_transport_mock_stream_new); test_input_starts_with_continuation(log_transport_mock_records_new); } static void test_multiline_at_eof(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; proto_server_options.max_msg_size = 32; proto = log_proto_indented_multiline_server_new( /* 32 bytes max line length */ log_transport_mock_new( "01234567\n", -1, " 01234567\n", -1, " end\n", -1, LTM_EOF), get_inited_proto_server_options()); assert_proto_server_fetch(proto, "01234567\n" " 01234567\n" " end", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_multiline_at_eof) { test_multiline_at_eof(log_transport_mock_stream_new); test_multiline_at_eof(log_transport_mock_records_new); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-proxy-proto.c000066400000000000000000000251601450431004300245770ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "logproto/logproto-proxied-text-server.h" #include typedef struct { const gchar *proxy_header; gboolean valid; } ProtocolHeaderTestParams; ParameterizedTestParameters(log_proto, test_proxy_protocol_parse_header) { static ProtocolHeaderTestParams test_params[] = { /* SUCCESS */ { "PROXY UNKNOWN\r\n", TRUE }, { "PROXY UNKNOWN extra ignored parameters\r\n", TRUE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, { "PROXY TCP6 ::1 ::2 3333 4444\r\n", TRUE }, /* INVALID PROTO */ { "PROXY UNKNOWN\n", TRUE }, // WRONG TERMINATION { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\n", TRUE }, // WRONG TERMINATION { "PROXY UNKNOWN\r", FALSE }, // WRONG TERMINATION { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r", FALSE }, // WRONG TERMINATION { "PROXY\r\n", FALSE }, { "PROXY TCP4\r\n", FALSE }, { "PROXY TCP4 1.1.1.1\r\n", FALSE }, { "PROXY TCP4 1.1.1.1 2.2.2.2\r\n", FALSE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333\r\n", FALSE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444 extra param\r\n", TRUE}, /* EXTRA WHITESPACE - PERMISSIVE */ { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444 \r\n", TRUE }, /* EXTRA WHITESPACE BEFORE PARAMETERS */ { "PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", FALSE }, /* INVALID ARGUMENTS - PERMISSIVE */ { "PROXY TCP6 1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, // WRONG IP PROTO { "PROXY TCP4 ::1 ::2 3333 4444\r\n", TRUE }, // WRONG IP PROTO { "PROXY TCP4 1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, // WRONG IP { "PROXY TCP4 1.1.1.1.1 2.2.2.2 3333 4444\r\n", TRUE }, // WRONG IP { "PROXY TCP6 ::1::0 ::1 3333 4444\r\n", TRUE }, // WRONG IP { "PROXY TCP4 1.1.1.1 2.2.2.2 33333 0\r\n", TRUE }, // WRONG PORT { "PROXY TCP4 1.1.1.1 2.2.2.2 33333 -1\r\n", TRUE }, // WRONG PORT { "PROXY TCP4 1.1.1.1 2.2.2.2 33333 65536\r\n", TRUE }, // WRONG PORT /* INVALID ARGUMENT(S)*/ { "PROXY TCP3 1.1.1.1 2.2.2.2 3333 4444\r\n", FALSE}, // WRONG IP PROTO { "PROXY TCP4 padpadpadpadpadpadpadpadpadpadpadpadpad" "padpadpadpadpadpadpadpadpadpadpadpadpadpadpadpadpad" "padpadpadpadpadpadpadpadpadpadpadpadpadpadpadpadpad", FALSE } // TOO LONG }; return cr_make_param_array(ProtocolHeaderTestParams, test_params, G_N_ELEMENTS(test_params)); } ParameterizedTest(ProtocolHeaderTestParams *params, log_proto, test_proxy_protocol_parse_header) { LogProtoServer *proto = log_proto_proxied_text_server_new(log_transport_mock_records_new(params->proxy_header, -1, LTM_EOF), get_inited_proto_server_options()); gboolean valid = log_proto_server_handshake(proto) == LPS_SUCCESS; cr_assert_eq(valid, params->valid, "This should be %s: %s", params->valid ? "valid" : "invalid", params->proxy_header); log_proto_server_free(proto); } Test(log_proto, test_proxy_protocol_handshake_and_fetch_success) { LogTransport *transport = log_transport_mock_records_new("PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", -1, "test message\n", -1, LTM_EOF); LogProtoServer *proto = log_proto_proxied_text_server_new(transport, get_inited_proto_server_options()); cr_assert_eq(log_proto_server_handshake(proto), LPS_SUCCESS); assert_proto_server_fetch(proto, "test message", -1); log_proto_server_free(proto); } Test(log_proto, test_proxy_protocol_handshake_failed) { LogTransport *transport = log_transport_mock_records_new("invalid header\r\n", -1, "test message\n", -1, LTM_EOF); LogProtoServer *proto = log_proto_proxied_text_server_new(transport, get_inited_proto_server_options()); cr_assert_eq(log_proto_server_handshake(proto), LPS_ERROR); log_proto_server_free(proto); } static void get_aux_data_from_next_message(LogProtoServer *proto, LogTransportAuxData *aux) { LogProtoStatus status; const guchar *msg = NULL; gsize msg_len = 0; Bookmark bookmark; gboolean may_read = TRUE; do { log_transport_aux_data_init(aux); status = log_proto_server_fetch(proto, &msg, &msg_len, &may_read, aux, &bookmark); if (status == LPS_AGAIN) status = LPS_SUCCESS; } while (status == LPS_SUCCESS && msg == NULL && may_read); } static void concat_nv(const gchar *name, const gchar *value, gsize value_len, gpointer user_data) { GString *aux_nv_concated = user_data; g_string_append_printf(aux_nv_concated, "%s:%s ", name, value); } Test(log_proto, test_proxy_protocol_aux_data) { const gchar *expected = "PROXIED_SRCIP:1.1.1.1 PROXIED_DSTIP:2.2.2.2 " "PROXIED_SRCPORT:3333 PROXIED_DSTPORT:4444 " "PROXIED_IP_VERSION:4 "; LogTransport *transport = log_transport_mock_records_new("PROXY TCP4 1.1.1.1 2.2.2.2 3333 4444\r\n", -1, "test message\n", -1, LTM_EOF); LogProtoServer *proto = log_proto_proxied_text_server_new(transport, get_inited_proto_server_options()); cr_assert_eq(log_proto_server_handshake(proto), LPS_SUCCESS); LogTransportAuxData aux; log_transport_aux_data_init(&aux); get_aux_data_from_next_message(proto, &aux); GString *aux_nv_concated = g_string_new(NULL); log_transport_aux_data_foreach(&aux, concat_nv, aux_nv_concated); cr_assert_str_eq(aux_nv_concated->str, expected); g_string_free(aux_nv_concated, TRUE); log_transport_aux_data_destroy(&aux); log_proto_server_free(proto); } Test(log_proto, test_proxy_protocol_v2_parse_header) { const gchar *expected = "PROXIED_SRCIP:1.1.1.1 PROXIED_DSTIP:2.2.2.2 " "PROXIED_SRCPORT:33333 PROXIED_DSTPORT:44444 " "PROXIED_IP_VERSION:4 "; LogProtoServer *proto = log_proto_proxied_text_server_new(log_transport_mock_records_new( "\r\n\r\n\0\r\nQUIT\n!\21\0\f\1\1\1\1\2\2\2\2\2025\255\234", 28, "test_message\n", -1, LTM_EOF ), get_inited_proto_server_options()); cr_assert_eq(log_proto_server_handshake(proto), LPS_SUCCESS, "Proxy protocol v2 parsing failed"); LogTransportAuxData aux; log_transport_aux_data_init(&aux); get_aux_data_from_next_message(proto, &aux); GString *aux_nv_concated = g_string_new(NULL); log_transport_aux_data_foreach(&aux, concat_nv, aux_nv_concated); cr_assert_str_eq(aux_nv_concated->str, expected); g_string_free(aux_nv_concated, TRUE); log_transport_aux_data_destroy(&aux); log_proto_server_free(proto); } static void assert_handshake_is_taking_place(LogProtoServer *proto) { gint timeout; GIOCondition cond; cr_assert_eq(log_proto_server_prepare(proto, &cond, &timeout), LPPA_POLL_IO); cr_assert_eq(cond, G_IO_IN); cr_assert(log_proto_server_handshake_in_progress(proto)); } Test(log_proto, test_proxy_protocol_header_partial_read) { LogTransportMock *transport = (LogTransportMock *) log_transport_mock_records_new(LTM_EOF); const char *proxy_header_segments[] = {"P", "ROXY TCP4 ", "1.1.1.1 ", "2.2.2.2 3333 ", "4444\r\n"}; size_t length = G_N_ELEMENTS(proxy_header_segments); for(size_t i = 0; i < length; i++) { log_transport_mock_inject_data(transport, proxy_header_segments[i], -1); log_transport_mock_inject_data(transport, LTM_INJECT_ERROR(EAGAIN)); } log_transport_mock_inject_data(transport, "test message\n", -1); LogProtoServer *proto = log_proto_proxied_text_server_new((LogTransport *) transport, get_inited_proto_server_options()); for(size_t i = 0; i < length; i++) { assert_handshake_is_taking_place(proto); cr_assert_eq(log_proto_server_handshake(proto), LPS_AGAIN); } cr_assert_eq(log_proto_server_handshake(proto), LPS_SUCCESS); cr_assert_not(log_proto_server_handshake_in_progress(proto)); const gchar *expected = "PROXIED_SRCIP:1.1.1.1 PROXIED_DSTIP:2.2.2.2 " "PROXIED_SRCPORT:3333 PROXIED_DSTPORT:4444 " "PROXIED_IP_VERSION:4 "; LogTransportAuxData aux; log_transport_aux_data_init(&aux); get_aux_data_from_next_message(proto, &aux); GString *aux_nv_concated = g_string_new(NULL); log_transport_aux_data_foreach(&aux, concat_nv, aux_nv_concated); cr_assert_str_eq(aux_nv_concated->str, expected); g_string_free(aux_nv_concated, TRUE); log_transport_aux_data_destroy(&aux); log_proto_server_free(proto); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-record-server.c000066400000000000000000000203051450431004300250330ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "logproto/logproto-record-server.h" Test(log_proto, test_log_proto_binary_record_server_no_encoding) { LogProtoServer *proto; proto = log_proto_binary_record_server_new( log_transport_mock_records_new( "0123456789ABCDEF0123456789ABCDEF", -1, "01234567\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", -1, "01234567\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32, /* utf8 */ "árvíztűrőtükörfúrógép\n\n", 32, /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n\n\n\n\n\n\n\n\n\n\n", -1, /* |rógép| */ /* ucs4 */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ "01234", 5, LTM_EOF), get_inited_proto_server_options(), 32); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", -1); assert_proto_server_fetch(proto, "01234567\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép\n\n", -1); assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |.rv.zt.r.t.k.rf.| */ "\x72\xf3\x67\xe9\x70\n\n\n\n\n\n\n\n\n\n\n", -1); /* |r.g.p| */ assert_proto_server_fetch(proto, "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32); /* |...z...t...q...r| */ assert_proto_server_fetch_failure(proto, LPS_ERROR, "Record size was set, and couldn't read enough bytes"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_padded_record_server_no_encoding) { LogProtoServer *proto; proto = log_proto_padded_record_server_new( log_transport_mock_records_new( "0123456789ABCDEF0123456789ABCDEF", -1, "01234567\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", -1, "01234567\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32, /* utf8 */ "árvíztűrőtükörfúrógép\n\n", 32, /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n\n\n\n\n\n\n\n\n\n\n", -1, /* |rógép| */ /* ucs4 */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ "01234", 5, LTM_EOF), get_inited_proto_server_options(), 32); assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); /* no encoding: utf8 remains utf8 */ assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); /* no encoding: iso-8859-2 remains iso-8859-2 */ assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |.rv.zt.r.t.k.rf.| */ "\x72\xf3\x67\xe9\x70", /* |r.g.p| */ -1); /* no encoding, ucs4 becomes an empty string as it starts with a zero byte */ assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Record size was set, and couldn't read enough bytes"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_padded_record_server_ucs4) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_padded_record_server_new( log_transport_mock_records_new( /* ucs4, terminated by record size */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ /* ucs4, terminated by ucs4 encododed NL at the end */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\n", 32, /* |...z...t...ű| */ "01234", 5, LTM_EOF), get_inited_proto_server_options(), 32); assert_proto_server_fetch(proto, "árvíztűr", -1); assert_proto_server_fetch(proto, "árvíztű", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Record size was set, and couldn't read enough bytes"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_padded_record_server_invalid_ucs4) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = log_proto_padded_record_server_new( /* 31 bytes record size */ log_transport_mock_records_new( /* invalid ucs4, trailing zeroes at the end */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00", 31, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options(), 31); assert_proto_server_fetch_failure(proto, LPS_ERROR, "Byte sequence too short, cannot convert an individual frame in its entirety"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_padded_record_server_iso_8859_2) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "iso-8859-2"); proto = log_proto_padded_record_server_new( /* 32 bytes record size */ log_transport_mock_records_new( /* iso-8859-2, deliberately contains * accented chars so utf8 representation * becomes longer than the record size */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9\xe9", -1, /* |rógépééééééééééé| */ LTM_EOF), get_inited_proto_server_options(), 32); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógépééééééééééé", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-regexp-multiline-server.c000066400000000000000000000231351450431004300270530ustar00rootroot00000000000000/* * Copyright (c) 2013-2019 Balabit * Copyright (c) 2013-2014 Balázs Scheidler * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "multi-line/multi-line-factory.h" #include "logproto/logproto-multiline-server.h" static LogProtoServer * log_proto_prefix_garbage_multiline_server_new(LogTransport *transport, const gchar *prefix, const gchar *garbage) { MultiLineOptions multi_line_options; multi_line_options_defaults(&multi_line_options); multi_line_options_set_mode(&multi_line_options, "prefix-garbage"); if (prefix) multi_line_options_set_prefix(&multi_line_options, prefix, NULL); if (garbage) multi_line_options_set_garbage(&multi_line_options, garbage, NULL); LogProtoServer *server = log_proto_multiline_server_new(transport, get_inited_proto_server_options(), multi_line_factory_construct(&multi_line_options)); multi_line_options_destroy(&multi_line_options); return server; } static LogProtoServer * log_proto_prefix_suffix_multiline_server_new(LogTransport *transport, const gchar *prefix, const gchar *suffix) { MultiLineOptions multi_line_options; multi_line_options_defaults(&multi_line_options); multi_line_options_set_mode(&multi_line_options, "prefix-suffix"); if (prefix) multi_line_options_set_prefix(&multi_line_options, prefix, NULL); if (suffix) multi_line_options_set_garbage(&multi_line_options, suffix, NULL); LogProtoServer *server = log_proto_multiline_server_new(transport, get_inited_proto_server_options(), multi_line_factory_construct(&multi_line_options)); multi_line_options_destroy(&multi_line_options); return server; } ParameterizedTestParameters(log_proto, test_lines_separated_with_prefix) { static LogTransportMockConstructor log_transport_mock_new_data_list[] = { log_transport_mock_stream_new, log_transport_mock_records_new, }; return cr_make_param_array( LogTransportMockConstructor, log_transport_mock_new_data_list, G_N_ELEMENTS(log_transport_mock_new_data_list)); } ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_lines_separated_with_prefix) { LogProtoServer *proto; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "Foo First Line\n" "Foo Second Line\n" "Foo Third Line\n" "Foo Multiline\n" "multi\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), "^Foo", NULL); assert_proto_server_fetch(proto, "Foo First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); } ParameterizedTestParameters(log_proto, test_lines_separated_with_prefix_and_garbage) { static LogTransportMockConstructor log_transport_mock_new_data_list[] = { log_transport_mock_stream_new, log_transport_mock_records_new, }; return cr_make_param_array( LogTransportMockConstructor, log_transport_mock_new_data_list, G_N_ELEMENTS(log_transport_mock_new_data_list)); } ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_lines_separated_with_prefix_and_garbage) { LogProtoServer *proto; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "Foo First Line Bar\n" "Foo Second Line Bar\n" "Foo Third Line Bar\n" "Foo Multiline\n" "multi Bar\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), "^Foo", " Bar$"); assert_proto_server_fetch(proto, "Foo First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); } ParameterizedTestParameters(log_proto, test_lines_separated_with_prefix_and_suffix) { static LogTransportMockConstructor log_transport_mock_new_data_list[] = { log_transport_mock_stream_new, log_transport_mock_records_new, }; return cr_make_param_array( LogTransportMockConstructor, log_transport_mock_new_data_list, G_N_ELEMENTS(log_transport_mock_new_data_list)); } ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_lines_separated_with_prefix_and_suffix) { LogProtoServer *proto; proto = log_proto_prefix_suffix_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "prefix first suffix garbage\n" "prefix multi\n" "suffix garbage\n" "prefix final\n", -1, LTM_PADDING, LTM_EOF), "^prefix", "suffix"); assert_proto_server_fetch(proto, "prefix first suffix", -1); assert_proto_server_fetch(proto, "prefix multi\nsuffix", -1); log_proto_server_free(proto); } ParameterizedTestParameters(log_proto, test_lines_separated_with_garbage) { static LogTransportMockConstructor log_transport_mock_new_data_list[] = { log_transport_mock_stream_new, log_transport_mock_records_new, }; return cr_make_param_array( LogTransportMockConstructor, log_transport_mock_new_data_list, G_N_ELEMENTS(log_transport_mock_new_data_list)); } ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_lines_separated_with_garbage) { LogProtoServer *proto; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "Foo First Line Bar\n" "Foo Second Line Bar\n" "Foo Third Line Bar\n" "Foo Multiline\n" "multi Bar\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), NULL, " Bar$"); assert_proto_server_fetch(proto, "Foo First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); } ParameterizedTestParameters(log_proto, test_first_line_without_prefix) { static LogTransportMockConstructor log_transport_mock_new_data_list[] = { log_transport_mock_stream_new, log_transport_mock_records_new, }; return cr_make_param_array( LogTransportMockConstructor, log_transport_mock_new_data_list, G_N_ELEMENTS(log_transport_mock_new_data_list)); } ParameterizedTest(LogTransportMockConstructor *log_transport_mock_new, log_proto, test_first_line_without_prefix) { LogProtoServer *proto; proto = log_proto_prefix_garbage_multiline_server_new( /* 32 bytes max line length, which means that the complete * multi-line block plus one additional line must fit into 32 * bytes. */ (*log_transport_mock_new)( "First Line\n" "Foo Second Line\n" "Foo Third Line\n" "Foo Multiline\n" "multi\n" "Foo final\n", -1, LTM_PADDING, LTM_EOF), "^Foo", NULL); assert_proto_server_fetch(proto, "First Line", -1); assert_proto_server_fetch(proto, "Foo Second Line", -1); assert_proto_server_fetch(proto, "Foo Third Line", -1); assert_proto_server_fetch(proto, "Foo Multiline\nmulti", -1); log_proto_server_free(proto); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-server-options.c000066400000000000000000000055001450431004300252500ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" Test(log_proto, test_log_proto_server_options_limits) { LogProtoServerOptions opts; log_proto_server_options_defaults(&opts); log_proto_server_options_init(&opts, configuration); cr_assert_gt(opts.max_msg_size, 0, "LogProtoServerOptions.max_msg_size is not initialized properly, max_msg_size=%d", opts.max_msg_size); cr_assert_gt(opts.init_buffer_size, 0, "LogProtoServerOptions.init_buffer_size is not initialized properly, init_buffer_size=%d", opts.init_buffer_size); cr_assert_gt(opts.max_buffer_size, 0, "LogProtoServerOptions.max_buffer_size is not initialized properly, max_buffer_size=%d", opts.max_buffer_size); log_proto_server_options_destroy(&opts); } Test(log_proto, test_log_proto_server_options_valid_encoding) { LogProtoServerOptions opts; log_proto_server_options_defaults(&opts); /* check that encoding can be set and error is properly returned */ log_proto_server_options_set_encoding(&opts, "utf-8"); cr_assert_str_eq(opts.encoding, "utf-8", "LogProtoServerOptions.encoding was not properly set"); log_proto_server_options_destroy(&opts); } Test(log_proto, test_log_proto_server_options_invalid_encoding) { LogProtoServerOptions opts; gboolean success; log_proto_server_options_defaults(&opts); success = log_proto_server_options_set_encoding(&opts, "never-ever-is-going-to-be-such-an-encoding"); cr_assert_str_eq(opts.encoding, "never-ever-is-going-to-be-such-an-encoding", "LogProtoServerOptions.encoding was not properly set"); log_proto_server_options_init(&opts, configuration); cr_assert_not(success, "Successfully set a bogus encoding, which is insane"); log_proto_server_options_destroy(&opts); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test-text-server.c000066400000000000000000000557601450431004300245560ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "libtest/grab-logging.h" #include "logproto/logproto-text-server.h" #include "ack-tracker/ack_tracker_factory.h" #include static gint accumulate_seq; LogProtoServer * construct_test_proto(LogTransport *transport) { proto_server_options.max_msg_size = 32; return log_proto_text_server_new(transport, get_inited_proto_server_options()); } LogProtoServer * construct_test_proto_with_nuls(LogTransport *transport) { proto_server_options.max_msg_size = 32; return log_proto_text_with_nuls_server_new(transport, get_inited_proto_server_options()); } LogProtoServer * construct_test_proto_with_accumulator(gint (*accumulator)(MultiLineLogic *, const guchar *, gsize, const guchar *, gsize), LogTransport *transport) { MultiLineLogic *multi_line = g_new0(MultiLineLogic, 1); multi_line_logic_init_instance(multi_line); multi_line->accumulate_line = accumulator; LogProtoServer *proto = construct_test_proto(transport); ((LogProtoTextServer *) proto)->multi_line = multi_line; return proto; } static gint accumulator_delay_lines(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { accumulate_seq++; if ((accumulate_seq % 2) == 0) return MLL_REWIND_SEGMENT | MLL_EXTRACTED; else return MLL_CONSUME_SEGMENT | MLL_WAITING; } static void test_log_proto_text_server_no_encoding(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; proto = construct_test_proto( /* 32 bytes max line length */ log_transport_mock_new( "01234567\n" /* line too long */ "0123456789ABCDEF0123456789ABCDEF01234567\n" /* utf8 */ "árvíztűrőtükörfúrógép\n" /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n", /* |rógép| */ -1, /* NUL terminated line */ "01234567\0" "01234567\0\n" "01234567\n\0" "01234567\r\n\0", 40, "01234567\r\n" /* no eol before EOF */ "01234567", -1, LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); /* input split due to an oversized input line */ assert_proto_server_fetch(proto, "0123456789ABCDEF0123456789ABCDEF", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch(proto, "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70", /* |rógép| */ -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "01234567", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_no_encoding) { test_log_proto_text_server_no_encoding(log_transport_mock_stream_new); test_log_proto_text_server_no_encoding(log_transport_mock_records_new); } Test(log_proto, test_log_proto_text_server_no_eol_before_eof) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_stream_new( /* no eol before EOF */ "01234567", -1, LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_with_embedded_nuls) { LogProtoServer *proto; proto = construct_test_proto_with_nuls( log_transport_mock_stream_new( /* no eol before EOF */ "01234567\n", -1, "alma\x00korte\n", 11, LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch(proto, "alma\x00korte", 10); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_eol_before_eof) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( /* eol before EOF */ "01234\n567\n890\n", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "01234", -1); assert_proto_server_fetch(proto, "567", -1); assert_proto_server_fetch(proto, "890", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_io_error_before_eof) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_stream_new( "01234567", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "01234567", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_partial_chars_before_eof) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "utf-8"); proto = construct_test_proto( log_transport_mock_stream_new( /* utf8 */ "\xc3", -1, LTM_EOF)); cr_assert(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch_failure(proto, LPS_EOF, "EOF read on a channel with leftovers from previous character conversion, dropping input"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_invalid_char_with_encoding) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "GB18030"); proto = construct_test_proto( log_transport_mock_stream_new( "foo" "\x80" "bar" "\x80" "baz", -1, LTM_EOF)); cr_assert(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "foobarbaz", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_not_fixed_encoding) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "utf-8"); /* to test whether a non-easily-reversable charset works too */ proto = construct_test_proto( log_transport_mock_stream_new( /* utf8 */ "árvíztűrőtükörfúrógép\n", -1, LTM_EOF)); cr_assert(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_ucs4) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); proto = construct_test_proto( log_transport_mock_stream_new( /* ucs4 */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72" /* |...z...t...ű...r| */ "\x00\x00\x01\x51\x00\x00\x00\x74\x00\x00\x00\xfc\x00\x00\x00\x6b" /* |...Q...t.......k| */ "\x00\x00\x00\xf6\x00\x00\x00\x72\x00\x00\x00\x66\x00\x00\x00\xfa" /* |.......r...f....| */ "\x00\x00\x00\x72\x00\x00\x00\xf3\x00\x00\x00\x67\x00\x00\x00\xe9" /* |...r.......g....| */ "\x00\x00\x00\x70\x00\x00\x00\x0a", 88, /* |...p....| */ LTM_EOF)); cr_assert(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_iso8859_2) { LogProtoServer *proto; log_proto_server_options_set_encoding(&proto_server_options, "iso-8859-2"); proto = construct_test_proto( log_transport_mock_stream_new( /* iso-8859-2 */ "\xe1\x72\x76\xed\x7a\x74\xfb\x72\xf5\x74\xfc\x6b\xf6\x72\x66\xfa" /* |árvíztűrőtükörfú| */ "\x72\xf3\x67\xe9\x70\n", -1, /* |rógép| */ LTM_EOF)); cr_assert(log_proto_server_validate_options(proto), "validate_options() returned failure but it should have succeeded"); assert_proto_server_fetch(proto, "árvíztűrőtükörfúrógép", -1); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_invalid_encoding) { LogProtoServer *proto; gboolean success; log_proto_server_options_set_encoding(&proto_server_options, "never-ever-is-going-to-be-such-an-encoding"); proto = construct_test_proto( log_transport_mock_stream_new( "", -1, LTM_EOF)); start_grabbing_messages(); success = log_proto_server_validate_options(proto); assert_grabbed_log_contains("Unknown character set name specified; encoding='never-ever-is-going-to-be-such-an-encoding'"); cr_assert_not(success, "validate_options() returned success but it should have failed"); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_multi_read) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( "foobar\n", -1, /* no EOL, proto implementation would read another chunk */ "foobaz", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "foobar", -1); assert_proto_server_fetch(proto, "foobaz", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_multi_read_not_allowed, .disabled = true) { /* FIXME: */ LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_records_new( "foobar\n", -1, /* no EOL, proto implementation would read another chunk */ "foobaz", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); ((LogProtoBufferedServer *) proto)->no_multi_read = TRUE; assert_proto_server_fetch_single_read(proto, "foobar", -1); /* because of EAGAIN */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* because of NOMREAD, partial lines are returned as empty */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* because of EAGAIN */ assert_proto_server_fetch_single_read(proto, NULL, -1); /* error was detected by this time, partial line is returned before the error */ assert_proto_server_fetch_single_read(proto, "foobaz", -1); /* finally the error is returned too */ assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_is_not_fetching_input_as_long_as_there_is_an_eol_in_buffer) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_delay_lines, log_transport_mock_records_new( /* should the LogProto instance read ahead, it gets an * EIO error */ "foo\n" "bar\n" "baz\n" "booz\n", -1, LTM_INJECT_ERROR(EIO), LTM_EOF)); assert_proto_server_fetch(proto, "foo", -1); assert_proto_server_fetch(proto, "bar", -1); assert_proto_server_fetch(proto, "baz", -1); assert_proto_server_fetch(proto, "booz", -1); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_free(proto); } static gint accumulator_assert_that_lines_are_starting_with_sequence_number(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { cr_assert_eq((msg[0] - '0'), accumulate_seq, "accumulate_line: Message doesn't start with sequence number, msg=%.*s, seq=%d", (int)msg_len, msg, accumulate_seq); cr_assert_eq(msg_len, 0, "Initial invocation of the accumulator expects 0 as msg_len"); accumulate_seq++; return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } static void test_log_proto_text_server_accumulate_line_is_called_for_each_line(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_assert_that_lines_are_starting_with_sequence_number, /* 32 bytes max line length */ log_transport_mock_new( "0 line\n" "1 line\n" "2 line\n" "3 line\n", -1, LTM_PADDING, LTM_EOF)); assert_proto_server_fetch(proto, "0 line", -1); assert_proto_server_fetch(proto, "1 line", -1); assert_proto_server_fetch(proto, "2 line", -1); assert_proto_server_fetch(proto, "3 line", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_accumulate_line_is_called_for_each_line) { test_log_proto_text_server_accumulate_line_is_called_for_each_line(log_transport_mock_stream_new); test_log_proto_text_server_accumulate_line_is_called_for_each_line(log_transport_mock_records_new); } static gint accumulator_extract_pairs(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { accumulate_seq++; if ((accumulate_seq % 2) == 0) return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; else return MLL_CONSUME_SEGMENT | MLL_WAITING; } static void test_log_proto_text_server_accumulate_line_can_consume_lines_without_returning_them( LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_extract_pairs, log_transport_mock_new( "0 line\n" "1 line\n" "2 line\n" "3 line\n", -1, LTM_PADDING, LTM_EOF)); assert_proto_server_fetch(proto, "0 line\n1 line", -1); assert_proto_server_fetch(proto, "2 line\n3 line", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_accumulate_line_can_consume_lines_without_returning_them) { test_log_proto_text_server_accumulate_line_can_consume_lines_without_returning_them(log_transport_mock_stream_new); test_log_proto_text_server_accumulate_line_can_consume_lines_without_returning_them(log_transport_mock_records_new); } static gint accumulator_join_continuation_lines(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { if (msg_len > 0 && segment_len > 0) { gchar first_char = segment[0]; if (first_char == ' ') return MLL_CONSUME_SEGMENT | MLL_WAITING; else return MLL_REWIND_SEGMENT | MLL_EXTRACTED; } else { return MLL_CONSUME_SEGMENT | MLL_WAITING; } } static void test_log_proto_text_server_accumulate_line_can_rewind_lines_if_uninteresting(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_join_continuation_lines, log_transport_mock_new( "0 line\n" " line\n" "2 line\n" " line\n" "3 end\n", -1, LTM_PADDING, LTM_EOF)); assert_proto_server_fetch(proto, "0 line\n line", -1); assert_proto_server_fetch(proto, "2 line\n line", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_accumulate_line_can_rewind_lines_if_uninteresting) { test_log_proto_text_server_accumulate_line_can_rewind_lines_if_uninteresting(log_transport_mock_stream_new); test_log_proto_text_server_accumulate_line_can_rewind_lines_if_uninteresting(log_transport_mock_records_new); } static void test_log_proto_text_server_accumulation_terminated_if_input_is_closed(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_join_continuation_lines, log_transport_mock_new( "0 line\n" " line\n" "1 line\n", -1, LTM_EOF)); assert_proto_server_fetch(proto, "0 line\n line", -1); assert_proto_server_fetch(proto, "1 line", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_accumulation_terminated_if_input_is_closed) { test_log_proto_text_server_accumulation_terminated_if_input_is_closed(log_transport_mock_stream_new); test_log_proto_text_server_accumulation_terminated_if_input_is_closed(log_transport_mock_records_new); } static void test_log_proto_text_server_accumulation_terminated_if_buffer_full(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_join_continuation_lines, log_transport_mock_new( "0123456789abcdef\n" " 0123456789abcdef\n" " continuation\n", -1, LTM_EOF)); assert_proto_server_fetch(proto, "0123456789abcdef\n 0123456789abcd", -1); assert_proto_server_fetch(proto, "ef\n continuation", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_accumulation_terminated_if_buffer_full) { test_log_proto_text_server_accumulation_terminated_if_buffer_full(log_transport_mock_stream_new); test_log_proto_text_server_accumulation_terminated_if_buffer_full(log_transport_mock_records_new); } static gint accumulator_rewind_initial(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { accumulate_seq++; if (accumulate_seq == 1) return MLL_REWIND_SEGMENT | MLL_EXTRACTED; return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } static void test_log_proto_text_server_rewinding_the_initial_line_results_in_an_empty_message(LogTransportMockConstructor log_transport_mock_new) { LogProtoServer *proto; accumulate_seq = 0; proto = construct_test_proto_with_accumulator( accumulator_rewind_initial, log_transport_mock_new( "0 line\n" "1 line\n" "2 line\n", -1, LTM_PADDING, LTM_EOF)); assert_proto_server_fetch(proto, "", -1); assert_proto_server_fetch(proto, "0 line", -1); assert_proto_server_fetch(proto, "1 line", -1); assert_proto_server_fetch(proto, "2 line", -1); log_proto_server_free(proto); } Test(log_proto, test_log_proto_text_server_rewinding_the_initial_line_results_in_an_empty_message) { test_log_proto_text_server_rewinding_the_initial_line_results_in_an_empty_message(log_transport_mock_stream_new); test_log_proto_text_server_rewinding_the_initial_line_results_in_an_empty_message(log_transport_mock_records_new); } Test(log_proto, test_log_proto_text_server_io_eagain) { LogProtoServer *proto; proto = construct_test_proto( log_transport_mock_stream_new( "01234567\n", -1, LTM_INJECT_ERROR(EAGAIN), LTM_EOF)); Bookmark bookmark; LogTransportAuxData aux; gboolean may_read = TRUE; const guchar *msg = NULL; gsize msg_len; log_transport_aux_data_init(&aux); cr_assert_eq(log_proto_server_fetch(proto, &msg, &msg_len, &may_read, &aux, &bookmark), LPS_SUCCESS); cr_assert_eq(log_proto_server_fetch(proto, &msg, &msg_len, &may_read, &aux, &bookmark), LPS_AGAIN); cr_assert_eq(log_proto_server_fetch(proto, &msg, &msg_len, &may_read, &aux, &bookmark), LPS_EOF); log_proto_server_free(proto); } Test(log_proto, buffer_split_with_encoding_and_position_tracking) { GString *data = g_string_new("Lorem ipsum\xe2\x98\x83lor sit amet, consectetur adipiscing elit\n"); GString *data_smaller = g_string_new("muspi merol\n"); gsize bytes_should_not_fit = 5; proto_server_options.max_msg_size = data->len + data_smaller->len - bytes_should_not_fit; proto_server_options.max_buffer_size = proto_server_options.max_msg_size; log_proto_server_options_set_encoding(&proto_server_options, "utf-8"); log_proto_server_options_set_ack_tracker_factory(&proto_server_options, consecutive_ack_tracker_factory_new()); gchar *full_payload = g_strconcat(data_smaller->str, data->str, NULL); LogTransportMock *transport = (LogTransportMock *) log_transport_mock_records_new(full_payload, -1, LTM_EOF); LogProtoServer *proto = log_proto_text_server_new((LogTransport *) transport, get_inited_proto_server_options()); start_grabbing_messages(); assert_proto_server_fetch(proto, data_smaller->str, data_smaller->len - 1); assert_proto_server_fetch(proto, data->str, data->len - 1); stop_grabbing_messages(); cr_assert_not(find_grabbed_message("Internal error")); assert_proto_server_fetch_failure(proto, LPS_EOF, NULL); log_proto_server_free(proto); g_free(full_payload); g_string_free(data_smaller, TRUE); g_string_free(data, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test_findeom.c000066400000000000000000000100031450431004300237460ustar00rootroot00000000000000/* * Copyright (c) 2008-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "logproto/logproto-server.h" #include "logmsg/logmsg.h" #include struct testcase_tuple { gchar *msg; gsize msg_len; gint eom_ofs; }; ParameterizedTestParameters(findeom, test_success) { static struct testcase_tuple params[] = { {"a\nb\nc\n", 6, 1}, {"ab\nb\nc\n", 7, 2}, {"abc\nb\nc\n", 8, 3}, {"abcd\nb\nc\n", 9, 4}, {"abcde\nb\nc\n", 10, 5}, {"abcdef\nb\nc\n", 11, 6}, {"abcdefg\nb\nc\n", 12, 7}, {"abcdefgh\nb\nc\n", 13, 8}, {"abcdefghi\nb\nc\n", 14, 9}, {"abcdefghij\nb\nc\n", 15, 10}, {"abcdefghijk\nb\nc\n", 16, 11}, {"abcdefghijkl\nb\nc\n", 17, 12}, {"abcdefghijklm\nb\nc\n", 18, 13}, {"abcdefghijklmn\nb\nc\n", 19, 14}, {"abcdefghijklmno\nb\nc\n", 20, 15}, {"abcdefghijklmnop\nb\nc\n", 21, 16}, {"abcdefghijklmnopq\nb\nc\n", 22, 17}, {"abcdefghijklmnopqr\nb\nc\n", 23, 18}, {"abcdefghijklmnopqrs\nb\nc\n", 24, 19}, {"abcdefghijklmnopqrst\nb\nc\n", 25, 20}, {"abcdefghijklmnopqrstu\nb\nc\n", 26, 21}, {"abcdefghijklmnopqrstuv\nb\nc\n", 27, 22}, {"abcdefghijklmnopqrstuvw\nb\nc\n", 28, 23}, {"abcdefghijklmnopqrstuvwx\nb\nc\n", 29, 24}, {"abcdefghijklmnopqrstuvwxy\nb\nc\n", 30, 25}, {"abcdefghijklmnopqrstuvwxyz\nb\nc\n", 31, 26}, }; return cr_make_param_array(struct testcase_tuple, params, G_N_ELEMENTS(params)); } ParameterizedTest(struct testcase_tuple *tup, findeom, test_success) { const guchar *eom; const guchar *msg = (const guchar *) tup->msg; eom = find_eom((guchar *) msg, tup-> msg_len); cr_assert(eom - msg == tup->eom_ofs, "EOM is at wrong location. msg=%s, eom_ofs=%d, eom=%s\n", msg, tup->eom_ofs, eom); } ParameterizedTestParameters(findeom, test_failed) { static struct testcase_tuple params[] = { {"a", 1, -1}, {"ab", 2, -1}, {"abc", 3, -1}, {"abcd", 4, -1}, {"abcde", 5, -1}, {"abcdef", 6, -1}, {"abcdefg", 7, -1}, {"abcdefgh", 8, -1}, {"abcdefghi", 9, -1}, {"abcdefghij", 10, -1}, {"abcdefghijk", 11, -1}, {"abcdefghijkl", 12, -1}, {"abcdefghijklm", 13, -1}, {"abcdefghijklmn", 14, -1}, {"abcdefghijklmno", 15, -1}, {"abcdefghijklmnop", 16, -1}, {"abcdefghijklmnopq", 17, -1}, {"abcdefghijklmnopqr", 18, -1}, {"abcdefghijklmnopqrs", 19, -1}, {"abcdefghijklmnopqrst", 20, -1}, {"abcdefghijklmnopqrstu", 21, -1}, {"abcdefghijklmnopqrstuv", 22, -1}, {"abcdefghijklmnopqrstuvw", 23, -1}, {"abcdefghijklmnopqrstuvwx", 24, -1}, {"abcdefghijklmnopqrstuvwxy", 25, -1}, {"abcdefghijklmnopqrstuvwxyz", 26, -1}, }; return cr_make_param_array(struct testcase_tuple, params, G_N_ELEMENTS(params)); } ParameterizedTest(struct testcase_tuple *tup, findeom, test_failed) { const guchar *eom; const guchar *msg = (const guchar *) tup->msg; eom = find_eom((guchar *) msg, tup-> msg_len); cr_assert_null(eom, "EOM returned is not NULL, which was expected. eom_ofs=%d, eom=%s\n", tup->eom_ofs, eom); } syslog-ng-syslog-ng-4.4.0/lib/logproto/tests/test_logproto.c000066400000000000000000000066721450431004300242130ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include "libtest/proto_lib.h" #include "libtest/msg_parse_lib.h" #include "logproto/logproto.h" #include "logproto/logproto-text-server.h" #include "logproto/logproto-framed-server.h" #include "logproto/logproto-dgram-server.h" #include "logproto/logproto-record-server.h" #include "apphook.h" void setup(void) { app_startup(); init_proto_tests(); } void teardown(void) { deinit_proto_tests(); app_shutdown(); } Test(log_proto, test_base) { cr_assert_eq(log_proto_get_char_size_for_fixed_encoding("iso-8859-2"), 1); cr_assert_eq(log_proto_get_char_size_for_fixed_encoding("ucs-4"), 4); log_proto_server_options_set_encoding(&proto_server_options, "ucs-4"); LogProtoServer *proto = log_proto_binary_record_server_new( log_transport_mock_records_new( /* ucs4, terminated by record size */ "\x00\x00\x00\xe1\x00\x00\x00\x72\x00\x00\x00\x76\x00\x00\x00\xed" /* |...á...r...v...í| */ "\x00\x00\x00\x7a\x00\x00\x00\x74\x00\x00\x01\x71\x00\x00\x00\x72", 32, /* |...z...t...ű...r| */ LTM_EOF), get_inited_proto_server_options(), 32); /* check if error state is not forgotten unless reset_error is called */ proto->status = LPS_ERROR; assert_proto_server_status(proto, proto->status, LPS_ERROR); assert_proto_server_fetch_failure(proto, LPS_ERROR, NULL); log_proto_server_reset_error(proto); assert_proto_server_fetch(proto, "árvíztűr", -1); assert_proto_server_status(proto, proto->status, LPS_SUCCESS); log_proto_server_free(proto); } Test(log_proto, test_log_proto, .disabled = true) { /* * Things that are yet to be done: * * log_proto_text_server_new * - apply-state/restart_with_state * - questions: maybe move this to a separate LogProtoFileReader? * - apply state: * - same file, continued: same inode, size grown, * - truncated file: same inode, size smaller * - file starts over, all state data is reset! * - buffer: * - no encoding * - encoding: utf8, ucs4, koi8r * - state version: v1, v2, v3, v4 * - queued * - saddr caching * * log_proto_text_client_new * log_proto_file_writer_new * log_proto_framed_client_new */ } TestSuite(log_proto, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/logqueue-fifo.c000066400000000000000000000550221450431004300210400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logqueue.h" #include "logpipe.h" #include "messages.h" #include "serialize.h" #include "stats/stats-registry.h" #include "mainloop-worker.h" #include #include #include #include #include #include QueueType log_queue_fifo_type = "FIFO"; /* * LogFifo is a scalable first-in-first-output queue implementation, that: * * - has a per-thread, unlocked input queue where threads can put their items * * - has a locked wait-queue where items go once the per-thread input * would be overflown or if the input thread goes to sleep (e.g. one * lock acquisition per a longer period) * * - has an unlocked output queue where items from the wait queue go, once * it becomes depleted. * * This means that items flow in this sequence from one list to the next: * * input queue (per-thread) -> wait queue (locked) -> output queue (single-threaded) * * Fastpath is: * - input threads putting elements on their per-thread queue (lockless) * - output threads removing elements from the output queue (lockless) * * Slowpath: * - input queue is overflown (or the input thread goes to sleep), wait * queue mutex is grabbed, all elements are put to the wait queue. * * - output queue is depleted, wait queue mutex is grabbed, all elements * on the wait queue is put to the output queue * * Threading assumptions: * - the head of the queue is only manipulated from the output thread * - the tail of the queue is only manipulated from the input threads * */ typedef struct _InputQueue { struct iv_list_head items; WorkerBatchCallback cb; guint32 len; guint32 non_flow_controlled_len; guint16 finish_cb_registered; } InputQueue; typedef struct _OverflowQueue { struct iv_list_head items; gint len; gint non_flow_controlled_len; } OverflowQueue; typedef struct _LogQueueFifo { LogQueue super; /* scalable qoverflow implementation */ OverflowQueue output_queue; OverflowQueue wait_queue; OverflowQueue backlog_queue; /* entries that were sent but not acked yet */ gint log_fifo_size; /* legacy: flow-controlled messages are included in the log_fifo_size limit */ gboolean use_legacy_fifo_size; gint num_input_queues; InputQueue input_queues[0]; } LogQueueFifo; /* NOTE: this is inherently racy. If the LogQueue->lock is taken, then the * race is limited to the changes in output_queue queue changes. * * In the output thread, this means that this can get race-free. In the * input thread, the output_queue can change because of a * log_queue_fifo_rewind_backlog(). * */ static void iv_list_update_msg_size(LogQueueFifo *self, struct iv_list_head *head) { LogMessage *msg; struct iv_list_head *ilh, *ilh2; iv_list_for_each_safe(ilh, ilh2, head) { msg = iv_list_entry(ilh, LogMessageQueueNode, list)->msg; log_queue_memory_usage_add(&self->super, log_msg_get_size(msg)); } } static gint64 log_queue_fifo_get_length(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; return self->wait_queue.len + self->output_queue.len; } static gint64 log_queue_fifo_get_non_flow_controlled_length(LogQueueFifo *self) { return self->wait_queue.non_flow_controlled_len + self->output_queue.non_flow_controlled_len; } gboolean log_queue_fifo_is_empty_racy(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; gboolean has_message_in_queue = FALSE; g_mutex_lock(&self->super.lock); if (log_queue_fifo_get_length(s) > 0) { has_message_in_queue = TRUE; } else { gint i; for (i = 0; i < self->num_input_queues && !has_message_in_queue; i++) { has_message_in_queue |= self->input_queues[i].finish_cb_registered; } } g_mutex_unlock(&self->super.lock); return !has_message_in_queue; } /* NOTE: this is inherently racy, can only be called if log processing is suspended (e.g. reload time) */ static gboolean log_queue_fifo_keep_on_reload(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; return log_queue_fifo_get_length(s) > 0 || self->backlog_queue.len > 0; } static inline void log_queue_fifo_drop_messages_from_input_queue(LogQueueFifo *self, InputQueue *input_queue, gint num_of_messages_to_drop) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; struct iv_list_head *item = input_queue->items.next; for (gint dropped = 0; dropped < num_of_messages_to_drop;) { LogMessageQueueNode *node = iv_list_entry(item, LogMessageQueueNode, list); item = item->next; path_options.ack_needed = node->ack_needed; path_options.flow_control_requested = node->flow_control_requested; if (!self->use_legacy_fifo_size && path_options.flow_control_requested) continue; iv_list_del(&node->list); input_queue->len--; log_queue_dropped_messages_inc(&self->super); log_msg_free_queue_node(node); LogMessage *msg = node->msg; if (path_options.flow_control_requested) log_msg_drop(msg, &path_options, AT_SUSPENDED); else { input_queue->non_flow_controlled_len--; log_msg_drop(msg, &path_options, AT_PROCESSED); } dropped++; } msg_debug("Destination queue full, dropping messages", evt_tag_int("log_fifo_size", self->log_fifo_size), evt_tag_int("number_of_dropped_messages", num_of_messages_to_drop), evt_tag_str("persist_name", self->super.persist_name)); } static inline gboolean log_queue_fifo_calculate_num_of_messages_to_drop(LogQueueFifo *self, InputQueue *input_queue, gint *num_of_messages_to_drop) { /* since we're in the input thread, queue_len will be racy. It can * increase due to log_queue_fifo_rewind_backlog() and can also decrease * as items are removed from the output queue using log_queue_pop_head(). * * The only reason we're using it here is to check for qoverflow * overflows, however the only side-effect of the race (if lost) is that * we would lose a couple of message too many or add some more messages to * qoverflow than permitted by the user. Since if flow-control is used, * the fifo size should be sized larger than the potential window sizes, * otherwise we can lose messages anyway, this is not deemed a cost to * justify proper locking in this case. */ guint16 input_queue_len; gint queue_len; if (G_UNLIKELY(self->use_legacy_fifo_size)) { queue_len = log_queue_fifo_get_length(&self->super); input_queue_len = input_queue->len; } else { queue_len = log_queue_fifo_get_non_flow_controlled_length(self); input_queue_len = input_queue->non_flow_controlled_len; } gboolean drop_messages = queue_len + input_queue_len > self->log_fifo_size; if (!drop_messages) return FALSE; /* NOTE: MAX is needed here to ensure that the lost race on queue_len * doesn't result in n < 0 */ *num_of_messages_to_drop = input_queue_len - MAX(0, (self->log_fifo_size - queue_len)); return TRUE; } /* move items from the per-thread input queue to the lock-protected "wait" queue */ static void log_queue_fifo_move_input_unlocked(LogQueueFifo *self, gint thread_index) { gint num_of_messages_to_drop; gboolean drop_messages = log_queue_fifo_calculate_num_of_messages_to_drop(self, &self->input_queues[thread_index], &num_of_messages_to_drop); if (drop_messages) { /* slow path, the input thread's queue would overflow the queue, let's drop some messages */ log_queue_fifo_drop_messages_from_input_queue(self, &self->input_queues[thread_index], num_of_messages_to_drop); } log_queue_queued_messages_add(&self->super, self->input_queues[thread_index].len); iv_list_update_msg_size(self, &self->input_queues[thread_index].items); iv_list_splice_tail_init(&self->input_queues[thread_index].items, &self->wait_queue.items); self->wait_queue.len += self->input_queues[thread_index].len; self->wait_queue.non_flow_controlled_len += self->input_queues[thread_index].non_flow_controlled_len; self->input_queues[thread_index].len = 0; self->input_queues[thread_index].non_flow_controlled_len = 0; } /* move items from the per-thread input queue to the lock-protected * "wait" queue, but grabbing locks first. This is registered as a * callback to be called when the input worker thread finishes its * job. */ static gpointer log_queue_fifo_move_input(gpointer user_data) { LogQueueFifo *self = (LogQueueFifo *) user_data; gint thread_index; thread_index = main_loop_worker_get_thread_index(); g_assert(thread_index >= 0); g_mutex_lock(&self->super.lock); log_queue_fifo_move_input_unlocked(self, thread_index); log_queue_push_notify(&self->super); g_mutex_unlock(&self->super.lock); self->input_queues[thread_index].finish_cb_registered = FALSE; log_queue_unref(&self->super); return NULL; } /* lock must be held */ static inline gboolean _message_has_to_be_dropped(LogQueueFifo *self, const LogPathOptions *path_options) { if (G_UNLIKELY(self->use_legacy_fifo_size)) return log_queue_fifo_get_length(&self->super) >= self->log_fifo_size; return !path_options->flow_control_requested && log_queue_fifo_get_non_flow_controlled_length(self) >= self->log_fifo_size; } static inline void _drop_message(LogMessage *msg, const LogPathOptions *path_options) { if (path_options->flow_control_requested) { log_msg_drop(msg, path_options, AT_SUSPENDED); return; } log_msg_drop(msg, path_options, AT_PROCESSED); } /** * Assumed to be called from one of the input threads. If the thread_index * cannot be determined, the item is put directly in the wait queue. * * Puts the message to the queue, and logs an error if it caused the * queue to be full. * * It attempts to put the item to the per-thread input queue. * * NOTE: It consumes the reference passed by the caller. **/ static void log_queue_fifo_push_tail(LogQueue *s, LogMessage *msg, const LogPathOptions *path_options) { LogQueueFifo *self = (LogQueueFifo *) s; gint thread_index; LogMessageQueueNode *node; thread_index = main_loop_worker_get_thread_index(); /* if this thread has an ID than the number of input queues we have (due * to a config change), handle the load via the slow path */ if (thread_index >= self->num_input_queues) thread_index = -1; /* NOTE: we don't use high-water marks for now, as log_fetch_limit * limits the number of items placed on the per-thread input queue * anyway, and any sane number decreased the performance measurably. * * This means that per-thread input queues contain _all_ items that * a single poll iteration produces. And once the reader is finished * (either because the input is depleted or because of * log_fetch_limit / window_size) the whole bunch is propagated to * the "wait" queue. */ if (thread_index >= 0) { /* fastpath, use per-thread input FIFOs */ if (!self->input_queues[thread_index].finish_cb_registered) { /* this is the first item in the input FIFO, register a finish * callback to make sure it gets moved to the wait_queue if the * input thread finishes * One reference should be held, while the callback is registered * avoiding use-after-free situation */ main_loop_worker_register_batch_callback(&self->input_queues[thread_index].cb); self->input_queues[thread_index].finish_cb_registered = TRUE; log_queue_ref(&self->super); } log_msg_write_protect(msg); node = log_msg_alloc_queue_node(msg, path_options); iv_list_add_tail(&node->list, &self->input_queues[thread_index].items); self->input_queues[thread_index].len++; if (!path_options->flow_control_requested) self->input_queues[thread_index].non_flow_controlled_len++; log_msg_unref(msg); return; } /* slow path, put the pending item and the whole input queue to the wait_queue */ g_mutex_lock(&self->super.lock); if (_message_has_to_be_dropped(self, path_options)) { log_queue_dropped_messages_inc(&self->super); g_mutex_unlock(&self->super.lock); _drop_message(msg, path_options); msg_debug("Destination queue full, dropping message", evt_tag_int("queue_len", log_queue_fifo_get_length(&self->super)), evt_tag_int("log_fifo_size", self->log_fifo_size), evt_tag_str("persist_name", self->super.persist_name)); return; } log_msg_write_protect(msg); node = log_msg_alloc_queue_node(msg, path_options); iv_list_add_tail(&node->list, &self->wait_queue.items); self->wait_queue.len++; if (!path_options->flow_control_requested) self->wait_queue.non_flow_controlled_len++; log_queue_push_notify(&self->super); log_queue_queued_messages_inc(&self->super); log_queue_memory_usage_add(&self->super, log_msg_get_size(msg)); g_mutex_unlock(&self->super.lock); log_msg_unref(msg); } /* * Can only run from the output thread. */ static inline void _move_items_from_wait_queue_to_output_queue(LogQueueFifo *self) { /* slow path, output queue is empty, get some elements from the wait queue */ g_mutex_lock(&self->super.lock); iv_list_splice_tail_init(&self->wait_queue.items, &self->output_queue.items); self->output_queue.len = self->wait_queue.len; self->output_queue.non_flow_controlled_len = self->wait_queue.non_flow_controlled_len; self->wait_queue.len = 0; self->wait_queue.non_flow_controlled_len = 0; g_mutex_unlock(&self->super.lock); } /* * Can only run from the output thread. */ static LogMessage * log_queue_fifo_peek_head(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; LogMessageQueueNode *node; LogMessage *msg = NULL; if (self->output_queue.len == 0) _move_items_from_wait_queue_to_output_queue(self); if (self->output_queue.len == 0) return NULL; node = iv_list_entry(self->output_queue.items.next, LogMessageQueueNode, list); msg = node->msg; return msg; } /* * Can only run from the output thread. * * NOTE: this returns a reference which the caller must take care to free. */ static LogMessage * log_queue_fifo_pop_head(LogQueue *s, LogPathOptions *path_options) { LogQueueFifo *self = (LogQueueFifo *) s; LogMessageQueueNode *node; LogMessage *msg = NULL; if (self->output_queue.len == 0) _move_items_from_wait_queue_to_output_queue(self); if (self->output_queue.len > 0) { node = iv_list_entry(self->output_queue.items.next, LogMessageQueueNode, list); msg = node->msg; path_options->ack_needed = node->ack_needed; self->output_queue.len--; if (!node->flow_control_requested) self->output_queue.non_flow_controlled_len--; iv_list_del_init(&node->list); } else { /* no items either on the wait queue nor the output queue. * * NOTE: the input queues may contain items even in this case, * however we don't touch them here, they'll be migrated to the * wait_queue once the input threads finish their processing (or * the high watermark is reached). Also, they are unlocked, so * no way to touch them safely. */ return NULL; } log_queue_queued_messages_dec(&self->super); log_queue_memory_usage_sub(&self->super, log_msg_get_size(msg)); /* push to backlog */ log_msg_ref(msg); iv_list_add_tail(&node->list, &self->backlog_queue.items); self->backlog_queue.len++; if (!node->flow_control_requested) self->backlog_queue.non_flow_controlled_len++; return msg; } /* * Can only run from the output thread. */ static void log_queue_fifo_ack_backlog(LogQueue *s, gint rewind_count) { LogQueueFifo *self = (LogQueueFifo *) s; LogMessage *msg; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; gint pos; for (pos = 0; pos < rewind_count && self->backlog_queue.len > 0; pos++) { LogMessageQueueNode *node; node = iv_list_entry(self->backlog_queue.items.next, LogMessageQueueNode, list); msg = node->msg; iv_list_del(&node->list); self->backlog_queue.len--; if (!node->flow_control_requested) self->backlog_queue.non_flow_controlled_len--; path_options.ack_needed = node->ack_needed; log_msg_ack(msg, &path_options, AT_PROCESSED); log_msg_free_queue_node(node); log_msg_unref(msg); } } /* * log_queue_rewind_backlog_all: * * Move items on our backlog back to our qoverflow queue. Please note that this * function does not really care about qoverflow size, it has to put the backlog * somewhere. The backlog is emptied as that will be filled if we send the * items again. * * NOTE: this is assumed to be called from the output thread. */ static void log_queue_fifo_rewind_backlog_all(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; iv_list_update_msg_size(self, &self->backlog_queue.items); iv_list_splice_tail_init(&self->backlog_queue.items, &self->output_queue.items); self->output_queue.len += self->backlog_queue.len; self->output_queue.non_flow_controlled_len += self->backlog_queue.non_flow_controlled_len; log_queue_queued_messages_add(&self->super, self->backlog_queue.len); self->backlog_queue.len = 0; self->backlog_queue.non_flow_controlled_len = 0; } static void log_queue_fifo_rewind_backlog(LogQueue *s, guint rewind_count) { LogQueueFifo *self = (LogQueueFifo *) s; guint pos; if (rewind_count > self->backlog_queue.len) rewind_count = self->backlog_queue.len; for (pos = 0; pos < rewind_count; pos++) { LogMessageQueueNode *node = iv_list_entry(self->backlog_queue.items.prev, LogMessageQueueNode, list); /* * Because the message go to the backlog only in case of pop_head * and pop_head add ack and ref when it pushes the message into the backlog * The rewind must decrease the ack and ref too */ iv_list_del_init(&node->list); iv_list_add(&node->list, &self->output_queue.items); self->backlog_queue.len--; self->output_queue.len++; if (!node->flow_control_requested) { self->backlog_queue.non_flow_controlled_len--; self->output_queue.non_flow_controlled_len++; } log_queue_queued_messages_inc(&self->super); log_queue_memory_usage_add(&self->super, log_msg_get_size(node->msg)); } } static void log_queue_fifo_free_queue(struct iv_list_head *q) { while (!iv_list_empty(q)) { LogMessageQueueNode *node; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *msg; node = iv_list_entry(q->next, LogMessageQueueNode, list); iv_list_del(&node->list); path_options.ack_needed = node->ack_needed; msg = node->msg; log_msg_free_queue_node(node); log_msg_ack(msg, &path_options, AT_ABORTED); log_msg_unref(msg); } } static void log_queue_fifo_free(LogQueue *s) { LogQueueFifo *self = (LogQueueFifo *) s; gint i; for (i = 0; i < self->num_input_queues; i++) { g_assert(self->input_queues[i].finish_cb_registered == FALSE); log_queue_fifo_free_queue(&self->input_queues[i].items); } log_queue_fifo_free_queue(&self->wait_queue.items); log_queue_fifo_free_queue(&self->output_queue.items); log_queue_fifo_free_queue(&self->backlog_queue.items); log_queue_free_method(s); } LogQueue * log_queue_fifo_new(gint log_fifo_size, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { LogQueueFifo *self; gint max_threads = main_loop_worker_get_max_number_of_threads(); self = g_malloc0(sizeof(LogQueueFifo) + max_threads * sizeof(self->input_queues[0])); if (queue_sck_builder) { stats_cluster_key_builder_push(queue_sck_builder); stats_cluster_key_builder_set_name_prefix(queue_sck_builder, "memory_queue_"); } log_queue_init_instance(&self->super, persist_name, stats_level, driver_sck_builder, queue_sck_builder); self->super.type = log_queue_fifo_type; self->super.get_length = log_queue_fifo_get_length; self->super.is_empty_racy = log_queue_fifo_is_empty_racy; self->super.keep_on_reload = log_queue_fifo_keep_on_reload; self->super.push_tail = log_queue_fifo_push_tail; self->super.pop_head = log_queue_fifo_pop_head; self->super.peek_head = log_queue_fifo_peek_head; self->super.ack_backlog = log_queue_fifo_ack_backlog; self->super.rewind_backlog = log_queue_fifo_rewind_backlog; self->super.rewind_backlog_all = log_queue_fifo_rewind_backlog_all; self->super.free_fn = log_queue_fifo_free; self->num_input_queues = max_threads; for (gint i = 0; i < self->num_input_queues; i++) { INIT_IV_LIST_HEAD(&self->input_queues[i].items); worker_batch_callback_init(&self->input_queues[i].cb); self->input_queues[i].cb.func = log_queue_fifo_move_input; self->input_queues[i].cb.user_data = self; } INIT_IV_LIST_HEAD(&self->wait_queue.items); INIT_IV_LIST_HEAD(&self->output_queue.items); INIT_IV_LIST_HEAD(&self->backlog_queue.items); self->log_fifo_size = log_fifo_size; if (queue_sck_builder) stats_cluster_key_builder_pop(queue_sck_builder); return &self->super; } LogQueue * log_queue_fifo_legacy_new(gint log_fifo_size, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { LogQueueFifo *self = (LogQueueFifo *) log_queue_fifo_new(log_fifo_size, persist_name, stats_level, driver_sck_builder, queue_sck_builder); self->use_legacy_fifo_size = TRUE; return &self->super; } QueueType log_queue_fifo_get_type(void) { return log_queue_fifo_type; } syslog-ng-syslog-ng-4.4.0/lib/logqueue-fifo.h000066400000000000000000000031561450431004300210460ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGQUEUE_FIFO_H_INCLUDED #define LOGQUEUE_FIFO_H_INCLUDED #include "logqueue.h" LogQueue *log_queue_fifo_new(gint log_fifo_size, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder); LogQueue *log_queue_fifo_legacy_new(gint log_fifo_size, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder); QueueType log_queue_fifo_get_type(void); #endif syslog-ng-syslog-ng-4.4.0/lib/logqueue.c000066400000000000000000000311021450431004300201100ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logqueue.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "messages.h" #include "timeutils/misc.h" void log_queue_memory_usage_add(LogQueue *self, gsize value) { stats_counter_add(self->metrics.shared.memory_usage, value); stats_counter_add(self->metrics.owned.memory_usage, value); } void log_queue_memory_usage_sub(LogQueue *self, gsize value) { stats_counter_sub(self->metrics.shared.memory_usage, value); stats_counter_sub(self->metrics.owned.memory_usage, value); } void log_queue_queued_messages_add(LogQueue *self, gsize value) { stats_counter_add(self->metrics.shared.queued_messages, value); stats_counter_add(self->metrics.owned.queued_messages, value); } void log_queue_queued_messages_sub(LogQueue *self, gsize value) { stats_counter_sub(self->metrics.shared.queued_messages, value); stats_counter_sub(self->metrics.owned.queued_messages, value); } void log_queue_queued_messages_inc(LogQueue *self) { stats_counter_inc(self->metrics.shared.queued_messages); stats_counter_inc(self->metrics.owned.queued_messages); } void log_queue_queued_messages_dec(LogQueue *self) { stats_counter_dec(self->metrics.shared.queued_messages); stats_counter_dec(self->metrics.owned.queued_messages); } void log_queue_queued_messages_reset(LogQueue *self) { stats_counter_sub(self->metrics.shared.queued_messages, stats_counter_get(self->metrics.owned.queued_messages)); stats_counter_set(self->metrics.owned.queued_messages, log_queue_get_length(self)); stats_counter_add(self->metrics.shared.queued_messages, stats_counter_get(self->metrics.owned.queued_messages)); } void log_queue_dropped_messages_inc(LogQueue *self) { stats_counter_inc(self->metrics.shared.dropped_messages); } /* * When this is called, it is assumed that the output thread is currently * not running (since this is the function that wakes it up), thus we can * access the length of the output queue without acquiring a lock. Memory * barriers are covered by the use of the self->lock mutex, since * push_notify is registered under the protection of self->lock and after * that the length of the output queue will not change (since parallel_push * is only registered if it has less than enough items). * * NOTE: self->lock must have been acquired before calling this function. */ void log_queue_push_notify(LogQueue *self) { if (self->parallel_push_notify) { /* make sure the callback can call log_queue_check_items() again */ GDestroyNotify destroy = self->parallel_push_data_destroy; gpointer user_data = self->parallel_push_data; LogQueuePushNotifyFunc func = self->parallel_push_notify; self->parallel_push_data = NULL; self->parallel_push_data_destroy = NULL; self->parallel_push_notify = NULL; g_mutex_unlock(&self->lock); func(user_data); if (destroy && user_data) destroy(user_data); g_mutex_lock(&self->lock); } } void log_queue_reset_parallel_push(LogQueue *self) { g_mutex_lock(&self->lock); self->parallel_push_notify = NULL; self->parallel_push_data = NULL; g_mutex_unlock(&self->lock); } void log_queue_set_parallel_push(LogQueue *self, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy) { g_mutex_lock(&self->lock); self->parallel_push_notify = parallel_push_notify; self->parallel_push_data = user_data; self->parallel_push_data_destroy = user_data_destroy; g_mutex_unlock(&self->lock); } /* * * @batch_items: the number of items processed in a batch (e.g. the number of items the consumer is preferred to process at a single invocation) * @partial_batch: true is returned if some elements (but less than batch_items) are already buffered * @timeout: the number of milliseconds that the consumer needs to wait before we can possibly proceed */ gboolean log_queue_check_items(LogQueue *self, gint *timeout, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy) { gint64 num_elements; g_mutex_lock(&self->lock); /* drop reference to the previous callback/userdata */ if (self->parallel_push_data && self->parallel_push_data_destroy) self->parallel_push_data_destroy(self->parallel_push_data); num_elements = log_queue_get_length(self); if (num_elements == 0) { self->parallel_push_notify = parallel_push_notify; self->parallel_push_data = user_data; self->parallel_push_data_destroy = user_data_destroy; g_mutex_unlock(&self->lock); return FALSE; } /* consume the user_data reference as we won't use the callback */ if (user_data && user_data_destroy) user_data_destroy(user_data); self->parallel_push_notify = NULL; self->parallel_push_data = NULL; g_mutex_unlock(&self->lock); /* recalculate buckets, throttle is only running in the output thread, no need to lock it. */ if (self->throttle > 0) { gint64 diff; gint new_buckets; GTimeVal now; g_get_current_time(&now); /* throttling is enabled, calculate new buckets */ if (self->last_throttle_check.tv_sec != 0) { diff = g_time_val_diff(&now, &self->last_throttle_check); } else { diff = 0; self->last_throttle_check = now; } new_buckets = (self->throttle * diff) / G_USEC_PER_SEC; if (new_buckets) { /* if new_buckets is zero, we don't save the current time as * last_throttle_check. The reason is that new_buckets could be * rounded to zero when only a minimal interval passes between * poll iterations. */ self->throttle_buckets = MIN(self->throttle, self->throttle_buckets + new_buckets); self->last_throttle_check = now; } if (num_elements && self->throttle_buckets == 0) { if (timeout) { /* we are unable to send because of throttling, make sure that we * wake up when the rate limits lets us send at least 1 message */ *timeout = (1000 / self->throttle) + 1; msg_debug("Throttling output", evt_tag_int("wait", *timeout)); } return FALSE; } } return TRUE; } static void _register_shared_counters(LogQueue *self, gint stats_level, StatsClusterKeyBuilder *builder) { if (!builder) return; stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_name(builder, "output_events_total"); self->metrics.shared.output_events_sc_key = stats_cluster_key_builder_build_logpipe(builder); } stats_cluster_key_builder_pop(builder); stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_legacy_alias(builder, self->metrics.shared.output_events_sc_key->legacy.component, self->metrics.shared.output_events_sc_key->legacy.id, self->metrics.shared.output_events_sc_key->legacy.instance); stats_cluster_key_builder_set_legacy_alias_name(builder, "memory_usage"); self->metrics.shared.memory_usage_sc_key = stats_cluster_key_builder_build_single(builder); } stats_cluster_key_builder_pop(builder); stats_lock(); { stats_register_counter(stats_level, self->metrics.shared.output_events_sc_key, SC_TYPE_QUEUED, &self->metrics.shared.queued_messages); stats_register_counter(stats_level, self->metrics.shared.output_events_sc_key, SC_TYPE_DROPPED, &self->metrics.shared.dropped_messages); stats_register_counter_and_index(stats_level, self->metrics.shared.memory_usage_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.shared.memory_usage); } stats_unlock(); } static void _register_owned_counters(LogQueue *self, gint stats_level, StatsClusterKeyBuilder *builder) { if (!builder) return; stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_name(builder, "events"); self->metrics.owned.events_sc_key = stats_cluster_key_builder_build_single(builder); stats_cluster_key_builder_set_name(builder, "memory_usage_bytes"); self->metrics.owned.memory_usage_sc_key = stats_cluster_key_builder_build_single(builder); } stats_cluster_key_builder_pop(builder); stats_lock(); { stats_register_counter(stats_level, self->metrics.owned.events_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.owned.queued_messages); stats_register_counter(stats_level, self->metrics.owned.memory_usage_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.owned.memory_usage); } stats_unlock(); } static void _register_counters(LogQueue *self, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { g_assert(!driver_sck_builder || queue_sck_builder); _register_shared_counters(self, stats_level, driver_sck_builder); _register_owned_counters(self, stats_level, queue_sck_builder); } static void _unregister_shared_counters(LogQueue *self) { stats_lock(); { if (self->metrics.shared.output_events_sc_key) { log_queue_queued_messages_sub(self, stats_counter_get(self->metrics.owned.queued_messages)); stats_unregister_counter(self->metrics.shared.output_events_sc_key, SC_TYPE_QUEUED, &self->metrics.shared.queued_messages); stats_unregister_counter(self->metrics.shared.output_events_sc_key, SC_TYPE_DROPPED, &self->metrics.shared.dropped_messages); stats_cluster_key_free(self->metrics.shared.output_events_sc_key); } if (self->metrics.shared.memory_usage_sc_key) { log_queue_memory_usage_sub(self, stats_counter_get(self->metrics.owned.memory_usage)); stats_unregister_counter(self->metrics.shared.memory_usage_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.shared.memory_usage); stats_cluster_key_free(self->metrics.shared.memory_usage_sc_key); } } stats_unlock(); } static void _unregister_owned_counters(LogQueue *self) { stats_lock(); { if (self->metrics.owned.events_sc_key) { stats_unregister_counter(self->metrics.owned.events_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.owned.queued_messages); stats_cluster_key_free(self->metrics.owned.events_sc_key); } if (self->metrics.owned.memory_usage_sc_key) { stats_unregister_counter(self->metrics.owned.memory_usage_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.owned.memory_usage); stats_cluster_key_free(self->metrics.owned.memory_usage_sc_key); } } stats_unlock(); } static void _unregister_counters(LogQueue *self) { _unregister_shared_counters(self); _unregister_owned_counters(self); } void log_queue_init_instance(LogQueue *self, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder) { g_atomic_counter_set(&self->ref_cnt, 1); self->free_fn = log_queue_free_method; self->persist_name = persist_name ? g_strdup(persist_name) : NULL; g_mutex_init(&self->lock); _register_counters(self, stats_level, driver_sck_builder, queue_sck_builder); } void log_queue_free_method(LogQueue *self) { _unregister_counters(self); g_mutex_clear(&self->lock); g_free(self->persist_name); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/logqueue.h000066400000000000000000000137461450431004300201330ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGQUEUE_H_INCLUDED #define LOGQUEUE_H_INCLUDED #include "logmsg/logmsg.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-key-builder.h" typedef void (*LogQueuePushNotifyFunc)(gpointer user_data); typedef struct _LogQueue LogQueue; typedef const char *QueueType; typedef struct _LogQueueMetrics { struct { StatsClusterKey *output_events_sc_key; StatsClusterKey *memory_usage_sc_key; StatsCounterItem *queued_messages; StatsCounterItem *dropped_messages; StatsCounterItem *memory_usage; } shared; struct { StatsClusterKey *events_sc_key; StatsClusterKey *memory_usage_sc_key; StatsCounterItem *memory_usage; StatsCounterItem *queued_messages; } owned; } LogQueueMetrics; struct _LogQueue { QueueType type; GAtomicCounter ref_cnt; gint throttle; gint throttle_buckets; GTimeVal last_throttle_check; gchar *persist_name; LogQueueMetrics metrics; GMutex lock; LogQueuePushNotifyFunc parallel_push_notify; gpointer parallel_push_data; GDestroyNotify parallel_push_data_destroy; /* queue management */ gboolean (*keep_on_reload)(LogQueue *self); gint64 (*get_length)(LogQueue *self); gboolean (*is_empty_racy)(LogQueue *self); void (*push_tail)(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options); LogMessage *(*pop_head)(LogQueue *self, LogPathOptions *path_options); LogMessage *(*peek_head)(LogQueue *self); void (*ack_backlog)(LogQueue *self, gint n); void (*rewind_backlog)(LogQueue *self, guint rewind_count); void (*rewind_backlog_all)(LogQueue *self); void (*free_fn)(LogQueue *self); }; static inline gboolean log_queue_keep_on_reload(LogQueue *self) { if (self->keep_on_reload) return self->keep_on_reload(self); return TRUE; } static inline gint64 log_queue_get_length(LogQueue *self) { return self->get_length(self); } static inline gboolean log_queue_is_empty_racy(LogQueue *self) { if (self->is_empty_racy) return self->is_empty_racy(self); else return (self->get_length(self) == 0); } static inline void log_queue_push_tail(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options) { self->push_tail(self, msg, path_options); } static inline LogMessage * log_queue_pop_head(LogQueue *self, LogPathOptions *path_options) { LogMessage *msg = NULL; if (self->throttle && self->throttle_buckets == 0) return NULL; msg = self->pop_head(self, path_options); if (msg && self->throttle_buckets > 0) self->throttle_buckets--; return msg; } static inline LogMessage * log_queue_peek_head(LogQueue *self) { return self->peek_head(self); } static inline LogMessage * log_queue_pop_head_ignore_throttle(LogQueue *self, LogPathOptions *path_options) { return self->pop_head(self, path_options); } static inline void log_queue_rewind_backlog(LogQueue *self, guint rewind_count) { self->rewind_backlog(self, rewind_count); } static inline void log_queue_rewind_backlog_all(LogQueue *self) { self->rewind_backlog_all(self); } static inline void log_queue_ack_backlog(LogQueue *self, guint rewind_count) { self->ack_backlog(self, rewind_count); } static inline LogQueue * log_queue_ref(LogQueue *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } static inline void log_queue_unref(LogQueue *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self && g_atomic_counter_dec_and_test(&self->ref_cnt)) { if (self->free_fn) self->free_fn(self); } } static inline void log_queue_set_throttle(LogQueue *self, gint throttle) { self->throttle = throttle; self->throttle_buckets = throttle; } static inline gboolean log_queue_has_type(LogQueue *self, QueueType type) { return g_strcmp0(self->type, type) == 0; } void log_queue_memory_usage_add(LogQueue *self, gsize value); void log_queue_memory_usage_sub(LogQueue *self, gsize value); void log_queue_queued_messages_add(LogQueue *self, gsize value); void log_queue_queued_messages_sub(LogQueue *self, gsize value); void log_queue_queued_messages_inc(LogQueue *self); void log_queue_queued_messages_dec(LogQueue *self); void log_queue_queued_messages_reset(LogQueue *self); void log_queue_dropped_messages_inc(LogQueue *self); void log_queue_push_notify(LogQueue *self); void log_queue_reset_parallel_push(LogQueue *self); void log_queue_set_parallel_push(LogQueue *self, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy); gboolean log_queue_check_items(LogQueue *self, gint *timeout, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy); void log_queue_init_instance(LogQueue *self, const gchar *persist_name, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder, StatsClusterKeyBuilder *queue_sck_builder); void log_queue_free_method(LogQueue *self); #endif syslog-ng-syslog-ng-4.4.0/lib/logreader.c000066400000000000000000000624631450431004300202440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logreader.h" #include "stats/stats-cluster-single.h" #include "mainloop-call.h" #include "ack-tracker/ack_tracker.h" #include "ack-tracker/ack_tracker_factory.h" static void log_reader_io_handle_in(gpointer s); static gboolean log_reader_fetch_log(LogReader *self); static void log_reader_update_watches(LogReader *self); /***************************************************************************** * LogReader setters *****************************************************************************/ void log_reader_set_peer_addr(LogReader *s, GSockAddr *peer_addr) { LogReader *self = (LogReader *) s; g_sockaddr_unref(self->peer_addr); self->peer_addr = g_sockaddr_ref(peer_addr); } void log_reader_set_local_addr(LogReader *s, GSockAddr *local_addr) { LogReader *self = (LogReader *) s; g_sockaddr_unref(self->local_addr); self->local_addr = g_sockaddr_ref(local_addr); } void log_reader_set_immediate_check(LogReader *s) { LogReader *self = (LogReader *) s; self->immediate_check = TRUE; } void log_reader_set_options(LogReader *s, LogPipe *control, LogReaderOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb) { LogReader *self = (LogReader *) s; /* log_reader_reopen() needs to be called prior to set_options. This is * an ugly hack, but at least it is more explicitly than what used to be * here, which silently ignored if self->proto was NULL. */ g_assert(self->proto != NULL); log_source_set_options(&self->super, &options->super, stats_id, kb, (options->flags & LR_THREADED), control->expr_node); AckTrackerFactory *factory = log_proto_server_get_ack_tracker_factory(self->proto); log_source_set_ack_tracker_factory(&self->super, ack_tracker_factory_ref(factory)); log_pipe_unref(self->control); self->control = log_pipe_ref(control); self->options = options; log_proto_server_set_options(self->proto, &self->options->proto_options.super); } void log_reader_set_name(LogReader *self, const gchar *name) { log_source_set_name(&self->super, name); } void log_reader_disable_bookmark_saving(LogReader *s) { log_source_disable_bookmark_saving(&s->super); } /**************************************************************************** * Watches: the poll_events instance and the idle timer ***************************************************************************/ static void log_reader_idle_timeout(void *cookie) { LogReader *self = (LogReader *) cookie; g_assert(!self->io_job.working); msg_notice("Source timeout has elapsed, closing connection", evt_tag_int("fd", log_proto_server_get_fd(self->proto))); log_pipe_notify(self->control, NC_CLOSE, self); } static void log_reader_stop_idle_timer(LogReader *self) { if (iv_timer_registered(&self->idle_timer)) iv_timer_unregister(&self->idle_timer); } static void log_reader_start_watches(LogReader *self) { g_assert(!self->watches_running); if (self->poll_events) poll_events_start_watches(self->poll_events); self->watches_running = TRUE; log_reader_update_watches(self); } static void log_reader_stop_watches(LogReader *self) { g_assert(self->watches_running); if (self->poll_events) poll_events_stop_watches(self->poll_events); log_reader_stop_idle_timer(self); self->watches_running = FALSE; } static void log_reader_disable_watches(LogReader *self) { g_assert(self->watches_running); if (self->poll_events) poll_events_suspend_watches(self->poll_events); log_reader_stop_idle_timer(self); } /**************************************************************************** * Suspend/wakeup ****************************************************************************/ static void log_reader_suspend_until_awoken(LogReader *self) { self->immediate_check = FALSE; log_reader_disable_watches(self); self->suspended = TRUE; } static void log_reader_force_check_in_next_poll(LogReader *self) { self->immediate_check = FALSE; log_reader_disable_watches(self); self->suspended = FALSE; if (!iv_task_registered(&self->restart_task)) { iv_task_register(&self->restart_task); } } static void log_reader_wakeup_triggered(gpointer s) { LogReader *self = (LogReader *) s; if (!self->io_job.working && self->suspended) { /* NOTE: by the time working is set to FALSE we're over an * update_watches call. So it is called either here (when * work_finished has done its work) or from work_finished above. The * two are not racing as both run in the main thread */ log_reader_update_watches(self); } } /* NOTE: may be running in the destination's thread, thus proper locking must be used */ static void log_reader_wakeup(LogSource *s) { LogReader *self = (LogReader *) s; /* * We might get called even after this LogReader has been * deinitialized, in which case we must not do anything (since the * iv_event triggered here is not registered). * * This happens when log_writer_deinit() flushes its output queue * after the reader which produced the message has already been * deinited. Since init/deinit calls are made in the main thread, no * locking is needed. * */ if (self->super.super.flags & PIF_INITIALIZED) iv_event_post(&self->schedule_wakeup); } /**************************************************************************** * Open/close/reopen ***************************************************************************/ static void log_reader_apply_proto_and_poll_events(LogReader *self, LogProtoServer *proto, PollEvents *poll_events) { if (self->proto) log_proto_server_free(self->proto); if (self->poll_events) poll_events_free(self->poll_events); self->proto = proto; if (self->proto) log_proto_server_set_wakeup_cb(self->proto, (LogProtoServerWakeupFunc) log_reader_wakeup, self); self->poll_events = poll_events; } /* run in the main thread in reaction to a log_reader_reopen to change * the source LogProtoServer instance. It needs to be ran in the main * thread as it reregisters the watches associated with the main * thread. */ void log_reader_close_proto_deferred(gpointer s) { LogReader *self = (LogReader *) s; if (self->io_job.working) { self->pending_close = TRUE; return; } log_reader_stop_watches(self); log_reader_apply_proto_and_poll_events(self, NULL, NULL); log_reader_start_watches(self); } void log_reader_close_proto(LogReader *self) { g_assert(self->watches_running); main_loop_call((MainLoopTaskFunc) log_reader_close_proto_deferred, self, TRUE); if (!main_loop_is_main_thread()) { g_mutex_lock(&self->pending_close_lock); while (self->pending_close) { g_cond_wait(&self->pending_close_cond, &self->pending_close_lock); } g_mutex_unlock(&self->pending_close_lock); } } void log_reader_open(LogReader *self, LogProtoServer *proto, PollEvents *poll_events) { g_assert(!self->watches_running); poll_events_set_callback(poll_events, log_reader_io_handle_in, self); log_reader_apply_proto_and_poll_events(self, proto, poll_events); } static gboolean log_reader_is_opened(LogReader *self) { return self->proto && self->poll_events; } /***************************************************************************** * Set watches state so we are polling the event(s) that comes next. *****************************************************************************/ static void log_reader_update_watches(LogReader *self) { GIOCondition cond; gint idle_timeout = -1; main_loop_assert_main_thread(); g_assert(self->watches_running); log_reader_disable_watches(self); if (!log_reader_is_opened(self)) return; gboolean free_to_send = log_source_free_to_send(&self->super); if (!free_to_send) { log_reader_suspend_until_awoken(self); return; } LogProtoPrepareAction prepare_action = log_proto_server_prepare(self->proto, &cond, &idle_timeout); if (idle_timeout > 0) { iv_validate_now(); self->idle_timer.expires = iv_now; self->idle_timer.expires.tv_sec += idle_timeout; iv_timer_register(&self->idle_timer); } if (self->immediate_check) { log_reader_force_check_in_next_poll(self); return; } switch (prepare_action) { case LPPA_POLL_IO: poll_events_update_watches(self->poll_events, cond); break; case LPPA_FORCE_SCHEDULE_FETCH: log_reader_force_check_in_next_poll(self); break; case LPPA_SUSPEND: log_reader_suspend_until_awoken(self); break; default: g_assert_not_reached(); break; } } /***************************************************************************** * Glue into MainLoopIOWorker *****************************************************************************/ static void log_reader_work_perform(void *s, gpointer arg) { LogReader *self = (LogReader *) s; self->notify_code = log_reader_fetch_log(self); } static void log_reader_work_finished(void *s, gpointer arg) { LogReader *self = (LogReader *) s; if (self->pending_close) { /* pending proto is only set in the main thread, so no need to * lock it before coming here. After we're syncing with the * log_writer_reopen() call, quite possibly coming from a * non-main thread. */ g_mutex_lock(&self->pending_close_lock); log_reader_apply_proto_and_poll_events(self, NULL, NULL); self->pending_close = FALSE; g_cond_signal(&self->pending_close_cond); g_mutex_unlock(&self->pending_close_lock); } if (self->notify_code) { gint notify_code = self->notify_code; self->notify_code = 0; log_pipe_notify(self->control, notify_code, self); } if (self->super.super.flags & PIF_INITIALIZED) { /* reenable polling the source assuming that we're still in * business (e.g. the reader hasn't been uninitialized) */ if (self->realloc_window_after_fetch) { self->realloc_window_after_fetch = FALSE; log_source_dynamic_window_realloc(s); } log_proto_server_reset_error(self->proto); log_reader_update_watches(self); } } /***************************************************************************** * Input processing, the main function of LogReader *****************************************************************************/ static void _add_aux_nvpair(const gchar *name, const gchar *value, gsize value_len, gpointer user_data) { LogMessage *msg = (LogMessage *) user_data; log_msg_set_value_by_name(msg, name, value, value_len);; } static inline gint log_reader_process_handshake(LogReader *self) { LogProtoStatus status = log_proto_server_handshake(self->proto); switch (status) { case LPS_EOF: case LPS_ERROR: return status == LPS_ERROR ? NC_READ_ERROR : NC_CLOSE; case LPS_SUCCESS: break; case LPS_AGAIN: break; default: g_assert_not_reached(); break; } return 0; } static void _log_reader_insert_msg_length_stats(LogReader *self, gsize len) { stats_aggregator_add_data_point(self->max_message_size, len); stats_aggregator_add_data_point(self->average_messages_size, len); } static gboolean log_reader_handle_line(LogReader *self, const guchar *line, gint length, LogTransportAuxData *aux) { LogMessage *m; m = msg_format_construct_message(&self->options->parse_options, line, length); msg_debug("Incoming log entry", evt_tag_mem("input", line, length), evt_tag_msg_reference(m)); msg_format_parse_into(&self->options->parse_options, m, line, length); _log_reader_insert_msg_length_stats(self, length); log_msg_set_recvd_rawmsg_size(m, length); if (aux) { log_msg_set_saddr(m, aux->peer_addr ? : self->peer_addr); log_msg_set_daddr(m, aux->local_addr ? : self->local_addr); if (aux->timestamp.tv_sec) { /* accurate timestamp was received from the transport layer, use * that instead of the one we generated */ m->timestamps[LM_TS_RECVD].ut_sec = aux->timestamp.tv_sec; m->timestamps[LM_TS_RECVD].ut_usec = aux->timestamp.tv_nsec / 1000; } m->proto = aux->proto; } log_msg_refcache_start_producer(m); log_transport_aux_data_foreach(aux, _add_aux_nvpair, m); log_source_post(&self->super, m); log_msg_refcache_stop(); return log_source_free_to_send(&self->super); } /* returns: notify_code (NC_XXXX) or 0 for success */ static gint log_reader_fetch_log(LogReader *self) { gint msg_count = 0; gboolean may_read = TRUE; LogTransportAuxData aux_storage, *aux = &aux_storage; if ((self->options->flags & LR_IGNORE_AUX_DATA)) aux = NULL; log_transport_aux_data_init(aux); if (log_proto_server_handshake_in_progress(self->proto)) { return log_reader_process_handshake(self); } /* NOTE: this loop is here to decrease the load on the main loop, we try * to fetch a couple of messages in a single run (but only up to * fetch_limit). */ while (msg_count < self->options->fetch_limit && !main_loop_worker_job_quit()) { Bookmark *bookmark; const guchar *msg; gsize msg_len; LogProtoStatus status; msg = NULL; /* NOTE: may_read is used to implement multi-read checking. It * is initialized to TRUE to indicate that the protocol is * allowed to issue a read(). If multi-read is disallowed in the * protocol, it resets may_read to FALSE after the first read was issued. */ log_transport_aux_data_reinit(aux); bookmark = ack_tracker_request_bookmark(self->super.ack_tracker); status = log_proto_server_fetch(self->proto, &msg, &msg_len, &may_read, aux, bookmark); switch (status) { case LPS_EOF: log_transport_aux_data_destroy(aux); return NC_CLOSE; case LPS_ERROR: log_transport_aux_data_destroy(aux); return NC_READ_ERROR; case LPS_SUCCESS: break; case LPS_AGAIN: break; default: g_assert_not_reached(); break; } if (!msg) { /* no more messages for now */ break; } if (msg_len > 0 || (self->options->flags & LR_EMPTY_LINES)) { msg_count++; if (!log_reader_handle_line(self, msg, msg_len, aux)) { /* window is full, don't generate further messages */ break; } } } log_transport_aux_data_destroy(aux); if (msg_count == self->options->fetch_limit) self->immediate_check = TRUE; return 0; } static void log_reader_io_handle_in(gpointer s) { LogReader *self = (LogReader *) s; log_reader_disable_watches(self); if ((self->options->flags & LR_THREADED)) { main_loop_io_worker_job_submit(&self->io_job, NULL); } else { /* Checking main_loop_io_worker_job_quit() helps to speed up the * reload process. If reload/shutdown is requested we shouldn't do * anything here, outstanding messages will be processed by the new * configuration. * * Our current understanding is that it doesn't prevent race * conditions of any kind. */ if (!main_loop_worker_job_quit()) { log_pipe_ref(&self->super.super); log_reader_work_perform(s, NULL); log_reader_work_finished(s, NULL); log_pipe_unref(&self->super.super); } } } static void _register_aggregated_stats(LogReader *self) { gint level = log_pipe_is_internal(&self->super.super) ? STATS_LEVEL3 : self->super.options->stats_level; gchar stats_instance[1024]; const gchar *instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->super.metrics.stats_kb, stats_instance, sizeof(stats_instance)); StatsClusterKey sc_key_eps_input; stats_cluster_single_key_legacy_set_with_name(&sc_key_eps_input, self->super.options->stats_source | SCS_SOURCE, self->super.stats_id, instance_name, "processed"); stats_aggregator_lock(); StatsClusterKey sc_key; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.options->stats_source | SCS_SOURCE, self->super.stats_id, instance_name, "msg_size_max"); stats_register_aggregator_maximum(level, &sc_key, &self->max_message_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.options->stats_source | SCS_SOURCE, self->super.stats_id, instance_name, "msg_size_avg"); stats_register_aggregator_average(level, &sc_key, &self->average_messages_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.options->stats_source | SCS_SOURCE, self->super.stats_id, instance_name, "eps"); stats_register_aggregator_cps(level, &sc_key, &sc_key_eps_input, SC_TYPE_SINGLE_VALUE, &self->CPS); stats_aggregator_unlock(); } static void _unregister_aggregated_stats(LogReader *self) { stats_aggregator_lock(); stats_unregister_aggregator(&self->max_message_size); stats_unregister_aggregator(&self->average_messages_size); stats_unregister_aggregator(&self->CPS); stats_aggregator_unlock(); } /***************************************************************************** * LogReader->LogPipe interface implementation *****************************************************************************/ static gboolean log_reader_init(LogPipe *s) { LogReader *self = (LogReader *) s; if (!log_source_init(s)) return FALSE; log_proto_server_set_ack_tracker(self->proto, self->super.ack_tracker); if (!log_proto_server_validate_options(self->proto)) return FALSE; if (!self->options->parse_options.format_handler) { msg_error("Unknown format plugin specified", evt_tag_str("format", self->options->parse_options.format)); return FALSE; } iv_event_register(&self->schedule_wakeup); log_reader_start_watches(self); _register_aggregated_stats(self); return TRUE; } static gboolean log_reader_deinit(LogPipe *s) { LogReader *self = (LogReader *) s; main_loop_assert_main_thread(); iv_event_unregister(&self->schedule_wakeup); if (iv_task_registered(&self->restart_task)) iv_task_unregister(&self->restart_task); log_reader_stop_watches(self); _unregister_aggregated_stats(self); if (!log_source_deinit(s)) return FALSE; return TRUE; } static void log_reader_init_watches(LogReader *self) { IV_TASK_INIT(&self->restart_task); self->restart_task.cookie = self; self->restart_task.handler = log_reader_io_handle_in; IV_EVENT_INIT(&self->schedule_wakeup); self->schedule_wakeup.cookie = self; self->schedule_wakeup.handler = log_reader_wakeup_triggered; IV_TIMER_INIT(&self->idle_timer); self->idle_timer.cookie = self; self->idle_timer.handler = log_reader_idle_timeout; main_loop_io_worker_job_init(&self->io_job); self->io_job.user_data = self; self->io_job.work = log_reader_work_perform; self->io_job.completion = log_reader_work_finished; self->io_job.engage = (void (*)(gpointer)) log_pipe_ref; self->io_job.release = (void (*)(gpointer)) log_pipe_unref; } static void log_reader_free(LogPipe *s) { LogReader *self = (LogReader *) s; if (self->proto) { log_proto_server_free(self->proto); self->proto = NULL; } if (self->poll_events) poll_events_free(self->poll_events); log_pipe_unref(self->control); g_sockaddr_unref(self->peer_addr); g_sockaddr_unref(self->local_addr); g_mutex_clear(&self->pending_close_lock); g_cond_clear(&self->pending_close_cond); log_source_free(s); } static void _schedule_dynamic_window_realloc(LogSource *s) { LogReader *self = (LogReader *)s; msg_trace("LogReader::dynamic_window_realloc called"); if (self->io_job.working) { self->realloc_window_after_fetch = TRUE; return; } log_source_dynamic_window_realloc(s); } LogReader * log_reader_new(GlobalConfig *cfg) { LogReader *self = g_new0(LogReader, 1); log_source_init_instance(&self->super, cfg); self->super.super.init = log_reader_init; self->super.super.deinit = log_reader_deinit; self->super.super.free_fn = log_reader_free; self->super.wakeup = log_reader_wakeup; self->super.schedule_dynamic_window_realloc = _schedule_dynamic_window_realloc; self->super.metrics.raw_bytes_enabled = TRUE; self->immediate_check = FALSE; log_reader_init_watches(self); g_mutex_init(&self->pending_close_lock); g_cond_init(&self->pending_close_cond); return self; } /**************************************************************************** * LogReaderOptions defaults/init/destroy ***************************************************************************/ void log_reader_options_defaults(LogReaderOptions *options) { log_source_options_defaults(&options->super); log_proto_server_options_defaults(&options->proto_options.super); msg_format_options_defaults(&options->parse_options); options->fetch_limit = 10; } /* * NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy * * Rationale: * - init is called from driver init (e.g. affile_sd_init), * - destroy is called from driver free method (e.g. affile_sd_free, NOT affile_sd_deinit) * * The reason: * - when initializing the reloaded configuration fails for some reason, * we have to fall back to the old configuration, thus we cannot dump * the information stored in the Options structure at deinit time, but * have to recover it when the old configuration is initialized. * * For the reasons above, init and destroy behave the following way: * * - init is idempotent, it can be called multiple times without leaking * memory, and without loss of information * - destroy is only called once, when the options are indeed to be destroyed * * Also important to note is that when init is called multiple times, the * GlobalConfig reference is the same, this means that it is enough to * remember whether init was called already and return w/o doing anything in * that case, which is actually how idempotency is implemented here. */ void log_reader_options_init(LogReaderOptions *options, GlobalConfig *cfg, const gchar *group_name) { if (options->initialized) return; log_source_options_init(&options->super, cfg, group_name); log_proto_server_options_init(&options->proto_options.super, cfg); msg_format_options_init(&options->parse_options, cfg); if (options->check_hostname == -1) options->check_hostname = cfg->check_hostname; if (options->check_hostname) { options->parse_options.flags |= LP_CHECK_HOSTNAME; } if (!options->super.keep_timestamp) { options->parse_options.flags |= LP_NO_PARSE_DATE; } if (options->parse_options.default_pri == 0xFFFF) { if (options->flags & LR_KERNEL) options->parse_options.default_pri = LOG_KERN | LOG_NOTICE; else options->parse_options.default_pri = LOG_USER | LOG_NOTICE; } if (options->proto_options.super.encoding) options->parse_options.flags |= LP_ASSUME_UTF8; if (cfg->threaded) options->flags |= LR_THREADED; options->initialized = TRUE; } void log_reader_options_destroy(LogReaderOptions *options) { log_source_options_destroy(&options->super); log_proto_server_options_destroy(&options->proto_options.super); msg_format_options_destroy(&options->parse_options); options->initialized = FALSE; } CfgFlagHandler log_reader_flag_handlers[] = { /* NOTE: underscores are automatically converted to dashes */ /* LogReaderOptions */ { "kernel", CFH_SET, offsetof(LogReaderOptions, flags), LR_KERNEL }, { "empty-lines", CFH_SET, offsetof(LogReaderOptions, flags), LR_EMPTY_LINES }, { "threaded", CFH_SET, offsetof(LogReaderOptions, flags), LR_THREADED }, { "ignore-aux-data", CFH_SET, offsetof(LogReaderOptions, flags), LR_IGNORE_AUX_DATA }, { NULL }, }; gboolean log_reader_options_process_flag(LogReaderOptions *options, const gchar *flag) { if (!msg_format_options_process_flag(&options->parse_options, flag)) return cfg_process_flag(log_reader_flag_handlers, options, flag); return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/logreader.h000066400000000000000000000075521450431004300202470ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGREADER_H_INCLUDED #define LOGREADER_H_INCLUDED #include "logsource.h" #include "stats/aggregator/stats-aggregator.h" #include "stats/aggregator/stats-aggregator-registry.h" #include "logproto/logproto-server.h" #include "poll-events.h" #include "mainloop-io-worker.h" #include "msg-format.h" #include /* flags */ #define LR_KERNEL 0x0002 #define LR_EMPTY_LINES 0x0004 #define LR_IGNORE_AUX_DATA 0x0008 #define LR_THREADED 0x0040 /* options */ typedef struct _LogReaderOptions { gboolean initialized; LogSourceOptions super; MsgFormatOptions parse_options; LogProtoServerOptionsStorage proto_options; guint32 flags; gint fetch_limit; const gchar *group_name; gboolean check_hostname; } LogReaderOptions; typedef struct _LogReader LogReader; struct _LogReader { LogSource super; LogProtoServer *proto; gboolean immediate_check; LogPipe *control; LogReaderOptions *options; PollEvents *poll_events; GSockAddr *peer_addr; GSockAddr *local_addr; StatsAggregator *max_message_size; StatsAggregator *average_messages_size; StatsAggregator *CPS; /* NOTE: these used to be LogReaderWatch members, which were merged into * LogReader with the multi-thread refactorization */ struct iv_task restart_task; struct iv_event schedule_wakeup; MainLoopIOWorkerJob io_job; guint watches_running:1, suspended:1, realloc_window_after_fetch:1; gint notify_code; /* proto & poll_events pending to be applied. As long as the previous * processing is being done, we can't replace these in self->proto and * self->poll_events, they get applied to the production ones as soon as * the previous work is finished */ gboolean pending_close; GCond pending_close_cond; GMutex pending_close_lock; struct iv_timer idle_timer; }; void log_reader_set_options(LogReader *s, LogPipe *control, LogReaderOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb); void log_reader_set_follow_filename(LogReader *self, const gchar *follow_filename); void log_reader_set_name(LogReader *s, const gchar *name); void log_reader_set_peer_addr(LogReader *s, GSockAddr *peer_addr); void log_reader_set_local_addr(LogReader *s, GSockAddr *local_addr); void log_reader_set_immediate_check(LogReader *s); void log_reader_disable_bookmark_saving(LogReader *s); void log_reader_open(LogReader *s, LogProtoServer *proto, PollEvents *poll_events); void log_reader_close_proto(LogReader *s); LogReader *log_reader_new(GlobalConfig *cfg); void log_reader_options_defaults(LogReaderOptions *options); void log_reader_options_init(LogReaderOptions *options, GlobalConfig *cfg, const gchar *group_name); void log_reader_options_destroy(LogReaderOptions *options); void log_reader_options_set_tags(LogReaderOptions *options, GList *tags); gboolean log_reader_options_process_flag(LogReaderOptions *options, const gchar *flag); #endif syslog-ng-syslog-ng-4.4.0/lib/logscheduler-pipe.c000066400000000000000000000046761450431004300217150ustar00rootroot00000000000000/* * Copyright (c) 2023 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logscheduler-pipe.h" LogSchedulerOptions * log_scheduler_pipe_get_scheduler_options(LogPipe *s) { LogSchedulerPipe *self = (LogSchedulerPipe *) s; return &self->scheduler_options; } static gboolean _init(LogPipe *s) { LogSchedulerPipe *self = (LogSchedulerPipe *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_scheduler_options_init(&self->scheduler_options, cfg)) return FALSE; if (!self->scheduler) self->scheduler = log_scheduler_new(&self->scheduler_options, self->super.pipe_next); log_scheduler_init(self->scheduler); return TRUE; } static gboolean _deinit(LogPipe *s) { LogSchedulerPipe *self = (LogSchedulerPipe *) s; log_scheduler_deinit(self->scheduler); return TRUE; } static void _queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSchedulerPipe *self = (LogSchedulerPipe *) s; log_scheduler_push(self->scheduler, msg, path_options); } static void _free(LogPipe *s) { LogSchedulerPipe *self = (LogSchedulerPipe *) s; if (self->scheduler) log_scheduler_free(self->scheduler); } LogPipe * log_scheduler_pipe_new(GlobalConfig *cfg) { LogSchedulerPipe *self = g_new0(LogSchedulerPipe, 1); log_pipe_init_instance(&self->super, cfg); self->super.init = _init; self->super.deinit = _deinit; self->super.queue = _queue; self->super.free_fn = _free; log_scheduler_options_defaults(&self->scheduler_options); log_pipe_add_info(&self->super, "scheduler"); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/logscheduler-pipe.h000066400000000000000000000025621450431004300217120ustar00rootroot00000000000000/* * Copyright (c) 2023 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGSCHEDULER_PIPE_H_INCLUDED #define LOGSCHEDULER_PIPE_H_INCLUDED #include "logpipe.h" #include "logscheduler.h" typedef struct _LogSchedulerPipe { LogPipe super; LogSchedulerOptions scheduler_options; LogScheduler *scheduler; } LogSchedulerPipe; LogSchedulerOptions *log_scheduler_pipe_get_scheduler_options(LogPipe *s); LogPipe *log_scheduler_pipe_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/logscheduler.c000066400000000000000000000255671450431004300207640ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logscheduler.h" #include "template/eval.h" static void _reinject_message(LogPipe *front_pipe, LogMessage *msg, const LogPathOptions *path_options) { if (front_pipe) log_pipe_queue(front_pipe, msg, path_options); else log_msg_drop(msg, path_options, AT_PROCESSED); } #if SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION /* LogSchedulerBatch */ LogSchedulerBatch * _batch_new(struct iv_list_head *elements) { LogSchedulerBatch *batch = g_new0(LogSchedulerBatch, 1); INIT_IV_LIST_HEAD(&batch->elements); INIT_IV_LIST_HEAD(&batch->list); iv_list_splice_tail(elements, &batch->elements); return batch; } void _batch_free(LogSchedulerBatch *batch) { g_free(batch); } /* LogSchedulerPartition */ static void _work(gpointer s, gpointer arg) { LogSchedulerPartition *partition = (LogSchedulerPartition *) s; struct iv_list_head *ilh, *next; struct iv_list_head *ilh2, *next2; /* batches_lock protects the batches list itself. We take off partitions * one-by-one under the protection of the lock */ g_mutex_lock(&partition->batches_lock); while (!iv_list_empty(&partition->batches)) { struct iv_list_head batches = IV_LIST_HEAD_INIT(batches); iv_list_splice_init(&partition->batches, &batches); g_mutex_unlock(&partition->batches_lock); iv_list_for_each_safe(ilh, next, &batches) { /* remove the first batch from the batches list */ LogSchedulerBatch *batch = iv_list_entry(ilh, LogSchedulerBatch, list); iv_list_del(&batch->list); iv_list_for_each_safe(ilh2, next2, &batch->elements) { LogMessageQueueNode *node = iv_list_entry(ilh2, LogMessageQueueNode, list); iv_list_del(&node->list); LogMessage *msg = log_msg_ref(node->msg); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; path_options.ack_needed = node->ack_needed; path_options.flow_control_requested = node->flow_control_requested; log_msg_free_queue_node(node); log_msg_refcache_start_consumer(msg, &path_options); _reinject_message(partition->front_pipe, msg, &path_options); log_msg_unref(msg); log_msg_refcache_stop(); } _batch_free(batch); } g_mutex_lock(&partition->batches_lock); } g_mutex_unlock(&partition->batches_lock); } static void _complete(gpointer s, gpointer arg) { LogSchedulerPartition *partition = (LogSchedulerPartition *) s; gboolean needs_restart = FALSE; g_mutex_lock(&partition->batches_lock); if (!iv_list_empty(&partition->batches)) { /* our work() function returned right before a new batch was added, let's restart */ needs_restart = TRUE; } else partition->flush_running = FALSE; g_mutex_unlock(&partition->batches_lock); if (needs_restart) main_loop_io_worker_job_submit(&partition->io_job, NULL); } static void _partition_add_batch(LogSchedulerPartition *partition, LogSchedulerBatch *batch) { gboolean trigger_flush = FALSE; g_mutex_lock(&partition->batches_lock); if (!partition->flush_running && iv_list_empty(&partition->batches)) { trigger_flush = TRUE; partition->flush_running = TRUE; } iv_list_add_tail(&batch->list, &partition->batches); g_mutex_unlock(&partition->batches_lock); if (trigger_flush) { main_loop_io_worker_job_submit_continuation(&partition->io_job, NULL); } } static void _partition_init(LogSchedulerPartition *partition, LogPipe *front_pipe) { main_loop_io_worker_job_init(&partition->io_job); partition->io_job.user_data = partition; partition->io_job.work = _work; partition->io_job.completion = _complete; partition->io_job.engage = NULL; partition->io_job.release = NULL; partition->front_pipe = front_pipe; INIT_IV_LIST_HEAD(&partition->batches); g_mutex_init(&partition->batches_lock); } void _partition_clear(LogSchedulerPartition *partition) { g_mutex_clear(&partition->batches_lock); } /* LogSchedulerThreadState */ static guint _get_partition_index(LogScheduler *self, LogSchedulerThreadState *thread_state, LogMessage *msg) { if (!self->options->partition_key) { gint partition_index = thread_state->last_partition; thread_state->last_partition = (thread_state->last_partition + 1) % self->options->num_partitions; return partition_index; } else { LogTemplateEvalOptions options = DEFAULT_TEMPLATE_EVAL_OPTIONS; return log_template_hash(self->options->partition_key, msg, &options) % self->options->num_partitions; } } static gpointer _flush_batch(gpointer s) { LogScheduler *self = (LogScheduler *) s; gint thread_index = main_loop_worker_get_thread_index(); g_assert(thread_index >= 0); LogSchedulerThreadState *thread_state = &self->thread_states[thread_index]; for (gint partition_index = 0; partition_index < self->options->num_partitions; partition_index++) { if (iv_list_empty(&thread_state->batch_by_partition[partition_index])) continue; /* form the new batch, hand over the accumulated elements in batch_by_partition */ LogSchedulerBatch *batch = _batch_new(&thread_state->batch_by_partition[partition_index]); INIT_IV_LIST_HEAD(&thread_state->batch_by_partition[partition_index]); /* add the new batch to the target partition */ LogSchedulerPartition *partition = &self->partitions[partition_index]; _partition_add_batch(partition, batch); } thread_state->num_messages = 0; return NULL; } static void _queue_thread(LogScheduler *self, LogSchedulerThreadState *thread_state, LogMessage *msg, const LogPathOptions *path_options) { if (thread_state->num_messages == 0) main_loop_worker_register_batch_callback(&thread_state->batch_callback); guint partition_index = _get_partition_index(self, thread_state, msg); LogMessageQueueNode *node; node = log_msg_alloc_queue_node(msg, path_options); iv_list_add_tail(&node->list, &thread_state->batch_by_partition[partition_index]); thread_state->num_messages++; log_msg_unref(msg); } static void _thread_state_init(LogScheduler *self, LogSchedulerThreadState *state) { worker_batch_callback_init(&state->batch_callback); state->batch_callback.func = _flush_batch; state->batch_callback.user_data = self; for (gint i = 0; i < self->options->num_partitions; i++) INIT_IV_LIST_HEAD(&state->batch_by_partition[i]); } static void _init_thread_states(LogScheduler *self) { for (gint i = 0; i < self->num_threads; i++) { _thread_state_init(self, &self->thread_states[i]); } } static void _init_partitions(LogScheduler *self) { for (gint i = 0; i < self->options->num_partitions; i++) { _partition_init(&self->partitions[i], self->front_pipe); } } static void _free_partitions(LogScheduler *self) { for (gint i = 0; i < self->options->num_partitions; i++) { _partition_clear(&self->partitions[i]); } } gboolean log_scheduler_init(LogScheduler *self) { return TRUE; } void log_scheduler_deinit(LogScheduler *self) { } void log_scheduler_push(LogScheduler *self, LogMessage *msg, const LogPathOptions *path_options) { gint thread_index = main_loop_worker_get_thread_index(); if (!self->front_pipe || self->options->num_partitions == 0 || thread_index < 0 || thread_index >= self->num_threads) { _reinject_message(self->front_pipe, msg, path_options); return; } LogSchedulerThreadState *thread_state = &self->thread_states[thread_index]; _queue_thread(self, thread_state, msg, path_options); } LogScheduler * log_scheduler_new(LogSchedulerOptions *options, LogPipe *front_pipe) { gint max_threads = main_loop_worker_get_max_number_of_threads(); LogScheduler *self = g_malloc0(sizeof(LogScheduler) + max_threads * sizeof(LogSchedulerThreadState)); self->num_threads = max_threads; self->options = options; self->front_pipe = log_pipe_ref(front_pipe); _init_thread_states(self); _init_partitions(self); return self; } void log_scheduler_free(LogScheduler *self) { log_pipe_unref(self->front_pipe); _free_partitions(self); g_free(self); } #else gboolean log_scheduler_init(LogScheduler *self) { if (self->options->num_partitions > 0) { msg_warning("Unable to parallelize message work-load even though partitions(N) N > 1 was set, " "as the ivykis dependency is too old and lacks iv_work_pool_submit_continuation() " "function. Use the bundled version of ivykis or use a version that already has this " "function, see https://github.com/buytenh/ivykis/compare/master...bazsi:ivykis:iv-work-pool-support-for-slave-work-items"); } return TRUE; } void log_scheduler_deinit(LogScheduler *self) { } void log_scheduler_push(LogScheduler *self, LogMessage *msg, const LogPathOptions *path_options) { _reinject_message(self->front_pipe, msg, path_options); } LogScheduler * log_scheduler_new(LogSchedulerOptions *options, LogPipe *front_pipe) { LogScheduler *self = g_malloc0(sizeof(LogScheduler) + 0 * sizeof(LogSchedulerThreadState)); self->options = options; self->front_pipe = log_pipe_ref(front_pipe); return self; } void log_scheduler_free(LogScheduler *self) { log_pipe_unref(self->front_pipe); g_free(self); } #endif void log_scheduler_options_set_partition_key_ref(LogSchedulerOptions *options, LogTemplate *partition_key) { log_template_unref(options->partition_key); options->partition_key = partition_key; } void log_scheduler_options_defaults(LogSchedulerOptions *options) { options->num_partitions = -1; options->partition_key = NULL; } gboolean log_scheduler_options_init(LogSchedulerOptions *options, GlobalConfig *cfg) { if (options->num_partitions == -1) options->num_partitions = 0; if (options->num_partitions > LOGSCHEDULER_MAX_PARTITIONS) options->num_partitions = LOGSCHEDULER_MAX_PARTITIONS; return TRUE; } void log_scheduler_options_destroy(LogSchedulerOptions *options) { log_template_unref(options->partition_key); } syslog-ng-syslog-ng-4.4.0/lib/logscheduler.h000066400000000000000000000053221450431004300207540ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGSCHEDULER_H_INCLUDED #define LOGSCHEDULER_H_INCLUDED #include "logpipe.h" #include "mainloop-io-worker.h" #include "template/templates.h" #include #include #define LOGSCHEDULER_MAX_PARTITIONS 16 typedef struct _LogSchedulerBatch { struct iv_list_head elements; struct iv_list_head list; } LogSchedulerBatch; typedef struct _LogSchedulerPartition { GMutex batches_lock; struct iv_list_head batches; gboolean flush_running; MainLoopIOWorkerJob io_job; LogPipe *front_pipe; } LogSchedulerPartition; typedef struct _LogSchedulerThreadState { WorkerBatchCallback batch_callback; struct iv_list_head batch_by_partition[LOGSCHEDULER_MAX_PARTITIONS]; guint64 num_messages; gint last_partition; } LogSchedulerThreadState; typedef struct _LogSchedulerOptions { gint num_partitions; LogTemplate *partition_key; } LogSchedulerOptions; typedef struct _LogScheduler { LogPipe *front_pipe; LogSchedulerOptions *options; gint num_threads; LogSchedulerPartition partitions[LOGSCHEDULER_MAX_PARTITIONS]; LogSchedulerThreadState thread_states[]; } LogScheduler; gboolean log_scheduler_init(LogScheduler *self); void log_scheduler_deinit(LogScheduler *self); void log_scheduler_push(LogScheduler *self, LogMessage *msg, const LogPathOptions *path_options); LogScheduler *log_scheduler_new(LogSchedulerOptions *options, LogPipe *front_pipe); void log_scheduler_free(LogScheduler *self); void log_scheduler_options_set_partition_key_ref(LogSchedulerOptions *options, LogTemplate *partition_key); void log_scheduler_options_defaults(LogSchedulerOptions *options); gboolean log_scheduler_options_init(LogSchedulerOptions *options, GlobalConfig *cfg); void log_scheduler_options_destroy(LogSchedulerOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/logsource.c000066400000000000000000000737721450431004300203070ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logsource.h" #include "messages.h" #include "host-resolve.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-logpipe.h" #include "stats/stats-cluster-single.h" #include "msg-stats.h" #include "logmsg/tags.h" #include "ack-tracker/ack_tracker.h" #include "ack-tracker/ack_tracker_factory.h" #include "timeutils/misc.h" #include "compat/time.h" #include "scratch-buffers.h" #include #include gboolean accurate_nanosleep = FALSE; void log_source_wakeup(LogSource *self) { if (self->wakeup) self->wakeup(self); msg_diagnostics("Source has been resumed", log_pipe_location_tag(&self->super)); } static inline guint32 _take_reclaimed_window(LogSource *self, guint32 window_size_increment) { gssize old = atomic_gssize_sub(&self->window_size_to_be_reclaimed, window_size_increment); gboolean reclaim_in_progress = (old > 0); if (!reclaim_in_progress) { return window_size_increment; } guint32 remaining_window_size_increment = MAX(window_size_increment - old, 0); guint32 reclaimed = window_size_increment - remaining_window_size_increment; atomic_gssize_add(&self->pending_reclaimed, reclaimed); return remaining_window_size_increment; } static inline void _flow_control_window_size_adjust(LogSource *self, guint32 window_size_increment, gboolean last_ack_type_is_suspended) { gboolean suspended; if (G_UNLIKELY(dynamic_window_is_enabled(&self->dynamic_window))) window_size_increment = _take_reclaimed_window(self, window_size_increment); gsize old_window_size = window_size_counter_add(&self->window_size, window_size_increment, &suspended); stats_counter_add(self->metrics.stat_window_size, window_size_increment); msg_diagnostics("Window size adjustment", evt_tag_int("old_window_size", old_window_size), evt_tag_int("window_size_increment", window_size_increment), evt_tag_str("suspended_before_increment", suspended ? "TRUE" : "FALSE"), evt_tag_str("last_ack_type_is_suspended", last_ack_type_is_suspended ? "TRUE" : "FALSE")); gboolean need_to_resume_counter = !last_ack_type_is_suspended && suspended; if (need_to_resume_counter) window_size_counter_resume(&self->window_size); if (old_window_size == 0 || need_to_resume_counter) log_source_wakeup(self); } static void _flow_control_rate_adjust(LogSource *self) { #ifdef SYSLOG_NG_HAVE_CLOCK_GETTIME guint32 cur_ack_count, last_ack_count; /* NOTE: this is racy. msg_ack may be executing in different writer * threads. I don't want to lock, all we need is an approximate value of * the ACK rate of the last couple of seconds. */ if (accurate_nanosleep && self->threaded) { cur_ack_count = ++self->ack_count; if ((cur_ack_count & 0x3FFF) == 0) { struct timespec now; glong diff; /* do this every once in a while, once in 16k messages should be fine */ last_ack_count = self->last_ack_count; /* make sure that we have at least 16k messages to measure the rate * for. Because of the race we may have last_ack_count == * cur_ack_count if another thread already measured the same span */ if (last_ack_count < cur_ack_count - 16383) { clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec > self->last_ack_rate_time.tv_sec + 6) { /* last check was too far apart, this means the rate is quite slow. turn off sleeping. */ self->window_full_sleep_nsec = 0; self->last_ack_rate_time = now; } else { /* ok, we seem to have a close enough measurement, this means * we do have a high rate. Calculate how much we should sleep * in case the window gets full */ diff = timespec_diff_nsec(&now, &self->last_ack_rate_time); self->window_full_sleep_nsec = (diff / (cur_ack_count - last_ack_count)); if (self->window_full_sleep_nsec > 1e6) { /* in case we'd be waiting for 1msec for another free slot in the window, let's go to background instead */ self->window_full_sleep_nsec = 0; } else { /* otherwise let's wait for about 8 message to be emptied before going back to the loop, but clamp the maximum time to 0.1msec */ self->window_full_sleep_nsec <<= 3; if (self->window_full_sleep_nsec > 1e5) self->window_full_sleep_nsec = 1e5; } self->last_ack_count = cur_ack_count; self->last_ack_rate_time = now; } } } } #endif } void log_source_flow_control_adjust(LogSource *self, guint32 window_size_increment) { _flow_control_window_size_adjust(self, window_size_increment, FALSE); _flow_control_rate_adjust(self); } void log_source_flow_control_adjust_when_suspended(LogSource *self, guint32 window_size_increment) { _flow_control_window_size_adjust(self, window_size_increment, TRUE); _flow_control_rate_adjust(self); } void log_source_disable_bookmark_saving(LogSource *self) { ack_tracker_disable_bookmark_saving(self->ack_tracker); } /** * log_source_msg_ack: * * This is running in the same thread as the _destination_, thus care must * be taken when manipulating the LogSource data structure. **/ static void log_source_msg_ack(LogMessage *msg, AckType ack_type) { AckTracker *ack_tracker = msg->ack_record->tracker; ack_tracker_manage_msg_ack(ack_tracker, msg, ack_type); } void log_source_flow_control_suspend(LogSource *self) { msg_debug("Source has been suspended", log_pipe_location_tag(&self->super), evt_tag_str("function", __FUNCTION__)); window_size_counter_suspend(&self->window_size); } void log_source_enable_dynamic_window(LogSource *self, DynamicWindowPool *window_pool) { dynamic_window_set_pool(&self->dynamic_window, dynamic_window_pool_ref(window_pool)); } gboolean log_source_is_dynamic_window_enabled(LogSource *self) { return dynamic_window_is_enabled(&self->dynamic_window); } void log_source_dynamic_window_update_statistics(LogSource *self) { dynamic_window_stat_update(&self->dynamic_window.stat, window_size_counter_get(&self->window_size, NULL)); msg_trace("Updating dynamic window statistic", evt_tag_int("avg window size", dynamic_window_stat_get_avg(&self->dynamic_window.stat))); } static void _reclaim_dynamic_window(LogSource *self, gsize window_size) { g_assert(self->full_window_size - window_size >= self->initial_window_size); atomic_gssize_set(&self->window_size_to_be_reclaimed, window_size); } static void _release_dynamic_window(LogSource *self) { g_assert(self->ack_tracker == NULL); gsize dynamic_part = self->full_window_size - self->initial_window_size; msg_trace("Releasing dynamic part of the window", evt_tag_int("dynamic_window_to_be_released", dynamic_part), log_pipe_location_tag(&self->super)); self->full_window_size -= dynamic_part; stats_counter_sub(self->metrics.stat_full_window, dynamic_part); window_size_counter_sub(&self->window_size, dynamic_part, NULL); stats_counter_sub(self->metrics.stat_window_size, dynamic_part); dynamic_window_release(&self->dynamic_window, dynamic_part); dynamic_window_pool_unref(self->dynamic_window.pool); } static void _inc_balanced(LogSource *self, gsize inc) { gsize offered_dynamic = dynamic_window_request(&self->dynamic_window, inc); msg_trace("Balance::increase", log_pipe_location_tag(&self->super), evt_tag_printf("connection", "%p", self), evt_tag_int("old_full_window_size", self->full_window_size), evt_tag_int("new_full_window_size", self->full_window_size + offered_dynamic)); self->full_window_size += offered_dynamic; stats_counter_add(self->metrics.stat_full_window, offered_dynamic); gsize old_window_size = window_size_counter_add(&self->window_size, offered_dynamic, NULL); stats_counter_add(self->metrics.stat_window_size, offered_dynamic); if (old_window_size == 0 && offered_dynamic != 0) log_source_wakeup(self); } static void _dec_balanced(LogSource *self, gsize dec) { gsize new_full_window_size = self->full_window_size - dec; gsize empty_window = window_size_counter_get(&self->window_size, NULL); gsize remaining_sub = 0; if (empty_window <= dec) { remaining_sub = dec - empty_window; if (empty_window == 0) { dec = 0; } else { dec = empty_window - 1; } new_full_window_size = self->full_window_size - dec; _reclaim_dynamic_window(self, remaining_sub); } window_size_counter_sub(&self->window_size, dec, NULL); stats_counter_sub(self->metrics.stat_window_size, dec); msg_trace("Balance::decrease", log_pipe_location_tag(&self->super), evt_tag_printf("connection", "%p", self), evt_tag_int("old_full_window_size", self->full_window_size), evt_tag_int("new_full_window_size", new_full_window_size), evt_tag_int("to_be_reclaimed", remaining_sub)); self->full_window_size = new_full_window_size; stats_counter_set(self->metrics.stat_full_window, new_full_window_size); dynamic_window_release(&self->dynamic_window, dec); } static gboolean _reclaim_window_instead_of_rebalance(LogSource *self) { //check pending_reclaimed gssize total_reclaim = atomic_gssize_set_and_get(&self->pending_reclaimed, 0); gssize to_be_reclaimed = atomic_gssize_get(&self->window_size_to_be_reclaimed); gboolean reclaim_in_progress = (to_be_reclaimed > 0); if (total_reclaim > 0) { self->full_window_size -= total_reclaim; stats_counter_sub(self->metrics.stat_full_window, total_reclaim); dynamic_window_release(&self->dynamic_window, total_reclaim); } else { //to avoid underflow, we need to set a value <= 0 if (to_be_reclaimed < 0) atomic_gssize_set(&self->window_size_to_be_reclaimed, 0); } msg_trace("Checking if reclaim is in progress...", log_pipe_location_tag(&self->super), evt_tag_printf("connection", "%p", self), evt_tag_printf("in progress", "%s", reclaim_in_progress ? "yes" : "no"), evt_tag_long("total_reclaim", total_reclaim)); return reclaim_in_progress; } static void _dynamic_window_rebalance(LogSource *self) { gsize current_dynamic_win = self->full_window_size - self->initial_window_size; gboolean have_to_increase = current_dynamic_win < self->dynamic_window.pool->balanced_window; gboolean have_to_decrease = current_dynamic_win > self->dynamic_window.pool->balanced_window; msg_trace("Rebalance dynamic window", log_pipe_location_tag(&self->super), evt_tag_printf("connection", "%p", self), evt_tag_int("full_window", self->full_window_size), evt_tag_int("dynamic_win", current_dynamic_win), evt_tag_int("static_window", self->initial_window_size), evt_tag_int("balanced_window", self->dynamic_window.pool->balanced_window), evt_tag_int("avg_free", dynamic_window_stat_get_avg(&self->dynamic_window.stat))); if (have_to_increase) _inc_balanced(self, self->dynamic_window.pool->balanced_window - current_dynamic_win); else if (have_to_decrease) _dec_balanced(self, current_dynamic_win - self->dynamic_window.pool->balanced_window); } void log_source_dynamic_window_realloc(LogSource *self) { /* it is safe to assume that the window size is not decremented while this function runs, * only incrementation is possible by destination threads */ if (!_reclaim_window_instead_of_rebalance(self)) _dynamic_window_rebalance(self); dynamic_window_stat_reset(&self->dynamic_window.stat); } void log_source_mangle_hostname(LogSource *self, LogMessage *msg) { const gchar *resolved_name; gsize resolved_name_len; const gchar *orig_host; resolved_name = resolve_sockaddr_to_hostname(&resolved_name_len, msg->saddr, &self->options->host_resolve_options); log_msg_set_value(msg, LM_V_HOST_FROM, resolved_name, resolved_name_len); orig_host = log_msg_get_value(msg, LM_V_HOST, NULL); if (!self->options->keep_hostname || !orig_host || !orig_host[0]) { gchar host[256]; gint host_len = -1; if (G_UNLIKELY(self->options->chain_hostnames)) { msg->flags |= LF_CHAINED_HOSTNAME; if (msg->flags & LF_LOCAL) { /* local */ host_len = g_snprintf(host, sizeof(host), "%s@%s", self->options->group_name, resolved_name); } else if (!orig_host || !orig_host[0]) { /* remote && no hostname */ host_len = g_snprintf(host, sizeof(host), "%s/%s", resolved_name, resolved_name); } else { /* everything else, append source hostname */ host_len = g_snprintf(host, sizeof(host), "%s/%s", orig_host, resolved_name); } if (host_len >= sizeof(host)) host_len = sizeof(host) - 1; log_msg_set_value(msg, LM_V_HOST, host, host_len); } else { log_msg_set_value(msg, LM_V_HOST, resolved_name, resolved_name_len); } } } static void _register_window_stats(LogSource *self) { if (!stats_check_level(4)) return; gchar stats_instance[1024]; const gchar *instance_name = self->name; if (!instance_name) instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); StatsClusterKey sc_key; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->options->stats_source | SCS_SOURCE, self->stats_id, instance_name, "free_window"); self->metrics.stat_window_size_cluster = stats_register_dynamic_counter(4, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.stat_window_size); stats_counter_set(self->metrics.stat_window_size, window_size_counter_get(&self->window_size, NULL)); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->options->stats_source | SCS_SOURCE, self->stats_id, instance_name, "full_window"); self->metrics.stat_full_window_cluster = stats_register_dynamic_counter(4, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.stat_full_window); stats_counter_set(self->metrics.stat_full_window, self->full_window_size); } static void _unregister_window_stats(LogSource *self) { if (!stats_check_level(4)) return; stats_unregister_dynamic_counter(self->metrics.stat_window_size_cluster, SC_TYPE_SINGLE_VALUE, &self->metrics.stat_window_size); stats_unregister_dynamic_counter(self->metrics.stat_full_window_cluster, SC_TYPE_SINGLE_VALUE, &self->metrics.stat_full_window); } static inline void _create_ack_tracker_if_not_exists(LogSource *self) { if (!self->ack_tracker) { if (!self->ack_tracker_factory) self->ack_tracker_factory = instant_ack_tracker_bookmarkless_factory_new(); self->ack_tracker = ack_tracker_factory_create(self->ack_tracker_factory, self); } } static void _register_raw_bytes_stats(LogSource *self, gint stats_level) { stats_byte_counter_init(&self->metrics.recvd_bytes, self->metrics.recvd_bytes_key, stats_level, SBCP_KIB); } static void _unregister_raw_bytes_stats(LogSource *self) { stats_byte_counter_deinit(&self->metrics.recvd_bytes, self->metrics.recvd_bytes_key); } static void _register_counters(LogSource *self) { stats_lock(); gint level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : self->options->stats_level; stats_register_counter(level, self->metrics.recvd_messages_key, SC_TYPE_SINGLE_VALUE, &self->metrics.recvd_messages); StatsClusterKey sc_key; gchar stats_instance[1024]; const gchar *instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); stats_cluster_logpipe_key_legacy_set(&sc_key, self->options->stats_source | SCS_SOURCE, self->stats_id, instance_name); stats_register_counter(level, &sc_key, SC_TYPE_STAMP, &self->metrics.last_message_seen); _register_window_stats(self); stats_unlock(); if (self->metrics.raw_bytes_enabled) { level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : STATS_LEVEL1; _register_raw_bytes_stats(self, level); } } gboolean log_source_init(LogPipe *s) { LogSource *self = (LogSource *) s; _create_ack_tracker_if_not_exists(self); if (!ack_tracker_init(self->ack_tracker)) { msg_error("Failed to initialize AckTracker"); return FALSE; } _register_counters(self); return TRUE; } static void _unregister_counters(LogSource *self) { if (self->metrics.raw_bytes_enabled) _unregister_raw_bytes_stats(self); stats_lock(); stats_unregister_counter(self->metrics.recvd_messages_key, SC_TYPE_SINGLE_VALUE, &self->metrics.recvd_messages); StatsClusterKey sc_key; gchar stats_instance[1024]; const gchar *instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); stats_cluster_logpipe_key_legacy_set(&sc_key, self->options->stats_source | SCS_SOURCE, self->stats_id, instance_name); stats_unregister_counter(&sc_key, SC_TYPE_STAMP, &self->metrics.last_message_seen); _unregister_window_stats(self); stats_unlock(); } gboolean log_source_deinit(LogPipe *s) { LogSource *self = (LogSource *) s; ack_tracker_deinit(self->ack_tracker); _unregister_counters(self); return TRUE; } void log_source_post(LogSource *self, LogMessage *msg) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; gint old_window_size; ack_tracker_track_msg(self->ack_tracker, msg); /* NOTE: we start by enabling flow-control, thus we need an acknowledgement */ path_options.ack_needed = TRUE; log_msg_ref(msg); log_msg_add_ack(msg, &path_options); msg->ack_func = log_source_msg_ack; old_window_size = window_size_counter_sub(&self->window_size, 1, NULL); stats_counter_sub(self->metrics.stat_window_size, 1); if (G_UNLIKELY(old_window_size == 1)) { msg_debug("Source has been suspended", log_pipe_location_tag(&self->super), evt_tag_str("function", __FUNCTION__)); } /* * NOTE: this assertion validates that the source is not overflowing its * own flow-control window size, decreased above, by the atomic statement. * * If the _old_ value is zero, that means that the decrement operation * above has decreased the value to -1. */ g_assert(old_window_size > 0); ScratchBuffersMarker mark; scratch_buffers_mark(&mark); log_pipe_queue(&self->super, msg, &path_options); scratch_buffers_reclaim_marked(mark); } static gboolean _invoke_mangle_callbacks(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSource *self = (LogSource *) s; GList *next_item = g_list_first(self->options->source_queue_callbacks); while(next_item) { if(next_item->data) { if(!((mangle_callback) (next_item->data))(log_pipe_get_config(s), msg, self)) { log_msg_drop(msg, path_options, AT_PROCESSED); return FALSE; } } next_item = next_item->next; } return TRUE; } static void log_source_override_host(LogSource *self, LogMessage *msg) { if (self->options->host_override_len < 0) self->options->host_override_len = strlen(self->options->host_override); log_msg_set_value(msg, LM_V_HOST, self->options->host_override, self->options->host_override_len); } static void log_source_override_program(LogSource *self, LogMessage *msg) { if (self->options->program_override_len < 0) self->options->program_override_len = strlen(self->options->program_override); log_msg_set_value(msg, LM_V_PROGRAM, self->options->program_override, self->options->program_override_len); } static gchar * _get_pid_string(void) { #define MAX_PID_CHAR_COUNT 20 /* max PID on 64 bit systems is 2^64 - 1, which is 19 characters, +1 for terminating 0 */ static gchar pid_string[MAX_PID_CHAR_COUNT]; if (pid_string[0] == '\0') { #ifdef _WIN32 g_snprintf(pid_string, MAX_PID_CHAR_COUNT, "%lu", GetCurrentProcessId()); #else g_snprintf(pid_string, MAX_PID_CHAR_COUNT, "%d", getpid()); #endif } return pid_string; } static void log_source_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSource *self = (LogSource *) s; gint i; msg_set_context(msg); msg_diagnostics(">>>>>> Source side message processing begin", log_pipe_location_tag(s), evt_tag_msg_reference(msg)); /* $HOST setup */ log_source_mangle_hostname(self, msg); if (self->options->use_syslogng_pid) log_msg_set_value(msg, LM_V_PID, _get_pid_string(), -1); /* source specific tags */ if (self->options->tags) { for (i = 0; i < self->options->tags->len; i++) { log_msg_set_tag_by_id(msg, g_array_index(self->options->tags, LogTagId, i)); } } log_msg_set_tag_by_id(msg, self->options->source_group_tag); if (!_invoke_mangle_callbacks(s, msg, path_options)) return; if (self->options->host_override) log_source_override_host(self, msg); if (self->options->program_override) log_source_override_program(self, msg); msg_stats_update_counters(self->stats_id, msg); /* message setup finished, send it out */ stats_counter_inc(self->metrics.recvd_messages); stats_counter_set_time(self->metrics.last_message_seen, msg->timestamps[LM_TS_RECVD].ut_sec); stats_byte_counter_add(&self->metrics.recvd_bytes, msg->recvd_rawmsg_size); log_pipe_forward_msg(s, msg, path_options); if (accurate_nanosleep && self->threaded && self->window_full_sleep_nsec > 0 && !log_source_free_to_send(self)) { struct timespec ts; /* wait one 0.1msec in the hope that the buffer clears up */ ts.tv_sec = 0; ts.tv_nsec = self->window_full_sleep_nsec; nanosleep(&ts, NULL); } msg_diagnostics("<<<<<< Source side message processing finish", log_pipe_location_tag(s), evt_tag_msg_reference(msg)); msg_set_context(NULL); } static void _initialize_window(LogSource *self, gint init_window_size) { self->window_initialized = TRUE; window_size_counter_set(&self->window_size, init_window_size); self->initial_window_size = init_window_size; self->full_window_size = init_window_size; } static gboolean _is_window_initialized(LogSource *self) { return self->window_initialized; } static void _set_metric_options(LogSource *self, const gchar *stats_id, StatsClusterKeyBuilder *kb) { if (self->stats_id) g_free(self->stats_id); self->stats_id = stats_id ? g_strdup(stats_id) : NULL; if (self->metrics.stats_kb) stats_cluster_key_builder_free(self->metrics.stats_kb); if (!kb) kb = stats_cluster_key_builder_new(); self->metrics.stats_kb = kb; stats_cluster_key_builder_push(self->metrics.stats_kb); { gchar stats_instance[1024]; const gchar *instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); stats_cluster_key_builder_set_name(self->metrics.stats_kb, "input_events_total"); stats_cluster_key_builder_set_legacy_alias(self->metrics.stats_kb, self->options->stats_source | SCS_SOURCE, self->stats_id, instance_name); stats_cluster_key_builder_set_legacy_alias_name(self->metrics.stats_kb, "processed"); stats_cluster_key_builder_add_label(self->metrics.stats_kb, stats_cluster_label("id", self->stats_id)); self->metrics.recvd_messages_key = stats_cluster_key_builder_build_single(self->metrics.stats_kb); } stats_cluster_key_builder_pop(self->metrics.stats_kb); stats_cluster_key_builder_push(self->metrics.stats_kb); { stats_cluster_key_builder_set_name(self->metrics.stats_kb, "input_event_bytes_total");; stats_cluster_key_builder_add_label(self->metrics.stats_kb, stats_cluster_label("id", self->stats_id)); self->metrics.recvd_bytes_key = stats_cluster_key_builder_build_single(self->metrics.stats_kb); } stats_cluster_key_builder_pop(self->metrics.stats_kb); } void log_source_set_options(LogSource *self, LogSourceOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb, gboolean threaded, LogExprNode *expr_node) { /* NOTE: we don't adjust window_size even in case it was changed in the * configuration and we received a SIGHUP. This means that opened * connections will not have their window_size changed. */ if (!_is_window_initialized(self)) _initialize_window(self, options->init_window_size); self->options = options; _set_metric_options(self, stats_id, kb); self->threaded = threaded; log_pipe_detach_expr_node(&self->super); log_pipe_attach_expr_node(&self->super, expr_node); } void log_source_set_ack_tracker_factory(LogSource *self, AckTrackerFactory *factory) { ack_tracker_factory_unref(self->ack_tracker_factory); self->ack_tracker_factory = factory; } void log_source_set_name(LogSource *self, const gchar *name) { g_free(self->name); self->name = name ? g_strdup(name) : NULL; } void log_source_init_instance(LogSource *self, GlobalConfig *cfg) { log_pipe_init_instance(&self->super, cfg); self->super.queue = log_source_queue; self->super.free_fn = log_source_free; self->super.init = log_source_init; self->super.deinit = log_source_deinit; self->window_initialized = FALSE; self->ack_tracker_factory = instant_ack_tracker_bookmarkless_factory_new(); self->ack_tracker = NULL; } void log_source_free(LogPipe *s) { LogSource *self = (LogSource *) s; ack_tracker_free(self->ack_tracker); self->ack_tracker = NULL; g_free(self->name); g_free(self->stats_id); if (self->metrics.stats_kb) stats_cluster_key_builder_free(self->metrics.stats_kb); if (self->metrics.recvd_messages_key) stats_cluster_key_free(self->metrics.recvd_messages_key); if (self->metrics.recvd_bytes_key) stats_cluster_key_free(self->metrics.recvd_bytes_key); log_pipe_detach_expr_node(&self->super); log_pipe_free_method(s); ack_tracker_factory_unref(self->ack_tracker_factory); if (G_UNLIKELY(dynamic_window_is_enabled(&self->dynamic_window))) _release_dynamic_window(self); } void log_source_options_defaults(LogSourceOptions *options) { options->init_window_size = -1; options->keep_hostname = -1; options->chain_hostnames = -1; options->keep_timestamp = -1; options->program_override_len = -1; options->host_override_len = -1; options->tags = NULL; options->read_old_records = TRUE; host_resolve_options_defaults(&options->host_resolve_options); } /* NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy */ void log_source_options_init(LogSourceOptions *options, GlobalConfig *cfg, const gchar *group_name) { gchar *source_group_name; options->source_queue_callbacks = cfg->source_mangle_callback_list; if (options->init_window_size == -1) options->init_window_size = 100; if (options->keep_hostname == -1) options->keep_hostname = cfg->keep_hostname; if (options->chain_hostnames == -1) options->chain_hostnames = cfg->chain_hostnames; if (options->keep_timestamp == -1) options->keep_timestamp = cfg->keep_timestamp; options->group_name = group_name; source_group_name = g_strdup_printf(".source.%s", group_name); options->source_group_tag = log_tags_get_by_name(source_group_name); g_free(source_group_name); host_resolve_options_init(&options->host_resolve_options, &cfg->host_resolve_options); } void log_source_options_destroy(LogSourceOptions *options) { host_resolve_options_destroy(&options->host_resolve_options); if (options->program_override) g_free(options->program_override); if (options->host_override) g_free(options->host_override); if (options->tags) { g_array_free(options->tags, TRUE); options->tags = NULL; } } void log_source_options_set_tags(LogSourceOptions *options, GList *tags) { LogTagId id; if (!options->tags) options->tags = g_array_new(FALSE, FALSE, sizeof(LogTagId)); while (tags) { id = log_tags_get_by_name((gchar *) tags->data); g_array_append_val(options->tags, id); g_free(tags->data); tags = g_list_delete_link(tags, tags); } } void log_source_global_init(void) { accurate_nanosleep = check_nanosleep(); if (!accurate_nanosleep) { msg_debug("nanosleep() is not accurate enough to introduce minor stalls on the reader side, multi-threaded performance may be affected"); } } syslog-ng-syslog-ng-4.4.0/lib/logsource.h000066400000000000000000000122351450431004300202770ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGSOURCE_H_INCLUDED #define LOGSOURCE_H_INCLUDED #include "logpipe.h" #include "stats/stats-registry.h" #include "stats/stats-compat.h" #include "stats/stats-cluster-key-builder.h" #include "window-size-counter.h" #include "dynamic-window.h" typedef struct _LogSourceOptions { gssize init_window_size; const gchar *group_name; gboolean keep_timestamp; gboolean keep_hostname; gboolean chain_hostnames; HostResolveOptions host_resolve_options; gchar *program_override; gint program_override_len; gchar *host_override; gint host_override_len; LogTagId source_group_tag; gboolean read_old_records; gboolean use_syslogng_pid; GArray *tags; GList *source_queue_callbacks; gint stats_level; gint stats_source; } LogSourceOptions; typedef struct _LogSource LogSource; /** * LogSource: * * This structure encapsulates an object which generates messages without * defining how those messages are accepted by peers. The most prominent * derived class is LogReader which is an extended RFC3164 capable syslog * message processor used everywhere. **/ struct _LogSource { LogPipe super; LogSourceOptions *options; gboolean threaded; gchar *name; gchar *stats_id; WindowSizeCounter window_size; DynamicWindow dynamic_window; gboolean window_initialized; gsize initial_window_size; /* full_window_size = static + dynamic */ gsize full_window_size; atomic_gssize window_size_to_be_reclaimed; atomic_gssize pending_reclaimed; struct { StatsClusterKeyBuilder *stats_kb; StatsCounterItem *stat_window_size; StatsCounterItem *stat_full_window; StatsCounterItem *last_message_seen; StatsClusterKey *recvd_messages_key; StatsCounterItem *recvd_messages; gboolean raw_bytes_enabled; StatsClusterKey *recvd_bytes_key; StatsByteCounter recvd_bytes; StatsCluster *stat_window_size_cluster; StatsCluster *stat_full_window_cluster; } metrics; guint32 last_ack_count; guint32 ack_count; glong window_full_sleep_nsec; struct timespec last_ack_rate_time; AckTrackerFactory *ack_tracker_factory; AckTracker *ack_tracker; void (*wakeup)(LogSource *s); void (*schedule_dynamic_window_realloc)(LogSource *s); }; static inline gboolean log_source_free_to_send(LogSource *self) { return !window_size_counter_suspended(&self->window_size); } static inline gsize log_source_get_init_window_size(LogSource *self) { return self->initial_window_size; } static inline void log_source_schedule_dynamic_window_realloc(LogSource *s) { if (!s || !s->schedule_dynamic_window_realloc) return; s->schedule_dynamic_window_realloc(s); } gboolean log_source_init(LogPipe *s); gboolean log_source_deinit(LogPipe *s); void log_source_post(LogSource *self, LogMessage *msg); void log_source_set_options(LogSource *self, LogSourceOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb, gboolean threaded, LogExprNode *expr_node); void log_source_set_ack_tracker_factory(LogSource *self, AckTrackerFactory *factory); void log_source_set_name(LogSource *self, const gchar *name); void log_source_mangle_hostname(LogSource *self, LogMessage *msg); void log_source_init_instance(LogSource *self, GlobalConfig *cfg); void log_source_options_defaults(LogSourceOptions *options); void log_source_options_init(LogSourceOptions *options, GlobalConfig *cfg, const gchar *group_name); void log_source_options_destroy(LogSourceOptions *options); void log_source_options_set_tags(LogSourceOptions *options, GList *tags); void log_source_free(LogPipe *s); void log_source_wakeup(LogSource *self); void log_source_flow_control_adjust(LogSource *self, guint32 window_size_increment); void log_source_flow_control_adjust_when_suspended(LogSource *self, guint32 window_size_increment); void log_source_flow_control_suspend(LogSource *self); void log_source_disable_bookmark_saving(LogSource *self); void log_source_enable_dynamic_window(LogSource *self, DynamicWindowPool *window_ctr); void log_source_dynamic_window_update_statistics(LogSource *self); gboolean log_source_is_dynamic_window_enabled(LogSource *self); void log_source_global_init(void); /* protected */ void log_source_dynamic_window_realloc(LogSource *self); #endif syslog-ng-syslog-ng-4.4.0/lib/logthrdest/000077500000000000000000000000001450431004300203005ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logthrdest/CMakeLists.txt000066400000000000000000000002571450431004300230440ustar00rootroot00000000000000set(LOGTHRDEST_HEADERS logthrdest/logthrdestdrv.h PARENT_SCOPE) set(LOGTHRDEST_SOURCES logthrdest/logthrdestdrv.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/logthrdest/Makefile.am000066400000000000000000000004031450431004300223310ustar00rootroot00000000000000logthrdestincludedir = ${pkgincludedir}/logthrdest EXTRA_DIST += lib/logthrdest/CMakeLists.txt logthrdestinclude_HEADERS = \ lib/logthrdest/logthrdestdrv.h logthrdest_sources = \ lib/logthrdest/logthrdestdrv.c include lib/logthrdest/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/logthrdest/logthrdestdrv.c000066400000000000000000001321141450431004300233410ustar00rootroot00000000000000/* * Copyright (c) 2013, 2014 Balabit * Copyright (c) 2013, 2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-cluster-logpipe.h" #include "stats/stats-cluster-single.h" #include "stats/aggregator/stats-aggregator-registry.h" #include "logthrdestdrv.h" #include "seqnum.h" #include "scratch-buffers.h" #include "template/eval.h" #include "mainloop-threaded-worker.h" #include #define MAX_RETRIES_ON_ERROR_DEFAULT 3 #define MAX_RETRIES_BEFORE_SUSPEND_DEFAULT 3 const gchar * log_threaded_result_to_str(LogThreadedResult self) { g_assert(self <= LTR_MAX); static const gchar *as_str[] = { "DROP", "ERROR", "EXPLICIT_ACK_MGMT", "SUCCESS", "QUEUED", "NOT_CONNECTED", "RETRY", "MAX" }; return as_str[self]; } /* LogThreadedDestWorker */ void log_threaded_dest_driver_set_batch_lines(LogDriver *s, gint batch_lines) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; self->batch_lines = batch_lines; } void log_threaded_dest_driver_set_batch_timeout(LogDriver *s, gint batch_timeout) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; self->batch_timeout = batch_timeout; } void log_threaded_dest_driver_set_time_reopen(LogDriver *s, time_t time_reopen) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; self->time_reopen = time_reopen; } /* this should be used in combination with LTR_EXPLICIT_ACK_MGMT to actually confirm message delivery. */ void log_threaded_dest_worker_ack_messages(LogThreadedDestWorker *self, gint batch_size) { log_queue_ack_backlog(self->queue, batch_size); stats_counter_add(self->owner->metrics.written_messages, batch_size); self->retries_on_error_counter = 0; self->batch_size -= batch_size; } void log_threaded_dest_worker_drop_messages(LogThreadedDestWorker *self, gint batch_size) { log_queue_ack_backlog(self->queue, batch_size); stats_counter_add(self->owner->metrics.dropped_messages, batch_size); self->retries_on_error_counter = 0; self->batch_size -= batch_size; } void log_threaded_dest_worker_rewind_messages(LogThreadedDestWorker *self, gint batch_size) { log_queue_rewind_backlog(self->queue, batch_size); self->rewound_batch_size = self->batch_size; self->batch_size -= batch_size; } static gchar * _format_queue_persist_name(LogThreadedDestWorker *self) { LogPipe *owner = &self->owner->super.super.super; if (self->worker_index == 0) { /* the first worker uses the legacy persist name, e.g. to be able to * recover the queue previously used. */ return g_strdup(log_pipe_get_persist_name(owner)); } else { return g_strdup_printf("%s.%d.queue", log_pipe_get_persist_name(owner), self->worker_index); } } static gboolean _should_flush_now(LogThreadedDestWorker *self) { struct timespec now; glong diff; if (self->owner->batch_timeout <= 0 || self->owner->batch_lines <= 1 || !self->enable_batching) return TRUE; iv_validate_now(); now = iv_now; diff = timespec_diff_msec(&now, &self->last_flush_time); return (diff >= self->owner->batch_timeout); } static void _stop_watches(LogThreadedDestWorker *self) { if (iv_task_registered(&self->do_work)) { iv_task_unregister(&self->do_work); } if (iv_timer_registered(&self->timer_reopen)) { iv_timer_unregister(&self->timer_reopen); } if (iv_timer_registered(&self->timer_throttle)) { iv_timer_unregister(&self->timer_throttle); } if (iv_timer_registered(&self->timer_flush)) { iv_timer_unregister(&self->timer_flush); } } /* NOTE: runs in the worker thread in response to a wakeup event being * posted, which happens if a new element is added to our queue while we * were sleeping */ static void _wakeup_event_callback(gpointer data) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) data; if (!iv_task_registered(&self->do_work)) { iv_task_register(&self->do_work); } } /* NOTE: runs in the worker thread in response to the shutdown event being * posted. The shutdown event is initiated by the mainloop when the * configuration is deinited */ static void _shutdown_event_callback(gpointer data) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) data; log_queue_reset_parallel_push(self->queue); _stop_watches(self); iv_quit(); } /* NOTE: runs in the worker thread */ static void _suspend(LogThreadedDestWorker *self) { self->suspended = TRUE; } /* NOTE: runs in the worker thread */ static void _connect(LogThreadedDestWorker *self) { if (!log_threaded_dest_worker_connect(self)) { msg_debug("Error establishing connection to server", evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index), log_expr_node_location_tag(self->owner->super.super.super.expr_node)); _suspend(self); } } /* NOTE: runs in the worker thread */ static void _disconnect(LogThreadedDestWorker *self) { log_threaded_dest_worker_disconnect(self); } /* NOTE: runs in the worker thread */ static void _disconnect_and_suspend(LogThreadedDestWorker *self) { _disconnect(self); _suspend(self); } /* Accepts the current batch including the current message by acking it back * to the source. * * NOTE: runs in the worker thread */ static void _accept_batch(LogThreadedDestWorker *self) { log_threaded_dest_worker_ack_messages(self, self->batch_size); } /* NOTE: runs in the worker thread */ static void _drop_batch(LogThreadedDestWorker *self) { log_threaded_dest_worker_drop_messages(self, self->batch_size); } /* NOTE: runs in the worker thread */ static void _rewind_batch(LogThreadedDestWorker *self) { log_threaded_dest_worker_rewind_messages(self, self->batch_size); } static void _process_result_drop(LogThreadedDestWorker *self) { msg_error("Message(s) dropped while sending message to destination", evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index), evt_tag_int("time_reopen", self->time_reopen), evt_tag_int("batch_size", self->batch_size)); _drop_batch(self); _disconnect_and_suspend(self); } static void _process_result_error(LogThreadedDestWorker *self) { self->retries_on_error_counter++; if (self->retries_on_error_counter >= self->owner->retries_on_error_max) { msg_error("Multiple failures while sending message(s) to destination, message(s) dropped", evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node), evt_tag_int("worker_index", self->worker_index), evt_tag_int("retries", self->retries_on_error_counter), evt_tag_int("batch_size", self->batch_size)); _drop_batch(self); } else { msg_error("Error occurred while trying to send a message, trying again", evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node), evt_tag_int("worker_index", self->worker_index), evt_tag_int("retries", self->retries_on_error_counter), evt_tag_int("time_reopen", self->time_reopen), evt_tag_int("batch_size", self->batch_size)); _rewind_batch(self); _disconnect_and_suspend(self); } } static void _process_result_not_connected(LogThreadedDestWorker *self) { msg_info("Server disconnected while preparing messages for sending, trying again", evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node), evt_tag_int("worker_index", self->worker_index), evt_tag_int("time_reopen", self->time_reopen), evt_tag_int("batch_size", self->batch_size)); self->retries_counter = 0; _rewind_batch(self); _disconnect_and_suspend(self); } static void _process_result_success(LogThreadedDestWorker *self) { _accept_batch(self); } static void _process_result_queued(LogThreadedDestWorker *self) { self->enable_batching = TRUE; } static void _process_result_retry(LogThreadedDestWorker *self) { self->retries_counter++; if (self->retries_counter >= self->owner->retries_max) _process_result_not_connected(self); else _rewind_batch(self); } static void _process_result(LogThreadedDestWorker *self, gint result) { switch (result) { case LTR_DROP: _process_result_drop(self); break; case LTR_ERROR: _process_result_error(self); break; case LTR_NOT_CONNECTED: _process_result_not_connected(self); break; case LTR_EXPLICIT_ACK_MGMT: /* we require the instance to use explicit calls to ack_messages/rewind_messages */ break; case LTR_SUCCESS: _process_result_success(self); break; case LTR_QUEUED: _process_result_queued(self); break; case LTR_RETRY: _process_result_retry(self); break; default: break; } } static LogThreadedResult _perform_flush(LogThreadedDestWorker *self) { LogThreadedResult result = LTR_SUCCESS; /* NOTE: earlier we had a condition on only calling flush() if batch_size * is non-zero. This was removed, as the language bindings that were done * _before_ the batching support in LogThreadedDestDriver relies on * flush() being called always, even if LTR_SUCCESS is * returned, in which case batch_size is already zero at this point. */ if (!self->suspended) { msg_trace("Flushing batch", evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index), evt_tag_int("batch_size", self->batch_size)); result = log_threaded_dest_worker_flush(self, LTF_FLUSH_NORMAL); _process_result(self, result); } iv_invalidate_now(); return result; } static inline gboolean _flush_on_worker_partition_key_change_enabled(LogThreadedDestWorker *self) { return self->owner->flush_on_key_change && self->owner->worker_partition_key; } static inline gboolean _should_flush_due_to_partition_key_change(LogThreadedDestWorker *self, LogMessage *msg) { GString *buffer = scratch_buffers_alloc(); LogTemplateEvalOptions options = DEFAULT_TEMPLATE_EVAL_OPTIONS; log_template_format(self->owner->worker_partition_key, msg, &options, buffer); gboolean should_flush = self->batch_size != 0 && strcmp(self->partitioning.last_key->str, buffer->str) != 0; g_string_assign(self->partitioning.last_key, buffer->str); return should_flush; } /* NOTE: runs in the worker thread, whenever items on our queue are * available. It iterates all elements on the queue, however will terminate * if the mainloop requests that we exit. */ static void _perform_inserts(LogThreadedDestWorker *self) { LogThreadedResult result; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; if (self->batch_size == 0) { /* first message in the batch sets the last_flush_time, so we * won't expedite the flush even if the previous one was a long * time ago */ iv_validate_now(); self->last_flush_time = iv_now; } while (G_LIKELY(!self->owner->under_termination) && !self->suspended) { ScratchBuffersMarker mark; scratch_buffers_mark(&mark); if (G_UNLIKELY(_flush_on_worker_partition_key_change_enabled(self))) { LogMessage *msg = log_queue_peek_head(self->queue); if (!msg) { scratch_buffers_reclaim_marked(mark); break; } if (_should_flush_due_to_partition_key_change(self, msg)) { gboolean flush_result = _perform_flush(self); if (flush_result != LTR_SUCCESS && flush_result != LTR_EXPLICIT_ACK_MGMT) goto flush_error; } } LogMessage *msg = log_queue_pop_head(self->queue, &path_options); if (!msg) { scratch_buffers_reclaim_marked(mark); break; } msg_set_context(msg); log_msg_refcache_start_consumer(msg, &path_options); self->batch_size++; result = log_threaded_dest_worker_insert(self, msg); _process_result(self, result); if (self->enable_batching && self->batch_size >= self->owner->batch_lines) _perform_flush(self); log_msg_unref(msg); msg_set_context(NULL); log_msg_refcache_stop(); flush_error: scratch_buffers_reclaim_marked(mark); if (self->rewound_batch_size) { self->rewound_batch_size--; if (self->rewound_batch_size == 0) break; } iv_invalidate_now(); } self->rewound_batch_size = 0; } /* this callback is invoked by LogQueue and is registered using * log_queue_check_items(). This only gets registered if at that point * we've decided to wait for the queue, e.g. the work_task is not running. * * This callback is invoked from the source thread, e.g. it is not safe to * do anything, but ensure that our thread is woken up in response. */ static void _message_became_available_callback(gpointer user_data) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) user_data; if (!self->owner->under_termination) iv_event_post(&self->wake_up_event); } static void _schedule_restart_on_suspend_timeout(LogThreadedDestWorker *self) { iv_validate_now(); self->timer_reopen.expires = iv_now; self->timer_reopen.expires.tv_sec += self->time_reopen; iv_timer_register(&self->timer_reopen); } static void _schedule_restart_on_batch_timeout(LogThreadedDestWorker *self) { self->timer_flush.expires = self->last_flush_time; timespec_add_msec(&self->timer_flush.expires, self->owner->batch_timeout); iv_timer_register(&self->timer_flush); } static void _schedule_restart(LogThreadedDestWorker *self) { if (self->suspended) _schedule_restart_on_suspend_timeout(self); else iv_task_register(&self->do_work); } static void _schedule_restart_on_next_flush(LogThreadedDestWorker *self) { if (self->suspended) _schedule_restart_on_suspend_timeout(self); else if (!_should_flush_now(self)) _schedule_restart_on_batch_timeout(self); else iv_task_register(&self->do_work); } static void _schedule_restart_on_throttle_timeout(LogThreadedDestWorker *self, gint timeout_msec) { iv_validate_now(); self->timer_throttle.expires = iv_now; timespec_add_msec(&self->timer_throttle.expires, timeout_msec); iv_timer_register(&self->timer_throttle); } static void _perform_work(gpointer data) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) data; gint timeout_msec = 0; self->suspended = FALSE; main_loop_worker_run_gc(); _stop_watches(self); if (!self->connected) { /* try to connect and come back if successful, would be suspended otherwise. */ _connect(self); _schedule_restart(self); } else if (log_queue_check_items(self->queue, &timeout_msec, _message_became_available_callback, self, NULL)) { msg_trace("Message(s) available in queue, starting inserts", evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index)); /* Something is in the queue, buffer them up and flush (if needed) */ _perform_inserts(self); if (_should_flush_now(self)) _perform_flush(self); _schedule_restart(self); } else if (self->batch_size > 0) { /* nothing in the queue, but there are pending elements in the buffer * (e.g. batch size != 0). perform a round of flushing. We might * get back here, as the flush() routine doesn't have to flush * everything. We are awoken either by the * _message_became_available_callback() or if the next flush time has * arrived. */ gboolean should_flush = _should_flush_now(self); msg_trace("Queue empty, flushing previously buffered data if needed", evt_tag_str("should_flush", should_flush ? "YES" : "NO"), evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index), evt_tag_int("batch_size", self->batch_size)); if (should_flush) _perform_flush(self); _schedule_restart_on_next_flush(self); } else if (timeout_msec != 0) { /* We probably have some items in the queue, but timeout_msec is set, * indicating a throttle being active. * _message_became_available_callback() is not set up in this case. * we need to wake up after timeout_msec time. * * We are processing throttle delays _after_ we finished flushing, as * items in the queue were already accepted by throttling, so they can * be flushed. */ msg_trace("Delaying output due to throttling", evt_tag_int("timeout_msec", timeout_msec), evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index)); _schedule_restart_on_throttle_timeout(self, timeout_msec); } else { /* NOTE: at this point we are not doing anything but keep the * parallel_push callback alive, which will call * _message_became_available_callback(), which in turn wakes us up by * posting an event which causes this function to be run again * * NOTE/2: the parallel_push callback may need to be cancelled if we * need to exit. That happens in the shutdown_event_callback(), or * here in this very function, as log_queue_check_items() will cancel * outstanding parallel push callbacks automatically. */ } } void log_threaded_dest_worker_wakeup_when_suspended(LogThreadedDestWorker *self) { if (self->suspended) _perform_work(self); } static void _flush_timer_cb(gpointer data) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) data; msg_trace("Flush timer expired", evt_tag_str("driver", self->owner->super.super.id), evt_tag_int("worker_index", self->worker_index), evt_tag_int("batch_size", self->batch_size)); _perform_work(data); } /* these are events of the _worker_ thread and are not registered to the * actual main thread. We basically run our workload in the handler of the * do_work task, which might be invoked in a number of ways. * * Basic states: * 1) disconnected state: _perform_work() will try to connect periodically * using the suspend() mechanism, which uses a timer to get up periodically. * * 2) once connected: * - if messages are already on the queue: flush them * * - if no messages are on the queue: schedule * _message_became_available_callback() to be called by the LogQueue. * * - if there's an error, disconnect go back to the #1 state above. * */ static void _init_watches(LogThreadedDestWorker *self) { IV_EVENT_INIT(&self->wake_up_event); self->wake_up_event.cookie = self; self->wake_up_event.handler = _wakeup_event_callback; IV_EVENT_INIT(&self->shutdown_event); self->shutdown_event.cookie = self; self->shutdown_event.handler = _shutdown_event_callback; IV_TIMER_INIT(&self->timer_reopen); self->timer_reopen.cookie = self; self->timer_reopen.handler = _perform_work; IV_TIMER_INIT(&self->timer_throttle); self->timer_throttle.cookie = self; self->timer_throttle.handler = _perform_work; IV_TIMER_INIT(&self->timer_flush); self->timer_flush.cookie = self; self->timer_flush.handler = _flush_timer_cb; IV_TASK_INIT(&self->do_work); self->do_work.cookie = self; self->do_work.handler = _perform_work; } static void _perform_final_flush(LogThreadedDestWorker *self) { GlobalConfig *cfg = log_pipe_get_config(&self->owner->super.super.super); LogThreadedResult result; LogThreadedFlushMode mode = LTF_FLUSH_NORMAL; if (!cfg_is_shutting_down(cfg)) mode = LTF_FLUSH_EXPEDITE; result = log_threaded_dest_worker_flush(self, mode); _process_result(self, result); log_queue_rewind_backlog_all(self->queue); } static gboolean _worker_thread_init(MainLoopThreadedWorker *s) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) s->data; iv_event_register(&self->wake_up_event); iv_event_register(&self->shutdown_event); return log_threaded_dest_worker_init(self); } static void _worker_thread_deinit(MainLoopThreadedWorker *s) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) s->data; log_threaded_dest_worker_deinit(self); iv_event_unregister(&self->wake_up_event); iv_event_unregister(&self->shutdown_event); } static void _worker_thread(MainLoopThreadedWorker *s) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) s->data; msg_debug("Dedicated worker thread started", evt_tag_int("worker_index", self->worker_index), evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node)); /* if we have anything on the backlog, that was a partial, potentially * not-flushed batch. Rewind it, so we start with that */ log_queue_rewind_backlog_all(self->queue); _schedule_restart(self); iv_main(); _perform_final_flush(self); _disconnect(self); msg_debug("Dedicated worker thread finished", evt_tag_int("worker_index", self->worker_index), evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node)); } static void _request_worker_exit(MainLoopThreadedWorker *s) { LogThreadedDestWorker *self = (LogThreadedDestWorker *) s->data; msg_debug("Shutting down dedicated worker thread", evt_tag_int("worker_index", self->worker_index), evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node)); self->owner->under_termination = TRUE; iv_event_post(&self->shutdown_event); } static gboolean log_threaded_dest_worker_start(LogThreadedDestWorker *self) { msg_debug("Starting dedicated worker thread", evt_tag_int("worker_index", self->worker_index), evt_tag_str("driver", self->owner->super.super.id), log_expr_node_location_tag(self->owner->super.super.super.expr_node)); return main_loop_threaded_worker_start(&self->thread); } static void _format_stats_key(LogThreadedDestDriver *self, StatsClusterKeyBuilder *kb) { self->format_stats_key(self, kb); } static const gchar * _format_legacy_stats_instance(LogThreadedDestDriver *self, StatsClusterKeyBuilder *kb) { const gchar *legacy_stats_instance = self->format_stats_key(self, kb); if (legacy_stats_instance) return legacy_stats_instance; static gchar stats_instance[1024]; stats_cluster_key_builder_format_legacy_stats_instance(kb, stats_instance, sizeof(stats_instance)); return stats_instance; } static void _init_worker_sck_builder(LogThreadedDestWorker *self, StatsClusterKeyBuilder *builder) { stats_cluster_key_builder_add_label(builder, stats_cluster_label("id", self->owner->super.super.id ? : "")); _format_stats_key(self->owner, builder); gchar worker_index_str[8]; g_snprintf(worker_index_str, sizeof(worker_index_str), "%d", self->worker_index); stats_cluster_key_builder_add_label(builder, stats_cluster_label("worker", worker_index_str)); } static gboolean _acquire_worker_queue(LogThreadedDestWorker *self, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder) { gchar *persist_name = _format_queue_persist_name(self); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); _init_worker_sck_builder(self, queue_sck_builder); self->queue = log_dest_driver_acquire_queue(&self->owner->super, persist_name, stats_level, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); g_free(persist_name); if (!self->queue) return FALSE; return TRUE; } static void _register_worker_stats(LogThreadedDestWorker *self) { gint level = log_pipe_is_internal(&self->owner->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL1; StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); stats_cluster_key_builder_push(kb); { stats_cluster_key_builder_add_label(kb, stats_cluster_label("id", self->owner->super.super.id ? : "")); _format_stats_key(self->owner, kb); if (self->owner->metrics.raw_bytes_enabled) { stats_cluster_key_builder_set_name(kb, "output_event_bytes_total"); self->metrics.output_event_bytes_sc_key = stats_cluster_key_builder_build_single(kb); stats_byte_counter_init(&self->metrics.written_bytes, self->metrics.output_event_bytes_sc_key, level, SBCP_KIB); } } stats_cluster_key_builder_pop(kb); stats_cluster_key_builder_push(kb); { _init_worker_sck_builder(self, kb); stats_lock(); { /* Up to 49 days and 17 hours on 32 bit machines. */ stats_cluster_key_builder_set_name(kb, "output_event_delay_sample_seconds"); stats_cluster_key_builder_set_unit(kb, SCU_MILLISECONDS); self->metrics.message_delay_sample_key = stats_cluster_key_builder_build_single(kb); stats_register_counter(level, self->metrics.message_delay_sample_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample); stats_cluster_key_builder_set_name(kb, "output_event_delay_sample_age_seconds"); stats_cluster_key_builder_set_unit(kb, SCU_SECONDS); stats_cluster_key_builder_set_frame_of_reference(kb, SCFOR_RELATIVE_TO_TIME_OF_QUERY); self->metrics.message_delay_sample_age_key = stats_cluster_key_builder_build_single(kb); stats_register_counter(level, self->metrics.message_delay_sample_age_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample_age); } stats_unlock(); } stats_cluster_key_builder_pop(kb); UnixTime now; unix_time_set_now(&now); stats_counter_set_time(self->metrics.message_delay_sample_age, now.ut_sec); self->metrics.last_delay_update = now.ut_sec; stats_cluster_key_builder_free(kb); } static void _unregister_worker_stats(LogThreadedDestWorker *self) { if (self->metrics.output_event_bytes_sc_key) { stats_byte_counter_deinit(&self->metrics.written_bytes, self->metrics.output_event_bytes_sc_key); stats_cluster_key_free(self->metrics.output_event_bytes_sc_key); self->metrics.output_event_bytes_sc_key = NULL; } stats_lock(); { if (self->metrics.message_delay_sample_key) { stats_unregister_counter(self->metrics.message_delay_sample_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample); stats_cluster_key_free(self->metrics.message_delay_sample_key); self->metrics.message_delay_sample_key = NULL; } if (self->metrics.message_delay_sample_age_key) { stats_unregister_counter(self->metrics.message_delay_sample_age_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample_age); stats_cluster_key_free(self->metrics.message_delay_sample_age_key); self->metrics.message_delay_sample_age_key = NULL; } } stats_unlock(); } gboolean log_threaded_dest_worker_init_method(LogThreadedDestWorker *self) { if (self->time_reopen == -1) self->time_reopen = self->owner->time_reopen; if (self->owner->flush_on_key_change) self->partitioning.last_key = g_string_sized_new(128); return TRUE; } void log_threaded_dest_worker_deinit_method(LogThreadedDestWorker *self) { if (self->partitioning.last_key) g_string_free(self->partitioning.last_key, TRUE); } void log_threaded_dest_worker_free_method(LogThreadedDestWorker *self) { _unregister_worker_stats(self); main_loop_threaded_worker_clear(&self->thread); } void log_threaded_dest_worker_init_instance(LogThreadedDestWorker *self, LogThreadedDestDriver *owner, gint worker_index) { main_loop_threaded_worker_init(&self->thread, MLW_THREADED_OUTPUT_WORKER, self); self->thread.thread_init = _worker_thread_init; self->thread.thread_deinit = _worker_thread_deinit; self->thread.run = _worker_thread; self->thread.request_exit = _request_worker_exit; self->worker_index = worker_index; self->init = log_threaded_dest_worker_init_method; self->deinit = log_threaded_dest_worker_deinit_method; self->free_fn = log_threaded_dest_worker_free_method; self->owner = owner; self->time_reopen = -1; self->partitioning.last_key = NULL; _init_watches(self); /* cannot be moved to the thread's init() as neither StatsByteCounter nor format_stats_key() is thread-safe */ _register_worker_stats(self); } void log_threaded_dest_worker_free(LogThreadedDestWorker *self) { if (self->free_fn) self->free_fn(self); g_free(self); } /* LogThreadedDestDriver */ void log_threaded_dest_driver_set_num_workers(LogDriver *s, gint num_workers) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; self->num_workers = num_workers; } void log_threaded_dest_driver_set_worker_partition_key_ref(LogDriver *s, LogTemplate *key) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; log_template_unref(self->worker_partition_key); self->worker_partition_key = key; } void log_threaded_dest_driver_set_flush_on_worker_key_change(LogDriver *s, gboolean f) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; self->flush_on_key_change = f; } /* compatibility bridge between LogThreadedDestWorker */ static gboolean _compat_init(LogThreadedDestWorker *self) { if (!log_threaded_dest_worker_init_method(self)) return FALSE; /* NOTE: driver level thread_init() didn't have a gboolean return */ if (self->owner->worker.thread_init) self->owner->worker.thread_init(self->owner); return TRUE; } static void _compat_deinit(LogThreadedDestWorker *self) { if (self->owner->worker.thread_deinit) self->owner->worker.thread_deinit(self->owner); log_threaded_dest_worker_deinit_method(self); } static gboolean _compat_connect(LogThreadedDestWorker *self) { if (self->owner->worker.connect) return self->owner->worker.connect(self->owner); return TRUE; } static void _compat_disconnect(LogThreadedDestWorker *self) { if (self->owner->worker.disconnect) self->owner->worker.disconnect(self->owner); } static LogThreadedResult _compat_insert(LogThreadedDestWorker *self, LogMessage *msg) { return self->owner->worker.insert(self->owner, msg); } static LogThreadedResult _compat_flush(LogThreadedDestWorker *self, LogThreadedFlushMode mode) { if (self->owner->worker.flush) return self->owner->worker.flush(self->owner); return LTR_SUCCESS; } static gboolean _is_worker_compat_mode(LogThreadedDestDriver *self) { return !self->worker.construct; } static LogThreadedDestWorker * _init_compat_worker(LogThreadedDestDriver *self) { LogThreadedDestWorker *worker = &self->worker.instance; log_threaded_dest_worker_init_instance(worker, self, 0); worker->init = _compat_init; worker->deinit = _compat_deinit; worker->connect = _compat_connect; worker->disconnect = _compat_disconnect; worker->insert = _compat_insert; worker->flush = _compat_flush; return worker; } static LogThreadedDestWorker * _construct_worker(LogThreadedDestDriver *self, gint worker_index) { if (_is_worker_compat_mode(self)) { /* kick in the compat layer, this case self->worker.instance is the * single worker we have and all Worker related state is in the * (derived) Driver class. */ return _init_compat_worker(self); } return self->worker.construct(self, worker_index); } void log_threaded_dest_driver_set_max_retries_on_error(LogDriver *s, gint max_retries) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; self->retries_on_error_max = max_retries; } LogThreadedDestWorker * _lookup_worker(LogThreadedDestDriver *self, LogMessage *msg) { if (self->worker_partition_key) { LogTemplateEvalOptions options = DEFAULT_TEMPLATE_EVAL_OPTIONS; guint worker_index = log_template_hash(self->worker_partition_key, msg, &options) % self->num_workers; return self->workers[worker_index]; } guint worker_index = self->last_worker; self->last_worker = (self->last_worker + 1) % self->num_workers; return self->workers[worker_index]; } /* the feeding side of the driver, runs in the source thread and puts an * incoming message to the associated queue. */ static void log_threaded_dest_driver_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; LogThreadedDestWorker *dw = _lookup_worker(self, msg); LogPathOptions local_options; if (!path_options->flow_control_requested) path_options = log_msg_break_ack(msg, path_options, &local_options); log_msg_add_ack(msg, path_options); log_queue_push_tail(dw->queue, log_msg_ref(msg), path_options); stats_counter_inc(self->metrics.processed_messages); log_dest_driver_queue_method(s, msg, path_options); } void log_threaded_dest_worker_written_bytes_add(LogThreadedDestWorker *self, gsize b) { stats_byte_counter_add(&self->metrics.written_bytes, b); } void log_threaded_dest_driver_insert_msg_length_stats(LogThreadedDestDriver *self, gsize len) { stats_aggregator_add_data_point(self->metrics.max_message_size, len); stats_aggregator_add_data_point(self->metrics.average_messages_size, len); } void log_threaded_dest_driver_insert_batch_length_stats(LogThreadedDestDriver *self, gsize len) { stats_aggregator_add_data_point(self->metrics.max_batch_size, len); stats_aggregator_add_data_point(self->metrics.average_batch_size, len); } void log_threaded_dest_driver_register_aggregated_stats(LogThreadedDestDriver *self) { gint level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL0; StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); const gchar *legacy_stats_instance = _format_legacy_stats_instance(self, kb); stats_cluster_key_builder_free(kb); StatsClusterKey sc_key_eps_input; stats_cluster_logpipe_key_legacy_set(&sc_key_eps_input, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance); stats_aggregator_lock(); StatsClusterKey sc_key; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance, "msg_size_max"); stats_register_aggregator_maximum(level, &sc_key, &self->metrics.max_message_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance, "msg_size_avg"); stats_register_aggregator_average(level, &sc_key, &self->metrics.average_messages_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance, "batch_size_max"); stats_register_aggregator_maximum(level, &sc_key, &self->metrics.max_batch_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance, "batch_size_avg"); stats_register_aggregator_average(level, &sc_key, &self->metrics.average_batch_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance, "eps"); stats_register_aggregator_cps(level, &sc_key, &sc_key_eps_input, SC_TYPE_WRITTEN, &self->metrics.CPS); stats_aggregator_unlock(); } void log_threaded_dest_driver_unregister_aggregated_stats(LogThreadedDestDriver *self) { stats_aggregator_lock(); stats_unregister_aggregator(&self->metrics.max_message_size); stats_unregister_aggregator(&self->metrics.average_messages_size); stats_unregister_aggregator(&self->metrics.max_batch_size); stats_unregister_aggregator(&self->metrics.average_batch_size); stats_unregister_aggregator(&self->metrics.CPS); stats_aggregator_unlock(); } static void _register_driver_stats(LogThreadedDestDriver *self, StatsClusterKeyBuilder *driver_sck_builder) { if (!driver_sck_builder) return; gint level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL0; stats_cluster_key_builder_push(driver_sck_builder); { stats_cluster_key_builder_set_name(driver_sck_builder, "output_events_total"); self->metrics.output_events_sc_key = stats_cluster_key_builder_build_logpipe(driver_sck_builder); } stats_cluster_key_builder_pop(driver_sck_builder); stats_cluster_key_builder_push(driver_sck_builder); { stats_cluster_key_builder_set_legacy_alias(driver_sck_builder, self->stats_source | SCS_DESTINATION, self->super.super.id, _format_legacy_stats_instance(self, driver_sck_builder)); stats_cluster_key_builder_set_legacy_alias_name(driver_sck_builder, "processed"); self->metrics.processed_sc_key = stats_cluster_key_builder_build_single(driver_sck_builder); } stats_cluster_key_builder_pop(driver_sck_builder); stats_lock(); { stats_register_counter(level, self->metrics.output_events_sc_key, SC_TYPE_DROPPED, &self->metrics.dropped_messages); stats_register_counter(level, self->metrics.output_events_sc_key, SC_TYPE_WRITTEN, &self->metrics.written_messages); stats_register_counter(level, self->metrics.processed_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.processed_messages); } stats_unlock(); } static void _init_driver_sck_builder(LogThreadedDestDriver *self, StatsClusterKeyBuilder *builder) { stats_cluster_key_builder_add_label(builder, stats_cluster_label("id", self->super.super.id ? : "")); const gchar *legacy_stats_instance = _format_legacy_stats_instance(self, builder); stats_cluster_key_builder_set_legacy_alias(builder, self->stats_source | SCS_DESTINATION, self->super.super.id, legacy_stats_instance); } static void _unregister_driver_stats(LogThreadedDestDriver *self) { stats_lock(); { if (self->metrics.output_events_sc_key) { stats_unregister_counter(self->metrics.output_events_sc_key, SC_TYPE_DROPPED, &self->metrics.dropped_messages); stats_unregister_counter(self->metrics.output_events_sc_key, SC_TYPE_WRITTEN, &self->metrics.written_messages); stats_cluster_key_free(self->metrics.output_events_sc_key); self->metrics.output_events_sc_key = NULL; } if (self->metrics.processed_sc_key) { stats_unregister_counter(self->metrics.processed_sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.processed_messages); stats_cluster_key_free(self->metrics.processed_sc_key); self->metrics.processed_sc_key = NULL; } } stats_unlock(); } static gchar * _format_seqnum_persist_name(LogThreadedDestDriver *self) { static gchar persist_name[256]; g_snprintf(persist_name, sizeof(persist_name), "%s.seqnum", self->super.super.super.generate_persist_name((const LogPipe *)self)); return persist_name; } static gboolean _create_workers(LogThreadedDestDriver *self, gint stats_level, StatsClusterKeyBuilder *driver_sck_builder) { /* free previous workers array if set to cope with num_workers change */ g_free(self->workers); self->workers = g_new0(LogThreadedDestWorker *, self->num_workers); for (self->created_workers = 0; self->created_workers < self->num_workers; self->created_workers++) { LogThreadedDestWorker *dw = _construct_worker(self, self->created_workers); self->workers[self->created_workers] = dw; if (!_acquire_worker_queue(dw, stats_level, driver_sck_builder)) return FALSE; } return TRUE; } gboolean log_threaded_dest_driver_pre_config_init(LogPipe *s) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; main_loop_worker_allocate_thread_space(self->num_workers); return TRUE; } gboolean log_threaded_dest_driver_init_method(LogPipe *s) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_dest_driver_init_method(&self->super.super.super)) return FALSE; self->under_termination = FALSE; if (self->time_reopen == -1) self->time_reopen = cfg->time_reopen; gpointer persisted_value = cfg_persist_config_fetch(cfg, _format_seqnum_persist_name(self)); self->shared_seq_num = GPOINTER_TO_INT(persisted_value); if (!self->shared_seq_num) init_sequence_number(&self->shared_seq_num); if (self->worker_partition_key && log_template_is_literal_string(self->worker_partition_key)) { msg_error("worker-partition-key() should not be literal string, use macros to form proper partitions", log_expr_node_location_tag(self->super.super.super.expr_node)); return FALSE; } StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); _init_driver_sck_builder(self, driver_sck_builder); gint stats_level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL0; if (!_create_workers(self, stats_level, driver_sck_builder)) { stats_cluster_key_builder_free(driver_sck_builder); return FALSE; } _register_driver_stats(self, driver_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); return TRUE; } /* This method is only used when a LogThreadedDestDriver is directly used * without overriding its post_config_init method. If there's an overridden * method, the caller is responsible for explicitly calling _start_workers() at * the end of post_config_init(). */ gboolean log_threaded_dest_driver_start_workers(LogPipe *s) { LogThreadedDestDriver *self = (LogThreadedDestDriver *) s; for (gint worker_index = 0; worker_index < self->num_workers; worker_index++) { if (!log_threaded_dest_worker_start(self->workers[worker_index])) return FALSE; } return TRUE; } static void _destroy_worker(LogThreadedDestDriver *self, LogThreadedDestWorker *worker) { if (_is_worker_compat_mode(self)) log_threaded_dest_worker_free_method(&self->worker.instance); else log_threaded_dest_worker_free(worker); } static void _destroy_workers(LogThreadedDestDriver *self) { for (int i = 0; i < self->created_workers; i++) _destroy_worker(self, self->workers[i]); } gboolean log_threaded_dest_driver_deinit_method(LogPipe *s) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; /* NOTE: workers are shut down by the time we get here, through the * request_exit mechanism of main loop worker threads */ cfg_persist_config_add(log_pipe_get_config(s), _format_seqnum_persist_name(self), GINT_TO_POINTER(self->shared_seq_num), NULL); _unregister_driver_stats(self); _destroy_workers(self); return log_dest_driver_deinit_method(s); } void log_threaded_dest_driver_free(LogPipe *s) { LogThreadedDestDriver *self = (LogThreadedDestDriver *)s; g_free(self->workers); log_dest_driver_free((LogPipe *)self); } void log_threaded_dest_driver_init_instance(LogThreadedDestDriver *self, GlobalConfig *cfg) { log_dest_driver_init_instance(&self->super, cfg); self->super.super.super.init = log_threaded_dest_driver_init_method; self->super.super.super.deinit = log_threaded_dest_driver_deinit_method; self->super.super.super.queue = log_threaded_dest_driver_queue; self->super.super.super.free_fn = log_threaded_dest_driver_free; self->super.super.super.pre_config_init = log_threaded_dest_driver_pre_config_init; self->super.super.super.post_config_init = log_threaded_dest_driver_start_workers; self->time_reopen = -1; self->batch_lines = -1; self->batch_timeout = -1; self->num_workers = 1; self->last_worker = 0; self->retries_on_error_max = MAX_RETRIES_ON_ERROR_DEFAULT; self->retries_max = MAX_RETRIES_BEFORE_SUSPEND_DEFAULT; self->flush_on_key_change = FALSE; } syslog-ng-syslog-ng-4.4.0/lib/logthrdest/logthrdestdrv.h000066400000000000000000000233171450431004300233520ustar00rootroot00000000000000/* * Copyright (c) 2013, 2014 Balabit * Copyright (c) 2013, 2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGTHRDESTDRV_H #define LOGTHRDESTDRV_H #include "syslog-ng.h" #include "driver.h" #include "stats/stats-registry.h" #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-compat.h" #include "stats/stats-cluster-key-builder.h" #include "logqueue.h" #include "seqnum.h" #include "mainloop-threaded-worker.h" #include "timeutils/misc.h" #include "template/templates.h" #include #include typedef enum { /* flush modes */ /* flush the infligh messages */ LTF_FLUSH_NORMAL, /* expedite flush, to be used at reload, when the persistency of the queue * contents is ensured */ LTF_FLUSH_EXPEDITE, } LogThreadedFlushMode; typedef enum { LTR_DROP, LTR_ERROR, LTR_EXPLICIT_ACK_MGMT, LTR_SUCCESS, LTR_QUEUED, LTR_NOT_CONNECTED, LTR_RETRY, LTR_MAX } LogThreadedResult; typedef struct _LogThreadedDestDriver LogThreadedDestDriver; typedef struct _LogThreadedDestWorker LogThreadedDestWorker; struct _LogThreadedDestWorker { MainLoopThreadedWorker thread; LogQueue *queue; struct iv_task do_work; struct iv_event wake_up_event; struct iv_event shutdown_event; struct iv_timer timer_reopen; struct iv_timer timer_throttle; struct iv_timer timer_flush; LogThreadedDestDriver *owner; gint worker_index; gboolean connected; gint batch_size; gint rewound_batch_size; gint retries_on_error_counter; guint retries_counter; gint32 seq_num; struct timespec last_flush_time; gboolean enable_batching; gboolean suspended; time_t time_reopen; struct { GString *last_key; } partitioning; struct { StatsClusterKey *output_event_bytes_sc_key; StatsClusterKey *message_delay_sample_key; StatsClusterKey *message_delay_sample_age_key; StatsByteCounter written_bytes; StatsCounterItem *message_delay_sample; StatsCounterItem *message_delay_sample_age; gint64 last_delay_update; } metrics; gboolean (*init)(LogThreadedDestWorker *s); void (*deinit)(LogThreadedDestWorker *s); gboolean (*connect)(LogThreadedDestWorker *s); void (*disconnect)(LogThreadedDestWorker *s); LogThreadedResult (*insert)(LogThreadedDestWorker *s, LogMessage *msg); LogThreadedResult (*flush)(LogThreadedDestWorker *s, LogThreadedFlushMode mode); void (*free_fn)(LogThreadedDestWorker *s); }; const gchar *log_threaded_result_to_str(LogThreadedResult self); struct _LogThreadedDestDriver { LogDestDriver super; struct { StatsClusterKey *output_events_sc_key; StatsClusterKey *processed_sc_key; StatsCounterItem *dropped_messages; StatsCounterItem *processed_messages; StatsCounterItem *written_messages; gboolean raw_bytes_enabled; StatsAggregator *max_message_size; StatsAggregator *average_messages_size; StatsAggregator *max_batch_size; StatsAggregator *average_batch_size; StatsAggregator *CPS; } metrics; gint batch_lines; gint batch_timeout; gboolean under_termination; time_t time_reopen; gint retries_on_error_max; guint retries_max; struct { LogThreadedDestWorker *(*construct)(LogThreadedDestDriver *s, gint worker_index); /* this is a compatibility layer that can be removed once all drivers have * been migrated to the use of LogThreadedDestWorker based interface. * Right now, if a driver is not overriding the Worker instance, we would * be calling these methods from the functions named `_compat_*()`. */ LogThreadedDestWorker instance; void (*thread_init)(LogThreadedDestDriver *s); void (*thread_deinit)(LogThreadedDestDriver *s); gboolean (*connect)(LogThreadedDestDriver *s); void (*disconnect)(LogThreadedDestDriver *s); LogThreadedResult (*insert)(LogThreadedDestDriver *s, LogMessage *msg); LogThreadedResult (*flush)(LogThreadedDestDriver *s); } worker; LogThreadedDestWorker **workers; gint num_workers; gint created_workers; guint last_worker; gboolean flush_on_key_change; LogTemplate *worker_partition_key; gint stats_source; /* this counter is not thread safe if there are multiple worker threads, * in that case, one needs to use LogThreadedDestWorker->seq_num, which is * static for a single insert() invocation, whereas this might be * increased in parallel by the multiple threads. */ gint32 shared_seq_num; const gchar *(*format_stats_key)(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb); }; static inline gboolean log_threaded_dest_worker_init(LogThreadedDestWorker *self) { if (self->init) return self->init(self); return TRUE; } static inline void log_threaded_dest_worker_deinit(LogThreadedDestWorker *self) { if (self->deinit) self->deinit(self); } static inline gboolean log_threaded_dest_worker_connect(LogThreadedDestWorker *self) { if (self->connect) self->connected = self->connect(self); else self->connected = TRUE; return self->connected; } static inline void log_threaded_dest_worker_disconnect(LogThreadedDestWorker *self) { if (self->disconnect) self->disconnect(self); self->connected = FALSE; } static inline LogThreadedResult log_threaded_dest_worker_insert(LogThreadedDestWorker *self, LogMessage *msg) { if (msg->flags & LF_LOCAL) { if (self->owner->num_workers > 1) self->seq_num = step_sequence_number_atomic(&self->owner->shared_seq_num); else self->seq_num = step_sequence_number(&self->owner->shared_seq_num); } else self->seq_num = 0; LogThreadedResult result = self->insert(self, msg); if (self->metrics.message_delay_sample && (result == LTR_QUEUED || result == LTR_SUCCESS || result == LTR_EXPLICIT_ACK_MGMT)) { UnixTime now; unix_time_set_now(&now); gint64 diff_msec = unix_time_diff_in_msec(&now, &msg->timestamps[LM_TS_RECVD]); if (self->metrics.last_delay_update != now.ut_sec) { stats_counter_set_time(self->metrics.message_delay_sample, diff_msec); stats_counter_set_time(self->metrics.message_delay_sample_age, now.ut_sec); self->metrics.last_delay_update = now.ut_sec; } } return result; } static inline LogThreadedResult log_threaded_dest_worker_flush(LogThreadedDestWorker *self, LogThreadedFlushMode mode) { LogThreadedResult result = LTR_SUCCESS; if (self->flush) result = self->flush(self, mode); iv_validate_now(); self->last_flush_time = iv_now; return result; } /* function for drivers that are not yet using the worker API */ static inline LogThreadedResult log_threaded_dest_driver_flush(LogThreadedDestDriver *self) { return log_threaded_dest_worker_flush(&self->worker.instance, LTF_FLUSH_NORMAL); } void log_threaded_dest_worker_ack_messages(LogThreadedDestWorker *self, gint batch_size); void log_threaded_dest_worker_drop_messages(LogThreadedDestWorker *self, gint batch_size); void log_threaded_dest_worker_rewind_messages(LogThreadedDestWorker *self, gint batch_size); void log_threaded_dest_worker_wakeup_when_suspended(LogThreadedDestWorker *self); gboolean log_threaded_dest_worker_init_method(LogThreadedDestWorker *self); void log_threaded_dest_worker_deinit_method(LogThreadedDestWorker *self); void log_threaded_dest_worker_init_instance(LogThreadedDestWorker *self, LogThreadedDestDriver *owner, gint worker_index); void log_threaded_dest_worker_free_method(LogThreadedDestWorker *self); void log_threaded_dest_worker_free(LogThreadedDestWorker *self); void log_threaded_dest_worker_written_bytes_add(LogThreadedDestWorker *self, gsize b); void log_threaded_dest_driver_insert_msg_length_stats(LogThreadedDestDriver *self, gsize len); void log_threaded_dest_driver_insert_batch_length_stats(LogThreadedDestDriver *self, gsize len); void log_threaded_dest_driver_register_aggregated_stats(LogThreadedDestDriver *self); void log_threaded_dest_driver_unregister_aggregated_stats(LogThreadedDestDriver *self); gboolean log_threaded_dest_driver_deinit_method(LogPipe *s); gboolean log_threaded_dest_driver_init_method(LogPipe *s); gboolean log_threaded_dest_driver_start_workers(LogPipe *s); void log_threaded_dest_driver_init_instance(LogThreadedDestDriver *self, GlobalConfig *cfg); void log_threaded_dest_driver_free(LogPipe *s); void log_threaded_dest_driver_set_max_retries_on_error(LogDriver *s, gint max_retries); void log_threaded_dest_driver_set_num_workers(LogDriver *s, gint num_workers); void log_threaded_dest_driver_set_worker_partition_key_ref(LogDriver *s, LogTemplate *key); void log_threaded_dest_driver_set_flush_on_worker_key_change(LogDriver *s, gboolean f); void log_threaded_dest_driver_set_batch_lines(LogDriver *s, gint batch_lines); void log_threaded_dest_driver_set_batch_timeout(LogDriver *s, gint batch_timeout); void log_threaded_dest_driver_set_time_reopen(LogDriver *s, time_t time_reopen); #endif syslog-ng-syslog-ng-4.4.0/lib/logthrdest/tests/000077500000000000000000000000001450431004300214425ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logthrdest/tests/CMakeLists.txt000066400000000000000000000000731450431004300242020ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_logthrdestdrv) syslog-ng-syslog-ng-4.4.0/lib/logthrdest/tests/Makefile.am000066400000000000000000000004631450431004300235010ustar00rootroot00000000000000lib_logthrdest_tests_TESTS = \ lib/logthrdest/tests/test_logthrdestdrv EXTRA_DIST += lib/logthrdest/tests/CMakeLists.txt check_PROGRAMS += ${lib_logthrdest_tests_TESTS} lib_logthrdest_tests_test_logthrdestdrv_CFLAGS = \ $(TEST_CFLAGS) lib_logthrdest_tests_test_logthrdestdrv_LDADD = \ $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/logthrdest/tests/test_logthrdestdrv.c000066400000000000000000000744731450431004300255570ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "libtest/stopwatch.h" #include "libtest/cr_template.h" #include "logthrdest/logthrdestdrv.h" #include "mainloop-worker.h" #include "apphook.h" typedef struct TestThreadedDestDriver { LogThreadedDestDriver super; gint connect_counter; gint insert_counter; gint flush_counter; gint failure_counter; gint prev_flush_size; gint flush_size; } TestThreadedDestDriver; static const gchar * _generate_persist_name(const LogPipe *s) { return "persist-name"; } static const gchar * _format_stats_key(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb) { stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "stats-name")); return NULL; } static gboolean _connect_success(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->connect_counter++; return TRUE; } static TestThreadedDestDriver * test_threaded_dd_new(GlobalConfig *cfg) { TestThreadedDestDriver *self = g_new0(TestThreadedDestDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.generate_persist_name = _generate_persist_name; self->super.format_stats_key = _format_stats_key; self->super.worker.connect = _connect_success; /* the insert function will be initialized explicitly in testcases */ self->super.worker.insert = NULL; self->super.batch_timeout = 0; self->super.batch_lines = 0; return self; } /* spins maximum about 10 seconds, if you need more time, increase the loop counter */ #define MAX_SPIN_ITERATIONS 10000 static void _sleep_msec(long msec) { struct timespec sleep_time = { msec / 1000, (msec % 1000) * 1000000 }; nanosleep(&sleep_time, NULL); } static void _spin_for_counter_value(StatsCounterItem *counter, gssize expected_value) { gssize value = stats_counter_get(counter); gint c = 0; while (value != expected_value && c < MAX_SPIN_ITERATIONS) { value = stats_counter_get(counter); _sleep_msec(1); c++; } cr_assert(expected_value == value, "counter did not reach the expected value after %d seconds, " "expected_value=%" G_GSSIZE_FORMAT ", value=%" G_GSSIZE_FORMAT, MAX_SPIN_ITERATIONS / 1000, expected_value, value); } static void _generate_messages(TestThreadedDestDriver *dd, gint n, gboolean local) { LogMessage *msg; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT_NOACK; gchar buf[32]; for (gint i = 0; i < n; i++) { msg = create_sample_message(); g_snprintf(buf, sizeof(buf), "%d", i); log_msg_set_value(msg, LM_V_PID, buf, -1); if (local) msg->flags |= LF_LOCAL; else msg->flags &= ~LF_LOCAL; log_pipe_queue(&dd->super.super.super.super, msg, &path_options); } } static void _generate_messages_and_wait_for_processing(TestThreadedDestDriver *dd, gint n, StatsCounterItem *counter) { _generate_messages(dd, n, TRUE); _spin_for_counter_value(counter, n); } static void _generate_message_and_wait_for_processing(TestThreadedDestDriver *dd, StatsCounterItem *counter) { _generate_messages_and_wait_for_processing(dd, 1, counter); } TestThreadedDestDriver *dd; MainLoop *main_loop; static void _setup_dd(void) { dd = test_threaded_dd_new(main_loop_get_current_config(main_loop)); cr_assert(log_pipe_init(&dd->super.super.super.super)); cr_assert(log_pipe_post_config_init(&dd->super.super.super.super)); } static void _teardown_dd(void) { main_loop_sync_worker_startup_and_teardown(); log_pipe_deinit(&dd->super.super.super.super); log_pipe_unref(&dd->super.super.super.super); } static LogThreadedResult _insert_single_message_success(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; cr_expect_neq(self->super.worker.instance.seq_num, 0); return LTR_SUCCESS; } Test(logthrdestdrv, driver_can_be_instantiated_and_one_message_is_properly_processed) { dd->super.worker.insert = _insert_single_message_success; _generate_message_and_wait_for_processing(dd, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == 1, "insert()-ed message count expected to match the amount generated, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 2, "seq_num expected to be 1 larger than the amount of messages generated, found %d", dd->super.shared_seq_num); } static LogThreadedResult _insert_single_message_with_zero_seq_num(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; cr_expect_eq(self->super.worker.instance.seq_num, 0); return LTR_SUCCESS; } Test(logthrdestdrv, non_local_messages_dont_increment_seq_num) { dd->super.worker.insert = _insert_single_message_with_zero_seq_num; _generate_messages(dd, 1, FALSE); _spin_for_counter_value(dd->super.metrics.written_messages, 1); cr_assert(dd->insert_counter == 1, "insert()-ed message count expected to match the amount generated, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 1, "seq_num expected to be unchanged while non-local messages get derilered, found %d, expected: %d", dd->super.shared_seq_num, 1); } static LogThreadedResult _insert_single_message_drop(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; return LTR_DROP; } Test(logthrdestdrv, message_drops_are_accounted_in_the_drop_counter_and_are_reported_properly) { dd->super.worker.insert = _insert_single_message_drop; start_grabbing_messages(); _generate_message_and_wait_for_processing(dd, dd->super.metrics.dropped_messages); cr_assert(dd->insert_counter == 1, "insert()-ed message count expected to match the amount generated, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 0); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 1); cr_assert(dd->super.shared_seq_num == 2, "seq_num expected to be 1 larger than the amount of messages generated, found %d", dd->super.shared_seq_num); assert_grabbed_log_contains("dropped while sending"); } static LogThreadedResult _insert_single_message_connection_failure(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; if (self->insert_counter++ < 10) return LTR_NOT_CONNECTED; return LTR_SUCCESS; } Test(logthrdestdrv, connection_failure_is_considered_an_error_and_retried_indefinitely) { dd->super.worker.insert = _insert_single_message_connection_failure; dd->super.worker.instance.time_reopen = 0; start_grabbing_messages(); _generate_message_and_wait_for_processing(dd, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == 11, "insert() invocations expected to match 11 (10 failed and 1 successul) attempts, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(dd->super.shared_seq_num == 12, "seq_num expected to be 1 larger than the number of insert attempts, found %d", dd->super.shared_seq_num); assert_grabbed_log_contains("Server disconnected"); } static LogThreadedResult _insert_single_message_error_until_drop(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; return LTR_ERROR; } Test(logthrdestdrv, error_result_retries_sending_retry_max_times_and_then_drops) { dd->super.worker.insert = _insert_single_message_error_until_drop; dd->super.worker.instance.time_reopen = 0; dd->super.retries_on_error_max = 5; start_grabbing_messages(); _generate_message_and_wait_for_processing(dd, dd->super.metrics.dropped_messages); cr_assert(dd->insert_counter == 5, "insert() invocations expected to match the number of retry attempts, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 0); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 1); cr_assert(dd->super.shared_seq_num == 6, "seq_num expected to be 1 larger than the number of insert attempts, found %d", dd->super.shared_seq_num); assert_grabbed_log_contains("Error occurred while"); assert_grabbed_log_contains("Multiple failures while sending"); } static LogThreadedResult _insert_single_message_error_until_successful(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; if (self->insert_counter++ < 4) return LTR_ERROR; return LTR_SUCCESS; } Test(logthrdestdrv, error_result_retries_sending_retry_max_times_and_then_accepts) { dd->super.worker.insert = _insert_single_message_error_until_successful; dd->super.worker.instance.time_reopen = 0; dd->super.retries_on_error_max = 5; start_grabbing_messages(); _generate_message_and_wait_for_processing(dd, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == 5, "insert() invocations expected to match the number of failed (4) plus the number of successful (1) attempts, found %d", dd->insert_counter); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 1); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(dd->super.shared_seq_num == 6, "seq_num expected to be 1 larger than the number of insert attempts, found %d", dd->super.shared_seq_num); assert_grabbed_log_contains("Error occurred while"); } static LogThreadedResult _insert_batched_message_success(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += self->super.worker.instance.batch_size; return LTR_SUCCESS; } static LogThreadedResult _flush_batched_message_success(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_counter++; self->flush_size += self->super.worker.instance.batch_size; return LTR_SUCCESS; } Test(logthrdestdrv, batched_set_of_messages_are_successfully_delivered) { dd->super.worker.insert = _insert_batched_message_success; dd->super.worker.flush = _flush_batched_message_success; dd->super.batch_lines = 5; _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == 10, "insert() invocations expected to match the number of messages generated, found %d", dd->insert_counter); cr_assert(dd->flush_size == 10, "flush_size expected to match the number of messages generated, found %d", dd->flush_size); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 11, "seq_num expected to be 1 larger than the number of insert attempts, found %d", dd->super.shared_seq_num); } static LogThreadedResult _insert_batched_message_drop(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += self->super.worker.instance.batch_size; return LTR_DROP; } static LogThreadedResult _flush_batched_message_drop(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_counter++; self->flush_size += self->super.worker.instance.batch_size; return LTR_DROP; } Test(logthrdestdrv, batched_set_of_messages_are_dropped_as_a_whole) { dd->super.worker.insert = _insert_batched_message_drop; dd->super.worker.flush = _flush_batched_message_drop; dd->super.worker.instance.time_reopen = 0; start_grabbing_messages(); _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.dropped_messages); cr_assert(dd->insert_counter == 10); cr_assert(dd->flush_size == 10); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 0); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 10); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 11, "%d", dd->super.shared_seq_num); assert_grabbed_log_contains("dropped while sending message"); } static inline void _expect_batch_size_remains_the_same_across_retries(TestThreadedDestDriver *self) { if (self->super.worker.instance.retries_on_error_counter > 0) { cr_expect(self->super.worker.instance.batch_size == self->prev_flush_size, "batch_size has to remain the same across retries, batch_size=%d, prev_flush_size=%d", self->super.worker.instance.batch_size, self->prev_flush_size); } else self->prev_flush_size = self->super.worker.instance.batch_size; } static LogThreadedResult _insert_batched_message_error_drop(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); return LTR_ERROR; } static LogThreadedResult _flush_batched_message_error_drop(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); /* see the note in logthrdestdrv.c:_perform_flush() */ if (self->super.worker.instance.batch_size == 0) return LTR_SUCCESS; return LTR_ERROR; } Test(logthrdestdrv, when_batched_set_of_messages_result_in_error_the_entire_batch_is_attempted_again_retry_count_times_and_then_dropped) { dd->super.worker.insert = _insert_batched_message_error_drop; dd->super.worker.flush = _flush_batched_message_error_drop; dd->super.worker.instance.time_reopen = 0; dd->super.retries_on_error_max = 5; start_grabbing_messages(); _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.dropped_messages); cr_assert(dd->insert_counter == dd->super.retries_on_error_max * 10, "not all messages were attempted %d times, insert_counter=%d", dd->super.retries_on_error_max, dd->insert_counter); cr_assert(dd->flush_size == dd->super.retries_on_error_max * 10, "not all messages were flushed %d times, flush_size=%d", dd->super.retries_on_error_max, dd->flush_size); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 0); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 10); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == dd->super.retries_on_error_max * 10 + 1, "seq_num needs to be one larger than the number of insert attempts, found %d", dd->super.shared_seq_num); assert_grabbed_log_contains("Error occurred while"); assert_grabbed_log_contains("Multiple failures while sending"); } /* * This testcase would try every message twice and fail and then be * successful at the third attempt. */ #define FAILING_ATTEMPTS_DROP 2 static inline LogThreadedResult _inject_error_a_few_times(TestThreadedDestDriver *self) { if (self->super.worker.instance.retries_on_error_counter >= FAILING_ATTEMPTS_DROP) return LTR_SUCCESS; else return LTR_ERROR; } static LogThreadedResult _insert_batched_message_error_success(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); return _inject_error_a_few_times(self); } static LogThreadedResult _flush_batched_message_error_success(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); /* see the note in logthrdestdrv.c:_perform_flush() */ if (self->super.worker.instance.batch_size == 0) return LTR_SUCCESS; return _inject_error_a_few_times(self); } Test(logthrdestdrv, when_batched_set_of_messages_result_in_error_the_entire_batch_is_attempted_again_and_then_successfully_delivered) { gint total_attempts = FAILING_ATTEMPTS_DROP + 1; dd->super.worker.insert = _insert_batched_message_error_success; dd->super.worker.flush = _flush_batched_message_error_success; dd->super.worker.instance.time_reopen = 0; dd->super.retries_on_error_max = 5; start_grabbing_messages(); _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == total_attempts * 10, "not all messages were attempted %d times, insert_counter=%d", total_attempts, dd->insert_counter); cr_assert(dd->flush_size == total_attempts * 10, "not all messages were flushed %d times, flush_size=%d", total_attempts, dd->flush_size); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == total_attempts * 10 + 1, "%d", dd->super.shared_seq_num); assert_grabbed_log_contains("Error occurred while"); } /* * This testcase would try every message twice and fail and then be * successful at the third attempt. */ #define FAILING_ATTEMPTS_NOTCONN 20 static inline LogThreadedResult _inject_not_connected_a_few_times(TestThreadedDestDriver *self) { if (self->failure_counter++ >= FAILING_ATTEMPTS_NOTCONN) { self->failure_counter = 0; return LTR_SUCCESS; } else return LTR_NOT_CONNECTED; } static LogThreadedResult _insert_batched_message_not_connected(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); return _inject_not_connected_a_few_times(self); } static LogThreadedResult _flush_batched_message_not_connected(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_size += self->super.worker.instance.batch_size; _expect_batch_size_remains_the_same_across_retries(self); /* see the note in logthrdestdrv.c:_perform_flush() */ if (self->super.worker.instance.batch_size == 0) return LTR_SUCCESS; return _inject_not_connected_a_few_times(self); } Test(logthrdestdrv, when_batched_set_of_messages_result_in_not_connected_the_entire_batch_is_attempted_again_and_then_successfully_delivered) { gint total_attempts = FAILING_ATTEMPTS_NOTCONN + 1; dd->super.worker.insert = _insert_batched_message_not_connected; dd->super.worker.flush = _flush_batched_message_not_connected; dd->super.worker.instance.time_reopen = 0; dd->super.retries_on_error_max = 5; start_grabbing_messages(); _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == total_attempts * 10, "not all messages were attempted %d times, insert_counter=%d", total_attempts, dd->insert_counter); cr_assert(dd->flush_size == total_attempts * 10, "not all messages were flushed %d times, flush_size=%d", total_attempts, dd->flush_size); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == total_attempts * 10 + 1, "%d", dd->super.shared_seq_num); assert_grabbed_log_contains("Server disconnected"); } Test(logthrdestdrv, throttle_is_applied_to_delivery_and_causes_flush_to_be_called_more_often) { /* 3 messages per second, we need to set this explicitly on the queue as it has already been initialized */ log_queue_set_throttle(dd->super.worker.instance.queue, 3); dd->super.worker.insert = _insert_batched_message_success; dd->super.worker.flush = _flush_batched_message_success; dd->super.batch_lines = 5; start_stopwatch(); _generate_messages_and_wait_for_processing(dd, 20, dd->super.metrics.written_messages); guint64 time_msec = stop_stopwatch_and_get_result(); /* NOTE: initially we send a bucket worth of messages, and then pace out * the remaining 6 buckets 1sec apart */ cr_assert(time_msec > 5000000); cr_assert(dd->insert_counter == 20); cr_assert(dd->flush_size == 20); cr_assert(dd->flush_counter > 3); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 20); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 20); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 21, "%d", dd->super.shared_seq_num); } Test(logthrdestdrv, batch_timeout_delays_flush_to_the_specified_interval) { /* 3 messages per second, we need to set this explicitly on the queue as it has already been initialized */ dd->super.worker.insert = _insert_batched_message_success; dd->super.worker.flush = _flush_batched_message_success; dd->super.batch_lines = 5; dd->super.batch_timeout = 1000; start_stopwatch(); _generate_messages(dd, 2, TRUE); gint flush_counter = dd->flush_counter; guint64 initial_feed_time = stop_stopwatch_and_get_result(); /* NOTE: this is a racy check. The rationale that this should be safe: * - we've set batch_timeout to 1 second * - the sending of two messages to the thread shouldn't take this much * - we only assert on the flush counter if this assertion does not fail * * if we need, we can always increase flush-timeout() if for some reason 1 * seconds wouldn't be enough time to do this validation. */ cr_assert(initial_feed_time < 1000000, "The initial feeding took more than batch_timeout(), e.g. 1 seconds. " "We can't validate that no flush happened in this period, check the " "comment above this assert for more information. initial_feed_time=%" G_GUINT64_FORMAT, initial_feed_time); cr_assert(flush_counter == 0, "Although the flush time has not yet elapsed, " "flush_counter is not zero, flush_counter=%d, initial_feed_time=%" G_GUINT64_FORMAT, flush_counter, initial_feed_time); _spin_for_counter_value(dd->super.metrics.written_messages, 2); cr_assert(dd->flush_size == 2); cr_assert(dd->flush_counter == 1); } Test(logthrdestdrv, batch_timeout_limits_flush_frequency) { /* 3 messages per second, we need to set this explicitly on the queue as it has already been initialized */ dd->super.worker.insert = _insert_batched_message_success; dd->super.worker.flush = _flush_batched_message_success; dd->super.batch_lines = 5; dd->super.batch_timeout = 1000; for (gint i = 0; i < 5; i++) { gint flush_counter; start_stopwatch(); _generate_messages(dd, 2, TRUE); _sleep_msec(100); flush_counter = dd->flush_counter; guint64 initial_feed_time = stop_stopwatch_and_get_result(); /* NOTE: the same rationale applies to this assert than in * batch_timeout_delays_flush_to_the_specified_interval() */ cr_assert(initial_feed_time < 1000000, "The initial feeding took more than batch_timeout(), e.g. 1 seconds. " "We can't validate that no flush happened in this period, check the " "comment above this assert for more information. initial_feed_time=%" G_GUINT64_FORMAT, initial_feed_time); cr_assert(flush_counter == i, "Although the flush time has not yet elapsed, flush_counter has already changed" "flush_counter=%d, expected %d, initial_feed_time=%" G_GUINT64_FORMAT, dd->flush_counter, i, initial_feed_time); /* force batch_timeout() to elapse, give some time to the thread to flush */ _sleep_msec(1200); cr_assert(dd->flush_counter == i + 1, "The flush time has now been forcibly spent, but the flush has not happened as expected." "flush_counter=%d, expected %d", dd->flush_counter, i + 1); } cr_assert(dd->flush_size == 10); } static gboolean _connect_failure(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->connect_counter++; if (self->connect_counter > 10) return TRUE; return FALSE; } Test(logthrdestdrv, test_connect_failure_kicks_in_suspend_retry_logic_which_keeps_reconnecting_until_successful) { /* the dd created by setup() is not good for us */ _teardown_dd(); /* we are asserting on a debug message */ debug_flag = TRUE; start_grabbing_messages(); dd = test_threaded_dd_new(main_loop_get_current_config(main_loop)); dd->super.worker.connect = _connect_failure; dd->super.worker.insert = _insert_single_message_success; dd->super.time_reopen = 0; cr_assert(log_pipe_init(&dd->super.super.super.super)); cr_assert(log_pipe_post_config_init(&dd->super.super.super.super)); _generate_message_and_wait_for_processing(dd, dd->super.metrics.written_messages); cr_assert(dd->connect_counter == 11, "%d", dd->connect_counter); assert_grabbed_log_contains("Error establishing connection to server"); } /* we batch 5 messages but then flush them only one-by-one */ static LogThreadedResult _insert_explicit_acks_message_success(LogThreadedDestDriver *s, LogMessage *msg) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->insert_counter++; if (self->super.worker.instance.batch_size < s->batch_lines) return LTR_QUEUED; self->flush_size += 1; log_threaded_dest_worker_ack_messages(&s->worker.instance, 1); return LTR_EXPLICIT_ACK_MGMT; } static LogThreadedResult _flush_explicit_acks_message_success(LogThreadedDestDriver *s) { TestThreadedDestDriver *self = (TestThreadedDestDriver *) s; self->flush_size += 1; log_threaded_dest_worker_ack_messages(&s->worker.instance, 1); return LTR_EXPLICIT_ACK_MGMT; } Test(logthrdestdrv, test_explicit_ack_accept) { dd->super.worker.insert = _insert_explicit_acks_message_success; dd->super.worker.flush = _flush_explicit_acks_message_success; dd->super.batch_lines = 5; _generate_messages_and_wait_for_processing(dd, 10, dd->super.metrics.written_messages); cr_assert(dd->insert_counter == 10, "%d", dd->insert_counter); cr_assert(dd->flush_size == 10); cr_assert(stats_counter_get(dd->super.metrics.processed_messages) == 10); cr_assert(stats_counter_get(dd->super.metrics.written_messages) == 10); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.queued_messages) == 0); cr_assert(stats_counter_get(dd->super.metrics.dropped_messages) == 0); cr_assert(stats_counter_get(dd->super.worker.instance.queue->metrics.shared.memory_usage) == 0); cr_assert(dd->super.shared_seq_num == 11, "%d", dd->super.shared_seq_num); } MainLoopOptions main_loop_options = {0}; static void setup(void) { app_startup(); main_loop = main_loop_get_instance(); main_loop_init(main_loop, &main_loop_options); cfg_set_current_version(main_loop_get_current_config(main_loop)); main_loop_worker_allocate_thread_space(2); main_loop_worker_finalize_thread_space(); _setup_dd(); } static void teardown(void) { _teardown_dd(); main_loop_deinit(main_loop); app_shutdown(); } TestSuite(logthrdestdrv, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/logthrsource/000077500000000000000000000000001450431004300206415ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logthrsource/CMakeLists.txt000066400000000000000000000004031450431004300233760ustar00rootroot00000000000000set(LOGTHRSOURCE_HEADERS logthrsource/logthrsourcedrv.h logthrsource/logthrfetcherdrv.h PARENT_SCOPE) set(LOGTHRSOURCE_SOURCES logthrsource/logthrsourcedrv.c logthrsource/logthrfetcherdrv.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/logthrsource/Makefile.am000066400000000000000000000005471450431004300227030ustar00rootroot00000000000000logthrsourceincludedir = ${pkgincludedir}/logthrsource EXTRA_DIST += lib/logthrsource/CMakeLists.txt logthrsourceinclude_HEADERS = \ lib/logthrsource/logthrsourcedrv.h \ lib/logthrsource/logthrfetcherdrv.h logthrsource_sources = \ lib/logthrsource/logthrsourcedrv.c \ lib/logthrsource/logthrfetcherdrv.c include lib/logthrsource/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/logthrsource/logthrfetcherdrv.c000066400000000000000000000220471450431004300243660ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logthrfetcherdrv.h" #include "messages.h" #include "timeutils/misc.h" #define SEC_TO_MSEC(x) ((x) * 1000) void log_threaded_fetcher_driver_set_fetch_no_data_delay(LogDriver *s, gdouble no_data_delay) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; self->no_data_delay = (gint64) SEC_TO_MSEC(no_data_delay); } void log_threaded_fetcher_driver_set_time_reopen(LogDriver *s, time_t time_reopen) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; self->time_reopen = time_reopen; } static EVTTAG * _tag_driver(LogThreadedFetcherDriver *f) { return evt_tag_str("driver", f->super.super.super.id); } static inline gboolean _connect(LogThreadedFetcherDriver *self) { msg_trace("Fetcher connect()", _tag_driver(self)); if (!self->connect) return TRUE; if (!self->connect(self)) { msg_debug("Error establishing connection", _tag_driver(self)); return FALSE; } return TRUE; } static inline void _disconnect(LogThreadedFetcherDriver *self) { msg_trace("Fetcher disconnect()", _tag_driver(self)); if (self->disconnect) self->disconnect(self); } static void _start_reconnect_timer(LogThreadedFetcherDriver *self) { iv_validate_now(); self->reconnect_timer.expires = iv_now; self->reconnect_timer.expires.tv_sec += self->time_reopen; iv_timer_register(&self->reconnect_timer); } static void _start_no_data_timer(LogThreadedFetcherDriver *self) { iv_validate_now(); self->no_data_timer.expires = iv_now; timespec_add_msec(&self->no_data_timer.expires, self->no_data_delay); iv_timer_register(&self->no_data_timer); } static gboolean _worker_thread_init(LogThreadedSourceDriver *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; iv_event_register(&self->shutdown_event); msg_trace("Fetcher thread_init()", _tag_driver(self)); if (self->thread_init) self->thread_init(self); return TRUE; } static void _worker_thread_deinit(LogThreadedSourceDriver *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; msg_trace("Fetcher thread_deinit()", _tag_driver(self)); if (self->thread_deinit) self->thread_deinit(self); iv_event_unregister(&self->shutdown_event); } static void _worker_run(LogThreadedSourceDriver *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; iv_event_register(&self->wakeup_event); if (_connect(self)) iv_task_register(&self->fetch_task); else _start_reconnect_timer(self); iv_main(); _disconnect(self); } static void _worker_request_exit(LogThreadedSourceDriver *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; self->under_termination = TRUE; iv_event_post(&self->shutdown_event); if (self->request_exit) self->request_exit(self); } static void _wakeup(LogThreadedSourceDriver *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; if (!self->under_termination) iv_event_post(&self->wakeup_event); } static inline void _schedule_next_fetch_if_free_to_send(LogThreadedFetcherDriver *self) { if (log_threaded_source_free_to_send(&self->super)) iv_task_register(&self->fetch_task); else self->suspended = TRUE; } static void _on_fetch_error(LogThreadedFetcherDriver *self) { msg_error("Error during fetching messages", _tag_driver(self)); _disconnect(self); _start_reconnect_timer(self); } static void _on_not_connected(LogThreadedFetcherDriver *self) { msg_info("Fetcher disconnected while receiving messages, reconnecting", _tag_driver(self)); _start_reconnect_timer(self); } static void _on_fetch_success(LogThreadedFetcherDriver *self, LogMessage *msg) { log_threaded_source_post(&self->super, msg); _schedule_next_fetch_if_free_to_send(self); } static void _on_fetch_try_again(LogThreadedFetcherDriver *self) { msg_debug("Try again when fetching messages", _tag_driver(self)); iv_task_register(&self->fetch_task); } static void _on_fetch_no_data(LogThreadedFetcherDriver *self) { msg_debug("No data during fetching messages", _tag_driver(self)); _start_no_data_timer(self); } static void _fetch(gpointer data) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) data; msg_trace("Fetcher fetch()", _tag_driver(self)); LogThreadedFetchResult fetch_result = self->fetch(self); switch (fetch_result.result) { case THREADED_FETCH_ERROR: _on_fetch_error(self); break; case THREADED_FETCH_NOT_CONNECTED: _on_not_connected(self); break; case THREADED_FETCH_SUCCESS: _on_fetch_success(self, fetch_result.msg); break; case THREADED_FETCH_TRY_AGAIN: _on_fetch_try_again(self); break; case THREADED_FETCH_NO_DATA: _on_fetch_no_data(self); break; default: g_assert_not_reached(); } } static void _wakeup_event_handler(gpointer data) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) data; if (self->suspended && log_threaded_source_free_to_send(&self->super)) { self->suspended = FALSE; if (!iv_task_registered(&self->fetch_task)) iv_task_register(&self->fetch_task); } } static void _stop_watches(LogThreadedFetcherDriver *self) { iv_event_unregister(&self->wakeup_event); if (iv_task_registered(&self->fetch_task)) iv_task_unregister(&self->fetch_task); if (iv_timer_registered(&self->reconnect_timer)) iv_timer_unregister(&self->reconnect_timer); if (iv_timer_registered(&self->no_data_timer)) iv_timer_unregister(&self->no_data_timer); } static void _shutdown_event_handler(gpointer data) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) data; _stop_watches(self); iv_quit(); } static void _reconnect(gpointer data) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) data; if (_connect(self)) _schedule_next_fetch_if_free_to_send(self); else _start_reconnect_timer(self); } static void _no_data(gpointer data) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) data; iv_task_register(&self->fetch_task); } static void _init_watches(LogThreadedFetcherDriver *self) { IV_TASK_INIT(&self->fetch_task); self->fetch_task.cookie = self; self->fetch_task.handler = _fetch; IV_EVENT_INIT(&self->wakeup_event); self->wakeup_event.cookie = self; self->wakeup_event.handler = _wakeup_event_handler; IV_EVENT_INIT(&self->shutdown_event); self->shutdown_event.cookie = self; self->shutdown_event.handler = _shutdown_event_handler; IV_TIMER_INIT(&self->reconnect_timer); self->reconnect_timer.cookie = self; self->reconnect_timer.handler = _reconnect; IV_TIMER_INIT(&self->no_data_timer); self->no_data_timer.cookie = self; self->no_data_timer.handler = _no_data; } gboolean log_threaded_fetcher_driver_init_method(LogPipe *s) { LogThreadedFetcherDriver *self = (LogThreadedFetcherDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_threaded_source_driver_init_method(s)) return FALSE; g_assert(self->fetch); if (self->time_reopen == -1) self->time_reopen = cfg->time_reopen; if (self->no_data_delay == -1) log_threaded_fetcher_driver_set_fetch_no_data_delay(&self->super.super.super, cfg->time_reopen); return TRUE; } gboolean log_threaded_fetcher_driver_deinit_method(LogPipe *s) { return log_threaded_source_driver_deinit_method(s); } void log_threaded_fetcher_driver_free_method(LogPipe *s) { log_threaded_source_driver_free_method(s); } void log_threaded_fetcher_driver_init_instance(LogThreadedFetcherDriver *self, GlobalConfig *cfg) { log_threaded_source_driver_init_instance(&self->super, cfg); self->time_reopen = -1; self->no_data_delay = -1; _init_watches(self); self->super.super.super.super.init = log_threaded_fetcher_driver_init_method; self->super.super.super.super.deinit = log_threaded_fetcher_driver_deinit_method; self->super.super.super.super.free_fn = log_threaded_fetcher_driver_free_method; self->super.wakeup = _wakeup; self->super.thread_init = _worker_thread_init; self->super.thread_deinit = _worker_thread_deinit; self->super.run = _worker_run; self->super.request_exit = _worker_request_exit; } syslog-ng-syslog-ng-4.4.0/lib/logthrsource/logthrfetcherdrv.h000066400000000000000000000052551450431004300243750ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGTHRFETCHERDRV_H #define LOGTHRFETCHERDRV_H #include "syslog-ng.h" #include "logthrsourcedrv.h" #include "logmsg/logmsg.h" #include "compat/time.h" #include #include typedef struct _LogThreadedFetcherDriver LogThreadedFetcherDriver; typedef enum { THREADED_FETCH_ERROR, THREADED_FETCH_NOT_CONNECTED, THREADED_FETCH_SUCCESS, THREADED_FETCH_TRY_AGAIN, THREADED_FETCH_NO_DATA } ThreadedFetchResult; typedef struct _LogThreadedFetchResult { ThreadedFetchResult result; LogMessage *msg; } LogThreadedFetchResult; struct _LogThreadedFetcherDriver { LogThreadedSourceDriver super; time_t time_reopen; gint64 no_data_delay; struct iv_task fetch_task; struct iv_event wakeup_event; struct iv_event shutdown_event; struct iv_timer reconnect_timer; struct iv_timer no_data_timer; gboolean suspended; gboolean under_termination; void (*thread_init)(LogThreadedFetcherDriver *self); void (*thread_deinit)(LogThreadedFetcherDriver *self); gboolean (*connect)(LogThreadedFetcherDriver *self); void (*disconnect)(LogThreadedFetcherDriver *self); LogThreadedFetchResult (*fetch)(LogThreadedFetcherDriver *self); void (*request_exit)(LogThreadedFetcherDriver *self); }; void log_threaded_fetcher_driver_init_instance(LogThreadedFetcherDriver *self, GlobalConfig *cfg); gboolean log_threaded_fetcher_driver_init_method(LogPipe *s); gboolean log_threaded_fetcher_driver_deinit_method(LogPipe *s); void log_threaded_fetcher_driver_free_method(LogPipe *s); void log_threaded_fetcher_driver_set_fetch_no_data_delay(LogDriver *self, gdouble no_data_delay); void log_threaded_fetcher_driver_set_time_reopen(LogDriver *s, time_t time_reopen); #endif syslog-ng-syslog-ng-4.4.0/lib/logthrsource/logthrsourcedrv.c000066400000000000000000000271261450431004300242510ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logthrsourcedrv.h" #include "mainloop-threaded-worker.h" #include "messages.h" #include "apphook.h" #include "ack-tracker/ack_tracker_factory.h" #include "stats/stats-cluster-key-builder.h" #include static void wakeup_cond_init(WakeupCondition *cond) { g_mutex_init(&cond->lock); g_cond_init(&cond->cond); cond->awoken = TRUE; } static void wakeup_cond_destroy(WakeupCondition *cond) { g_cond_clear(&cond->cond); g_mutex_clear(&cond->lock); } static inline void wakeup_cond_lock(WakeupCondition *cond) { g_mutex_lock(&cond->lock); } static inline void wakeup_cond_unlock(WakeupCondition *cond) { g_mutex_unlock(&cond->lock); } /* The wakeup lock must be held before calling this function. */ static inline void wakeup_cond_wait(WakeupCondition *cond) { cond->awoken = FALSE; while (!cond->awoken) g_cond_wait(&cond->cond, &cond->lock); } static inline void wakeup_cond_signal(WakeupCondition *cond) { g_mutex_lock(&cond->lock); cond->awoken = TRUE; g_cond_signal(&cond->cond); g_mutex_unlock(&cond->lock); } static LogPipe * log_threaded_source_worker_logpipe(LogThreadedSourceWorker *self) { return &self->super.super; } static void log_threaded_source_worker_set_options(LogThreadedSourceWorker *self, LogThreadedSourceDriver *control, LogThreadedSourceWorkerOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb) { log_source_set_options(&self->super, &options->super, stats_id, kb, TRUE, control->super.super.super.expr_node); log_source_set_ack_tracker_factory(&self->super, ack_tracker_factory_ref(options->ack_tracker_factory)); log_pipe_unref(&self->control->super.super.super); log_pipe_ref(&control->super.super.super); self->control = control; } void log_threaded_source_worker_options_defaults(LogThreadedSourceWorkerOptions *options) { log_source_options_defaults(&options->super); msg_format_options_defaults(&options->parse_options); options->parse_options.flags |= LP_SYSLOG_PROTOCOL; options->ack_tracker_factory = NULL; } void log_threaded_source_worker_options_init(LogThreadedSourceWorkerOptions *options, GlobalConfig *cfg, const gchar *group_name) { log_source_options_init(&options->super, cfg, group_name); msg_format_options_init(&options->parse_options, cfg); } void log_threaded_source_worker_options_destroy(LogThreadedSourceWorkerOptions *options) { log_source_options_destroy(&options->super); msg_format_options_destroy(&options->parse_options); ack_tracker_factory_unref(options->ack_tracker_factory); } /* The wakeup lock must be held before calling this function. */ static void log_threaded_source_suspend(LogThreadedSourceDriver *self) { LogThreadedSourceWorker *worker = self->worker; while (!log_threaded_source_free_to_send(self) && !worker->under_termination) wakeup_cond_wait(&worker->wakeup_cond); } static void log_threaded_source_wakeup(LogThreadedSourceDriver *self) { LogThreadedSourceWorker *worker = self->worker; wakeup_cond_signal(&worker->wakeup_cond); } static gboolean log_threaded_source_worker_thread_init(MainLoopThreadedWorker *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s->data; if (self->control->thread_init) return self->control->thread_init(self->control); return TRUE; } static void log_threaded_source_worker_thread_deinit(MainLoopThreadedWorker *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s->data; if (self->control->thread_deinit) self->control->thread_deinit(self->control); } static void log_threaded_source_worker_run(MainLoopThreadedWorker *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s->data; msg_debug("Worker thread started", evt_tag_str("driver", self->control->super.super.id)); self->control->run(self->control); msg_debug("Worker thread finished", evt_tag_str("driver", self->control->super.super.id)); } static void log_threaded_source_worker_request_exit(MainLoopThreadedWorker *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s->data; msg_debug("Requesting worker thread exit", evt_tag_str("driver", self->control->super.super.id)); self->under_termination = TRUE; self->control->request_exit(self->control); log_threaded_source_wakeup(self->control); } static void _worker_wakeup(LogSource *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s; self->control->wakeup(self->control); } static gboolean log_threaded_source_worker_init(LogPipe *s) { if (!log_source_init(s)) return FALSE; return TRUE; } static void log_threaded_source_worker_free(LogPipe *s) { LogThreadedSourceWorker *self = (LogThreadedSourceWorker *) s; wakeup_cond_destroy(&self->wakeup_cond); log_pipe_unref(&self->control->super.super.super); self->control = NULL; main_loop_threaded_worker_clear(&self->thread); log_source_free(s); } static LogThreadedSourceWorker * log_threaded_source_worker_new(GlobalConfig *cfg) { LogThreadedSourceWorker *self = g_new0(LogThreadedSourceWorker, 1); log_source_init_instance(&self->super, cfg); main_loop_threaded_worker_init(&self->thread, MLW_THREADED_INPUT_WORKER, self); self->thread.thread_init = log_threaded_source_worker_thread_init; self->thread.thread_deinit = log_threaded_source_worker_thread_deinit; self->thread.run = log_threaded_source_worker_run; self->thread.request_exit = log_threaded_source_worker_request_exit; wakeup_cond_init(&self->wakeup_cond); self->super.super.init = log_threaded_source_worker_init; self->super.super.free_fn = log_threaded_source_worker_free; self->super.wakeup = _worker_wakeup; return self; } gboolean log_threaded_source_driver_pre_config_init(LogPipe *s) { main_loop_worker_allocate_thread_space(1); return TRUE; } gboolean log_threaded_source_driver_init_method(LogPipe *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); self->worker = log_threaded_source_worker_new(cfg); if (!log_src_driver_init_method(s)) return FALSE; g_assert(self->format_stats_key); StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); self->format_stats_key(self, kb); log_threaded_source_worker_options_init(&self->worker_options, cfg, self->super.super.group); log_threaded_source_worker_set_options(self->worker, self, &self->worker_options, self->super.super.id, kb); LogPipe *worker_pipe = log_threaded_source_worker_logpipe(self->worker); log_pipe_append(worker_pipe, s); if (!log_pipe_init(worker_pipe)) { log_pipe_unref(worker_pipe); self->worker = NULL; return FALSE; } return TRUE; } gboolean log_threaded_source_driver_deinit_method(LogPipe *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; LogPipe *worker_pipe = log_threaded_source_worker_logpipe(self->worker); log_pipe_deinit(worker_pipe); log_pipe_unref(worker_pipe); return log_src_driver_deinit_method(s); } void log_threaded_source_driver_free_method(LogPipe *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; log_threaded_source_worker_options_destroy(&self->worker_options); log_src_driver_free(s); } gboolean log_threaded_source_driver_start_worker(LogPipe *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; main_loop_threaded_worker_start(&self->worker->thread); return TRUE; } static gboolean _is_default_priority_or_facility_set(MsgFormatOptions *parse_options) { return parse_options->default_pri != 0xFFFF; } static void _apply_default_priority_and_facility(LogThreadedSourceDriver *self, LogMessage *msg) { MsgFormatOptions *parse_options = &self->worker_options.parse_options; if (!_is_default_priority_or_facility_set(parse_options)) return; msg->pri = parse_options->default_pri; } /* * Call this every some messages so consumers that accumulate multiple * messages (LogQueueFifo for instance) can finish accumulation and go on * processing a batch. * * Basically this calls main_loop_worker_invoke_batch_callbacks(), which is * done by the minaloop-io-worker layer whenever we go back to the main * loop. Whether this is done automatically by LogThreadedSourceDriver is * controlled by the auto_close_batches member, in which case we do this * every message. * * Doing it every message defeats the purpose more or less, as consumers * tend to do batching to improve performance. */ void log_threaded_source_close_batch(LogThreadedSourceDriver *self) { main_loop_worker_invoke_batch_callbacks(); } void log_threaded_source_post(LogThreadedSourceDriver *self, LogMessage *msg) { msg_debug("Incoming log message", evt_tag_str("input", log_msg_get_value(msg, LM_V_MESSAGE, NULL)), evt_tag_msg_reference(msg)); _apply_default_priority_and_facility(self, msg); log_source_post(&self->worker->super, msg); if (self->auto_close_batches) log_threaded_source_close_batch(self); } gboolean log_threaded_source_free_to_send(LogThreadedSourceDriver *self) { return log_source_free_to_send(&self->worker->super); } void log_threaded_source_blocking_post(LogThreadedSourceDriver *self, LogMessage *msg) { LogThreadedSourceWorker *worker = self->worker; log_threaded_source_post(self, msg); /* * The wakeup lock must be held before calling free_to_send() and suspend(), * otherwise g_cond_signal() might be called between free_to_send() and * suspend(). We'd hang in that case. * * LogReader does not have such a lock, but this is because it runs an ivykis * loop with a _synchronized_ event queue, where suspend() and the * "schedule_wakeup" event are guaranteed to be scheduled in the right order. */ wakeup_cond_lock(&worker->wakeup_cond); if (!log_threaded_source_free_to_send(self)) log_threaded_source_suspend(self); wakeup_cond_unlock(&worker->wakeup_cond); } void log_threaded_source_driver_init_instance(LogThreadedSourceDriver *self, GlobalConfig *cfg) { log_src_driver_init_instance(&self->super, cfg); log_threaded_source_worker_options_defaults(&self->worker_options); self->super.super.super.init = log_threaded_source_driver_init_method; self->super.super.super.deinit = log_threaded_source_driver_deinit_method; self->super.super.super.free_fn = log_threaded_source_driver_free_method; self->super.super.super.pre_config_init = log_threaded_source_driver_pre_config_init; self->super.super.super.post_config_init = log_threaded_source_driver_start_worker; self->wakeup = log_threaded_source_wakeup; self->auto_close_batches = TRUE; } syslog-ng-syslog-ng-4.4.0/lib/logthrsource/logthrsourcedrv.h000066400000000000000000000074641450431004300242610ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGTHRSOURCEDRV_H #define LOGTHRSOURCEDRV_H #include "syslog-ng.h" #include "driver.h" #include "logsource.h" #include "cfg.h" #include "logpipe.h" #include "logmsg/logmsg.h" #include "msg-format.h" #include "mainloop-threaded-worker.h" #include "stats/stats-cluster-key-builder.h" typedef struct _LogThreadedSourceDriver LogThreadedSourceDriver; typedef struct _LogThreadedSourceWorker LogThreadedSourceWorker; typedef struct _LogThreadedSourceWorkerOptions { LogSourceOptions super; MsgFormatOptions parse_options; AckTrackerFactory *ack_tracker_factory; } LogThreadedSourceWorkerOptions; typedef struct _WakeupCondition { GMutex lock; GCond cond; gboolean awoken; } WakeupCondition; struct _LogThreadedSourceWorker { LogSource super; MainLoopThreadedWorker thread; LogThreadedSourceDriver *control; WakeupCondition wakeup_cond; gboolean under_termination; }; struct _LogThreadedSourceDriver { LogSrcDriver super; LogThreadedSourceWorkerOptions worker_options; LogThreadedSourceWorker *worker; gboolean auto_close_batches; void (*format_stats_key)(LogThreadedSourceDriver *self, StatsClusterKeyBuilder *kb); gboolean (*thread_init)(LogThreadedSourceDriver *self); void (*thread_deinit)(LogThreadedSourceDriver *self); void (*run)(LogThreadedSourceDriver *self); void (*request_exit)(LogThreadedSourceDriver *self); void (*wakeup)(LogThreadedSourceDriver *self); }; void log_threaded_source_worker_options_defaults(LogThreadedSourceWorkerOptions *options); void log_threaded_source_worker_options_init(LogThreadedSourceWorkerOptions *options, GlobalConfig *cfg, const gchar *group_name); void log_threaded_source_worker_options_destroy(LogThreadedSourceWorkerOptions *options); void log_threaded_source_driver_init_instance(LogThreadedSourceDriver *self, GlobalConfig *cfg); gboolean log_threaded_source_driver_init_method(LogPipe *s); gboolean log_threaded_source_driver_deinit_method(LogPipe *s); void log_threaded_source_driver_free_method(LogPipe *s); static inline LogSourceOptions * log_threaded_source_driver_get_source_options(LogDriver *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; return &self->worker_options.super; } static inline MsgFormatOptions * log_threaded_source_driver_get_parse_options(LogDriver *s) { LogThreadedSourceDriver *self = (LogThreadedSourceDriver *) s; return &self->worker_options.parse_options; } void log_threaded_source_close_batch(LogThreadedSourceDriver *self); /* blocking API */ void log_threaded_source_blocking_post(LogThreadedSourceDriver *self, LogMessage *msg); /* non-blocking API, use it wisely (thread boundaries) */ void log_threaded_source_post(LogThreadedSourceDriver *self, LogMessage *msg); gboolean log_threaded_source_free_to_send(LogThreadedSourceDriver *self); #endif syslog-ng-syslog-ng-4.4.0/lib/logthrsource/tests/000077500000000000000000000000001450431004300220035ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/logthrsource/tests/CMakeLists.txt000066400000000000000000000001731450431004300245440ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_logthrsourcedrv) add_unit_test(CRITERION LIBTEST TARGET test_logthrfetcherdrv) syslog-ng-syslog-ng-4.4.0/lib/logthrsource/tests/Makefile.am000066400000000000000000000007701450431004300240430ustar00rootroot00000000000000lib_logthrsource_tests_TESTS = \ lib/logthrsource/tests/test_logthrsourcedrv \ lib/logthrsource/tests/test_logthrfetcherdrv EXTRA_DIST += lib/logthrsource/tests/CMakeLists.txt check_PROGRAMS += ${lib_logthrsource_tests_TESTS} lib_logthrsource_tests_test_logthrsourcedrv_CFLAGS = $(TEST_CFLAGS) lib_logthrsource_tests_test_logthrsourcedrv_LDADD = $(TEST_LDADD) lib_logthrsource_tests_test_logthrfetcherdrv_CFLAGS = $(TEST_CFLAGS) lib_logthrsource_tests_test_logthrfetcherdrv_LDADD = $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/logthrsource/tests/test_logthrfetcherdrv.c000066400000000000000000000230021450431004300265570ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "logthrsource/logthrfetcherdrv.h" #include "apphook.h" #include "mainloop.h" #include "mainloop-worker.h" #include "cfg.h" #include "stats/stats-counter.h" #include "logsource.h" #include "compat/time.h" typedef struct _TestThreadedFetcherDriver { LogThreadedFetcherDriver super; gint num_of_messages_to_generate; gint num_of_connection_failures_to_generate; gint connect_counter; gboolean try_again_first_time; gboolean no_data_first_time; GMutex lock; GCond cond; } TestThreadedFetcherDriver; MainLoopOptions main_loop_options = {0}; MainLoop *main_loop; static const gchar * _generate_persist_name(const LogPipe *s) { return "test_threaded_fetcher_driver"; } static void _format_stats_key(LogThreadedSourceDriver *s, StatsClusterKeyBuilder *kb) { stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "test_threaded_fetcher_driver_stats")); } static void _source_queue_mock(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSource *self = (LogSource *) s; stats_counter_inc(self->metrics.recvd_messages); log_pipe_forward_msg(s, msg, path_options); } static LogSource * _get_source(TestThreadedFetcherDriver *self) { return (LogSource *) self->super.super.worker; } static void test_threaded_fetcher_free(LogPipe *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *) s; g_cond_clear(&self->cond); g_mutex_clear(&self->lock); log_threaded_fetcher_driver_free_method(s); } gboolean test_threaded_fetcher_driver_init_method(LogPipe *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *)s; if (!log_threaded_fetcher_driver_init_method(s)) return FALSE; /* mock out the hard-coded DNS lookup calls inside log_source_queue() */ _get_source(self)->super.queue = _source_queue_mock; return TRUE; } static TestThreadedFetcherDriver * test_threaded_fetcher_new(GlobalConfig *cfg) { TestThreadedFetcherDriver *self = g_new0(TestThreadedFetcherDriver, 1); log_threaded_fetcher_driver_init_instance(&self->super, cfg); g_mutex_init(&self->lock); g_cond_init(&self->cond); self->super.super.super.super.super.init = test_threaded_fetcher_driver_init_method; self->super.super.format_stats_key = _format_stats_key; self->super.super.super.super.super.generate_persist_name = _generate_persist_name; self->super.super.super.super.super.free_fn = test_threaded_fetcher_free; return self; } static TestThreadedFetcherDriver * create_threaded_fetcher(void) { return test_threaded_fetcher_new(main_loop_get_current_config(main_loop)); } static void start_test_threaded_fetcher(TestThreadedFetcherDriver *s) { cr_assert(log_pipe_init(&s->super.super.super.super.super)); cr_assert(log_pipe_post_config_init(&s->super.super.super.super.super)); } static void wait_for_messages(TestThreadedFetcherDriver *s) { g_mutex_lock(&s->lock); while (s->num_of_messages_to_generate > 0) g_cond_wait(&s->cond, &s->lock); g_mutex_unlock(&s->lock); } static void stop_test_threaded_fetcher(TestThreadedFetcherDriver *s) { main_loop_sync_worker_startup_and_teardown(); } static void destroy_test_threaded_fetcher(TestThreadedFetcherDriver *s) { cr_assert(log_pipe_deinit(&s->super.super.super.super.super)); log_pipe_unref(&s->super.super.super.super.super); } static void setup(void) { app_startup(); main_loop = main_loop_get_instance(); main_loop_init(main_loop, &main_loop_options); } static void teardown(void) { main_loop_deinit(main_loop); app_shutdown(); } static LogThreadedFetchResult _fetch(LogThreadedFetcherDriver *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *) s; if (self->num_of_connection_failures_to_generate && self->connect_counter <= self->num_of_connection_failures_to_generate) { return (LogThreadedFetchResult) { THREADED_FETCH_NOT_CONNECTED, NULL }; } g_mutex_lock(&self->lock); if (self->num_of_messages_to_generate <= 0) { g_cond_signal(&self->cond); g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { THREADED_FETCH_ERROR, NULL }; } LogMessage *msg = create_sample_message(); self->num_of_messages_to_generate--; g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { .result = THREADED_FETCH_SUCCESS, .msg = msg }; } static gboolean _connect_fail_first_time(LogThreadedFetcherDriver *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *) s; self->connect_counter++; if (self->connect_counter == 1) return FALSE; return TRUE; } TestSuite(logthrfetcherdrv, .init = setup, .fini = teardown, .timeout = 10); Test(logthrfetcherdrv, test_simple_fetch) { TestThreadedFetcherDriver *s = create_threaded_fetcher(); s->num_of_messages_to_generate = 10; s->super.fetch = _fetch; start_test_threaded_fetcher(s); wait_for_messages(s); stop_test_threaded_fetcher(s); StatsCounterItem *recvd_messages = _get_source(s)->metrics.recvd_messages; cr_assert(stats_counter_get(recvd_messages) == 10); destroy_test_threaded_fetcher(s); } Test(logthrfetcherdrv, test_reconnect) { TestThreadedFetcherDriver *s = create_threaded_fetcher(); s->num_of_messages_to_generate = 10; s->num_of_connection_failures_to_generate = 5; s->super.time_reopen = 0; /* immediate */ s->super.connect = _connect_fail_first_time; s->super.fetch = _fetch; start_test_threaded_fetcher(s); wait_for_messages(s); stop_test_threaded_fetcher(s); StatsCounterItem *recvd_messages = _get_source(s)->metrics.recvd_messages; cr_assert(stats_counter_get(recvd_messages) == 10); cr_assert_geq(s->connect_counter, 6); destroy_test_threaded_fetcher(s); } static LogThreadedFetchResult _fetch_for_try_again_test(LogThreadedFetcherDriver *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *) s; if (self->try_again_first_time) { self->try_again_first_time = FALSE; return (LogThreadedFetchResult) { THREADED_FETCH_TRY_AGAIN, NULL }; } g_mutex_lock(&self->lock); if (self->num_of_messages_to_generate <= 0) { g_cond_signal(&self->cond); g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { THREADED_FETCH_ERROR, NULL }; } LogMessage *msg = create_sample_message(); self->num_of_messages_to_generate--; g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { .result = THREADED_FETCH_SUCCESS, .msg = msg }; } Test(logthrfetcherdrv, test_try_again) { TestThreadedFetcherDriver *s = create_threaded_fetcher(); s->try_again_first_time = TRUE; s->num_of_messages_to_generate = 1; s->super.time_reopen = 10; s->super.fetch = _fetch_for_try_again_test; struct timespec start = {0}; cr_assert(!clock_gettime(CLOCK_MONOTONIC, &start)); start_test_threaded_fetcher(s); wait_for_messages(s); stop_test_threaded_fetcher(s); struct timespec stop = {0}; cr_assert(!clock_gettime(CLOCK_MONOTONIC, &stop)); // Should not pass time_reopen in case of try_again cr_assert(!stop.tv_sec - start.tv_sec < 2); destroy_test_threaded_fetcher(s); } static LogThreadedFetchResult _fetch_for_no_data(LogThreadedFetcherDriver *s) { TestThreadedFetcherDriver *self = (TestThreadedFetcherDriver *) s; if (self->no_data_first_time) { self->no_data_first_time = FALSE; return (LogThreadedFetchResult) { THREADED_FETCH_NO_DATA, NULL }; } g_mutex_lock(&self->lock); if (self->num_of_messages_to_generate <= 0) { g_cond_signal(&self->cond); g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { THREADED_FETCH_ERROR, NULL }; } LogMessage *msg = create_sample_message(); self->num_of_messages_to_generate--; g_mutex_unlock(&self->lock); return (LogThreadedFetchResult) { .result = THREADED_FETCH_SUCCESS, .msg = msg }; } Test(logthrfetcherdrv, test_no_data) { TestThreadedFetcherDriver *s = create_threaded_fetcher(); s->no_data_first_time = TRUE; s->num_of_messages_to_generate = 1; log_threaded_fetcher_driver_set_fetch_no_data_delay(&s->super.super.super.super, 1); s->super.fetch = _fetch_for_no_data; struct timespec start = {0}; cr_assert(!clock_gettime(CLOCK_MONOTONIC, &start)); start_test_threaded_fetcher(s); wait_for_messages(s); stop_test_threaded_fetcher(s); struct timespec stop = {0}; cr_assert(!clock_gettime(CLOCK_MONOTONIC, &stop)); cr_assert(stop.tv_sec - start.tv_sec >= 1); destroy_test_threaded_fetcher(s); } syslog-ng-syslog-ng-4.4.0/lib/logthrsource/tests/test_logthrsourcedrv.c000066400000000000000000000145241450431004300264500ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "logthrsource/logthrsourcedrv.h" #include "apphook.h" #include "mainloop.h" #include "mainloop-worker.h" #include "cfg.h" #include "stats/stats-counter.h" #include "logsource.h" typedef struct _TestThreadedSourceDriver { LogThreadedSourceDriver super; gint num_of_messages_to_generate; gboolean suspended; gboolean exit_requested; } TestThreadedSourceDriver; MainLoopOptions main_loop_options = {0}; MainLoop *main_loop; static void _request_exit(LogThreadedSourceDriver *s); static void _run_simple(LogThreadedSourceDriver *s); static void _run_using_blocking_posts(LogThreadedSourceDriver *s); static const gchar * _generate_persist_name(const LogPipe *s) { return "test_threaded_source_driver"; } static void _format_stats_key(LogThreadedSourceDriver *s, StatsClusterKeyBuilder *kb) { stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "test_threaded_source_driver_stats")); } static void _source_queue_mock(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogSource *self = (LogSource *) s; stats_counter_inc(self->metrics.recvd_messages); log_pipe_forward_msg(s, msg, path_options); } static LogSource * _get_source(TestThreadedSourceDriver *self) { return (LogSource *) self->super.worker; } gboolean test_threaded_source_driver_init_method(LogPipe *s) { TestThreadedSourceDriver *self = (TestThreadedSourceDriver *)s; if (!log_threaded_source_driver_init_method(s)) return FALSE; /* mock out the hard-coded DNS lookup calls inside log_source_queue() */ _get_source(self)->super.queue = _source_queue_mock; return TRUE; } static TestThreadedSourceDriver * test_threaded_sd_new(GlobalConfig *cfg, gboolean blocking_post) { TestThreadedSourceDriver *self = g_new0(TestThreadedSourceDriver, 1); log_threaded_source_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = test_threaded_source_driver_init_method; self->super.format_stats_key = _format_stats_key; self->super.super.super.super.generate_persist_name = _generate_persist_name; self->super.request_exit = _request_exit; if (blocking_post) self->super.run = _run_using_blocking_posts; else self->super.run = _run_simple; return self; } static TestThreadedSourceDriver * create_threaded_source(void) { return test_threaded_sd_new(main_loop_get_current_config(main_loop), FALSE); } static TestThreadedSourceDriver * create_threaded_source_blocking(void) { return test_threaded_sd_new(main_loop_get_current_config(main_loop), TRUE); } static void start_test_threaded_source(TestThreadedSourceDriver *s) { cr_assert(log_pipe_init(&s->super.super.super.super)); cr_assert(log_pipe_post_config_init(&s->super.super.super.super)); } static void request_exit_and_wait_for_stop(TestThreadedSourceDriver *s) { main_loop_sync_worker_startup_and_teardown(); } static void destroy_test_threaded_source(TestThreadedSourceDriver *s) { cr_assert(log_pipe_deinit(&s->super.super.super.super)); log_pipe_unref(&s->super.super.super.super); } static void setup(void) { app_startup(); main_loop = main_loop_get_instance(); main_loop_init(main_loop, &main_loop_options); } static void teardown(void) { main_loop_deinit(main_loop); app_shutdown(); } static void _run_using_blocking_posts(LogThreadedSourceDriver *s) { TestThreadedSourceDriver *self = (TestThreadedSourceDriver *) s; for (gint i = 0; i < self->num_of_messages_to_generate; ++i) { LogMessage *msg = create_sample_message(); log_threaded_source_blocking_post(&self->super, msg); } } static void _run_simple(LogThreadedSourceDriver *s) { TestThreadedSourceDriver *self = (TestThreadedSourceDriver *) s; for (gint i = 0; i < self->num_of_messages_to_generate; ++i) { LogMessage *msg = create_sample_message(); log_threaded_source_post(&self->super, msg); if (!log_threaded_source_free_to_send(&self->super)) { self->suspended = TRUE; break; } } } static void _request_exit(LogThreadedSourceDriver *s) { TestThreadedSourceDriver *self = (TestThreadedSourceDriver *) s; self->exit_requested = TRUE; } static void _do_not_ack_messages(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { log_msg_unref(msg); } TestSuite(logthrsourcedrv, .init = setup, .fini = teardown, .timeout = 10); Test(logthrsourcedrv, test_threaded_source_blocking_post) { TestThreadedSourceDriver *s = create_threaded_source_blocking(); s->num_of_messages_to_generate = 10; start_test_threaded_source(s); request_exit_and_wait_for_stop(s); StatsCounterItem *recvd_messages = _get_source(s)->metrics.recvd_messages; cr_assert(stats_counter_get(recvd_messages) == 10); cr_assert(s->exit_requested); destroy_test_threaded_source(s); } Test(logthrsourcedrv, test_threaded_source_suspend) { TestThreadedSourceDriver *s = create_threaded_source(); s->num_of_messages_to_generate = 5; s->super.worker_options.super.init_window_size = 5; s->super.super.super.super.queue = _do_not_ack_messages; start_test_threaded_source(s); request_exit_and_wait_for_stop(s); StatsCounterItem *recvd_messages = _get_source(s)->metrics.recvd_messages; cr_assert(stats_counter_get(recvd_messages) == 5); cr_assert(s->suspended); cr_assert(s->exit_requested); destroy_test_threaded_source(s); } syslog-ng-syslog-ng-4.4.0/lib/logwriter.c000066400000000000000000001741301450431004300203110ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logwriter.h" #include "messages.h" #include "stats/stats-registry.h" #include "stats/aggregator/stats-aggregator-registry.h" #include "stats/stats-cluster-single.h" #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-compat.h" #include "hostname.h" #include "host-resolve.h" #include "seqnum.h" #include "str-utils.h" #include "find-crlf.h" #include "mainloop.h" #include "mainloop-io-worker.h" #include "mainloop-call.h" #include "ml-batched-timer.h" #include "str-format.h" #include "scratch-buffers.h" #include "timeutils/format.h" #include "timeutils/misc.h" #include #include #include #include #include #include #include #include typedef enum { /* flush modes */ /* business as usual, flush when the buffer is full */ LW_FLUSH_NORMAL, /* flush the buffer immediately please */ LW_FLUSH_FORCE, } LogWriterFlushMode; struct _LogWriter { LogPipe super; LogQueue *queue; guint32 flags:31; gint32 seq_num; gboolean partial_write; struct { StatsClusterKeyBuilder *stats_kb; StatsClusterKey *output_events_key; StatsCounterItem *dropped_messages; StatsCounterItem *suppressed_messages; StatsCounterItem *processed_messages; StatsCounterItem *written_messages; StatsClusterKey *written_bytes_key; StatsByteCounter written_bytes; StatsAggregator *max_message_size; StatsAggregator *average_messages_size; StatsAggregator *CPS; StatsClusterKey *message_delay_key; StatsCounterItem *message_delay; StatsClusterKey *message_delay_sample_age_key; StatsCounterItem *message_delay_sample_age; struct { StatsCounterItem *count; StatsCounterItem *bytes; } truncated; } metrics; LogPipe *control; LogWriterOptions *options; LogMessage *last_msg; guint32 last_msg_count; time_t last_delay_update; GString *line_buffer; gchar *stats_id; struct iv_fd fd_watch; struct iv_timer suspend_timer; struct iv_task immed_io_task; struct iv_event queue_filled; MainLoopIOWorkerJob io_job; GMutex suppress_lock; MlBatchedTimer suppress_timer; MlBatchedTimer mark_timer; struct iv_timer reopen_timer; struct iv_timer idle_timer; gboolean work_result; gint pollable_state; LogProtoClient *proto, *pending_proto; guint watches_running:1, suspended:1, waiting_for_throttle:1; gboolean pending_proto_present; GCond pending_proto_cond; GMutex pending_proto_lock; }; /** * LogWriter behaviour * ~~~~~~~~~~~~~~~~~~~ * * LogWriter is a core element of syslog-ng sending messages out to some * kind of destination represented by a UNIX fd. Outgoing messages are sent * to the target asynchronously, first by placing them to a queue and then * sending messages when poll() indicates that the fd is writable. * * * Flow control * ------------ * For a simple log writer without a disk buffer messages are placed on a * GQueue and they are acknowledged when the send() system call returned * success. This is more complex when disk buffering is used, in which case * messages are put to the "disk buffer" first and acknowledged immediately. * (this way the reader never stops when the disk buffer area is not yet * full). When disk buffer reaches its limit, messages are added to the * usual GQueue and messages get acknowledged when they are moved to the * disk buffer. * **/ static gboolean log_writer_process_out(LogWriter *self); static gboolean log_writer_process_in(LogWriter *self); static void log_writer_broken(LogWriter *self, gint notify_code); static void log_writer_start_watches(LogWriter *self); static void log_writer_stop_watches(LogWriter *self); static void log_writer_stop_idle_timer(LogWriter *self); static void log_writer_update_watches(LogWriter *self); static void log_writer_suspend(LogWriter *self); static void log_writer_free_proto(LogWriter *self); static void log_writer_set_proto(LogWriter *self, LogProtoClient *proto); static void log_writer_set_pending_proto(LogWriter *self, LogProtoClient *proto, gboolean present); static void log_writer_msg_ack(gint num_msg_acked, gpointer user_data) { LogWriter *self = (LogWriter *)user_data; log_queue_ack_backlog(self->queue, num_msg_acked); } void log_writer_msg_rewind(LogWriter *self) { log_queue_rewind_backlog_all(self->queue); } static void log_writer_msg_rewind_cb(gpointer user_data) { LogWriter *self = (LogWriter *)user_data; log_writer_msg_rewind(self); } void log_writer_set_flags(LogWriter *self, guint32 flags) { g_assert((self->super.flags & PIF_INITIALIZED) == 0); self->flags = flags; } guint32 log_writer_get_flags(LogWriter *self) { return self->flags; } /* returns a reference */ LogQueue * log_writer_get_queue(LogWriter *s) { LogWriter *self = (LogWriter *) s; return log_queue_ref(self->queue); } /* consumes the reference */ void log_writer_set_queue(LogWriter *self, LogQueue *queue) { log_queue_unref(self->queue); self->queue = log_queue_ref(queue); } static void log_writer_work_perform(gpointer s, gpointer arg) { LogWriter *self = (LogWriter *) s; GIOCondition cond = GPOINTER_TO_INT(arg); g_assert((self->super.flags & PIF_INITIALIZED) != 0); g_assert((cond == G_IO_OUT) || (cond == G_IO_IN)); if (cond == G_IO_OUT) self->work_result = log_writer_process_out(self); else if (cond == G_IO_IN) self->work_result = log_writer_process_in(self); } static void log_writer_work_finished(gpointer s, gpointer arg) { LogWriter *self = (LogWriter *) s; main_loop_assert_main_thread(); self->waiting_for_throttle = FALSE; if (self->pending_proto_present) { /* pending proto is only set in the main thread, so no need to * lock it before coming here. After we're syncing with the * log_writer_reopen() call, quite possibly coming from a * non-main thread. */ g_mutex_lock(&self->pending_proto_lock); log_writer_free_proto(self); log_writer_set_proto(self, self->pending_proto); log_writer_set_pending_proto(self, NULL, FALSE); g_cond_signal(&self->pending_proto_cond); g_mutex_unlock(&self->pending_proto_lock); } if (!self->work_result) { log_writer_broken(self, NC_WRITE_ERROR); if (self->proto) { log_writer_suspend(self); msg_notice("Suspending write operation because of an I/O error", evt_tag_int("fd", log_proto_client_get_fd(self->proto)), evt_tag_int("time_reopen", self->options->time_reopen)); } return; } if ((self->super.flags & PIF_INITIALIZED) && self->proto) { /* reenable polling the source, but only if we're still initialized */ log_writer_start_watches(self); } } static void log_writer_io_handler(gpointer s, GIOCondition cond) { LogWriter *self = (LogWriter *) s; main_loop_assert_main_thread(); log_writer_stop_watches(self); if ((self->options->options & LWO_THREADED)) { main_loop_io_worker_job_submit(&self->io_job, GINT_TO_POINTER(cond)); } else { /* Checking main_loop_io_worker_job_quit() helps to speed up the * reload process. If reload/shutdown is requested we shouldn't do * anything here, a final flush will be attempted in * log_writer_deinit(). * * Our current understanding is that it doesn't prevent race * conditions of any kind. */ if (!main_loop_worker_job_quit()) { log_pipe_ref(&self->super); log_writer_work_perform(s, GINT_TO_POINTER(cond)); log_writer_work_finished(s, NULL); log_pipe_unref(&self->super); } } } static void log_writer_io_handle_out(gpointer s) { log_writer_io_handler(s, G_IO_OUT); } static void log_writer_io_handle_in(gpointer s) { log_writer_io_handler(s, G_IO_IN); } static void log_writer_io_error(gpointer s) { LogWriter *self = (LogWriter *) s; if (self->fd_watch.handler_out == NULL && self->fd_watch.handler_in == NULL) { msg_debug("POLLERR occurred while idle", evt_tag_int("fd", log_proto_client_get_fd(self->proto))); log_writer_broken(self, NC_WRITE_ERROR); return; } else { /* in case we have an error state but we also asked for read/write * polling, the error should be handled by the I/O callback. But we * need not call that explicitly as ivykis does that for us. */ } log_writer_update_watches(self); } static void log_writer_io_check_eof(gpointer s) { LogWriter *self = (LogWriter *) s; msg_error("EOF occurred while idle", evt_tag_int("fd", log_proto_client_get_fd(self->proto))); log_writer_broken(self, NC_CLOSE); } static void log_writer_error_suspend_elapsed(gpointer s) { LogWriter *self = (LogWriter *) s; self->suspended = FALSE; msg_notice("Error suspend timeout has elapsed, attempting to write again", evt_tag_int("fd", log_proto_client_get_fd(self->proto))); log_writer_start_watches(self); } static void log_writer_update_fd_callbacks(LogWriter *self, GIOCondition cond) { main_loop_assert_main_thread(); if (self->pollable_state > 0) { if (cond & G_IO_IN) iv_fd_set_handler_in(&self->fd_watch, log_writer_io_handle_in); else if (self->flags & LW_DETECT_EOF) iv_fd_set_handler_in(&self->fd_watch, log_writer_io_check_eof); else iv_fd_set_handler_in(&self->fd_watch, NULL); if (cond & G_IO_OUT) iv_fd_set_handler_out(&self->fd_watch, log_writer_io_handle_out); else iv_fd_set_handler_out(&self->fd_watch, NULL); iv_fd_set_handler_err(&self->fd_watch, log_writer_io_error); } else { /* fd is not pollable, assume it is always writable */ if (cond & G_IO_OUT) { if (!iv_task_registered(&self->immed_io_task)) iv_task_register(&self->immed_io_task); } else if (iv_task_registered(&self->immed_io_task)) { iv_task_unregister(&self->immed_io_task); } } } static void log_writer_stop_suspend_timer(LogWriter *self) { if (iv_timer_registered(&self->suspend_timer)) iv_timer_unregister(&self->suspend_timer); } static void log_writer_arm_suspend_timer(LogWriter *self, void (*handler)(void *), glong timeout_msec) { main_loop_assert_main_thread(); log_writer_stop_suspend_timer(self); iv_validate_now(); self->suspend_timer.handler = handler; self->suspend_timer.expires = iv_now; timespec_add_msec(&self->suspend_timer.expires, timeout_msec); iv_timer_register(&self->suspend_timer); } static void log_writer_queue_filled(gpointer s) { LogWriter *self = (LogWriter *) s; main_loop_assert_main_thread(); /* * NOTE: This theory is somewhat questionable, e.g. I'm not 100% sure it * is the right scenario, but the race was closed. So take this with a * grain of salt. * * The queue_filled callback is running in the main thread. Because of the * possible delay caused by iv_event_post() the callback might be * delivered event after stop_watches() has been called. * * - log_writer_schedule_update_watches() is called by the reader * thread, which calls iv_event_post() * - the main thread calls stop_watches() in work_perform * - the event is delivered in the main thread * * But since stop/start watches always run in the main thread and we do * too, we can check if this is the case. A LogWriter without watches * running is busy writing out data to the destination, e.g. a * start_watches is to be expected once log_writer_work_finished() is run * at the end of the deferred work, executed by the I/O threads. */ if (self->watches_running) log_writer_update_watches((LogWriter *) s); } /* NOTE: runs in the source thread */ static void log_writer_schedule_update_watches(LogWriter *self) { iv_event_post(&self->queue_filled); } static void log_writer_suspend(LogWriter *self) { /* flush code indicates that we need to suspend our writing activities * until time_reopen elapses */ log_writer_arm_suspend_timer(self, log_writer_error_suspend_elapsed, self->options->time_reopen * 1000L); self->suspended = TRUE; } static void log_writer_update_watches(LogWriter *self) { gint fd; GIOCondition cond = 0; gint timeout_msec = 0; gint idle_timeout = -1; main_loop_assert_main_thread(); log_writer_stop_idle_timer(self); /* NOTE: we either start the suspend_timer or enable the fd_watch. The two MUST not happen at the same time. */ if (log_proto_client_prepare(self->proto, &fd, &cond, &idle_timeout) || self->waiting_for_throttle || log_queue_check_items(self->queue, &timeout_msec, (LogQueuePushNotifyFunc) log_writer_schedule_update_watches, self, NULL)) { /* flush_lines number of element is already available and throttle would permit us to send. */ log_writer_update_fd_callbacks(self, cond); } else if (timeout_msec) { /* few elements are available, but less than flush_lines, we need to start a timer to initiate a flush */ log_writer_update_fd_callbacks(self, 0); self->waiting_for_throttle = TRUE; log_writer_arm_suspend_timer(self, (void (*)(void *)) log_writer_update_watches, (glong)timeout_msec); } else { /* no elements or no throttle space, wait for a wakeup by the queue * when the required number of items are added. see the * log_queue_check_items and its parallel_push argument above */ log_writer_update_fd_callbacks(self, 0); } if (idle_timeout > 0) { iv_validate_now(); self->idle_timer.expires = iv_now; self->idle_timer.expires.tv_sec += idle_timeout; iv_timer_register(&self->idle_timer); } } static gboolean is_file_regular(gint fd) { struct stat st; if (fstat(fd, &st) >= 0) { return S_ISREG(st.st_mode); } /* if stat fails, that's interesting, but we should probably poll * it, hopefully that's less likely to cause spinning */ return FALSE; } static void log_writer_start_watches(LogWriter *self) { gint fd; GIOCondition cond; gint idle_timeout = -1; if (self->watches_running) return; log_proto_client_prepare(self->proto, &fd, &cond, &idle_timeout); self->fd_watch.fd = fd; if (self->pollable_state < 0) { if (is_file_regular(fd)) self->pollable_state = 0; else self->pollable_state = !iv_fd_register_try(&self->fd_watch); } else if (self->pollable_state > 0) iv_fd_register(&self->fd_watch); log_writer_update_watches(self); self->watches_running = TRUE; } static void log_writer_stop_watches(LogWriter *self) { if (self->watches_running) { if (iv_timer_registered(&self->reopen_timer)) iv_timer_unregister(&self->reopen_timer); if (iv_fd_registered(&self->fd_watch)) iv_fd_unregister(&self->fd_watch); if (iv_task_registered(&self->immed_io_task)) iv_task_unregister(&self->immed_io_task); log_queue_reset_parallel_push(self->queue); self->watches_running = FALSE; } log_writer_stop_suspend_timer(self); log_writer_stop_idle_timer(self); } static void log_writer_stop_idle_timer(LogWriter *self) { if (iv_timer_registered(&self->idle_timer)) iv_timer_unregister(&self->idle_timer); } static void log_writer_arm_suppress_timer(LogWriter *self) { ml_batched_timer_postpone(&self->suppress_timer, self->options->suppress); } /** * Remember the last message for dup detection. * * NOTE: suppress_lock must be held. **/ static void log_writer_record_last_message(LogWriter *self, LogMessage *lm) { if (self->last_msg) log_msg_unref(self->last_msg); log_msg_ref(lm); self->last_msg = lm; self->last_msg_count = 0; } /* * NOTE: suppress_lock must be held. */ static void log_writer_release_last_message(LogWriter *self) { if (self->last_msg) log_msg_unref(self->last_msg); self->last_msg = NULL; self->last_msg_count = 0; } /* * NOTE: suppress_lock must be held. */ static void log_writer_emit_suppress_summary(LogWriter *self) { LogMessage *m; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; gchar buf[1024]; gssize len; const gchar *p; msg_debug("Suppress timer elapsed, emitting suppression summary"); len = g_snprintf(buf, sizeof(buf), "Last message '%.20s' repeated %d times, suppressed by syslog-ng on %s", log_msg_get_value(self->last_msg, LM_V_MESSAGE, NULL), self->last_msg_count, get_local_hostname_fqdn()); m = log_msg_new_internal(self->last_msg->pri, buf); p = log_msg_get_value(self->last_msg, LM_V_HOST, &len); log_msg_set_value(m, LM_V_HOST, p, len); p = log_msg_get_value(self->last_msg, LM_V_PROGRAM, &len); log_msg_set_value(m, LM_V_PROGRAM, p, len); path_options.ack_needed = FALSE; log_queue_push_tail(self->queue, m, &path_options); log_writer_release_last_message(self); } static gboolean log_writer_suppress_timeout(gpointer pt) { LogWriter *self = (LogWriter *) pt; main_loop_assert_main_thread(); /* NOTE: this will probably do nothing as we are the timer callback, but * we may not do it with the suppress_lock held */ ml_batched_timer_cancel(&self->suppress_timer); g_mutex_lock(&self->suppress_lock); /* NOTE: we may be waken up an extra time if the suppress_timer setup race * is lost, see the comment at log_writer_is_msg_suppressed() for an * explanation */ if (self->last_msg_count > 0) log_writer_emit_suppress_summary(self); g_mutex_unlock(&self->suppress_lock); return FALSE; } static gboolean _is_message_a_mark(LogMessage *msg) { gssize msg_len; const gchar *value = log_msg_get_value(msg, LM_V_MESSAGE, &msg_len); return strncmp(value, "-- MARK --", msg_len) == 0; } static gboolean _is_message_a_repetition(LogMessage *msg, LogMessage *last) { return strcmp(log_msg_get_value(last, LM_V_MESSAGE, NULL), log_msg_get_value(msg, LM_V_MESSAGE, NULL)) == 0 && strcmp(log_msg_get_value(last, LM_V_HOST, NULL), log_msg_get_value(msg, LM_V_HOST, NULL)) == 0 && strcmp(log_msg_get_value(last, LM_V_PROGRAM, NULL), log_msg_get_value(msg, LM_V_PROGRAM, NULL)) == 0 && strcmp(log_msg_get_value(last, LM_V_PID, NULL), log_msg_get_value(msg, LM_V_PID, NULL)) == 0; } static gboolean _is_time_within_the_suppress_timeout(LogWriter *self, LogMessage *msg) { return self->last_msg->timestamps[LM_TS_RECVD].ut_sec >= msg->timestamps[LM_TS_RECVD].ut_sec - self->options->suppress; } /** * log_writer_is_msg_suppressed: * * This function is called to suppress duplicate messages from a given host. * * Locking notes: * * There's a strict ordering requirement between suppress_lock and * interacting with the main loop (which ml_batched_timer beind * suppress_timer is doing). * * The reason is that the main thread (running * the main loop) sometimes acquires suppress_lock (at suppress timer * expiration) and while blocking on suppress_lock it cannot service * main_loop_calls() * * This function makes it sure that ml_batched_timer_update/cancel calls are * only done with the suppress lock released. * * If we do this, we might have a few unfortunate side effects due to races * that we also try to handle: * * Two messages race, one of these matches the recorded last message, * the other doesn't. In this case, moving the update on the suppress_timer * outside of the lock region might cause two different races: * * 1) matching message comes first, then non-matching * * This case the suppress_lock protected region decides that the suppress * timer needs to fire (#1) and then the other decides that it needs to * be cancelled. (#2) * * If these are processed in order, then we are the same as if the two was * also protected by the mutex (which is ok) * * If they are reversed, e.g. we first cancels the timer and the second arms it, * then we might have a timer wakeup which will find no suppressed messages * to report (as the non-matching message will set last_msg_count to zero). This * spurious wakeup should be handled by the expiration callback. * * 1) non-matching message comes first, then matching * * This is simply a message reordering case, e.g. we don't * want any suppressions to be emitted. * * In this case the locked regions finds that neither messages matched * the recorded one, thus both times they decide to cancel the timer, which * is ok. Timer cancellation can be reordered as they will have the same * effect anyway. * * Returns TRUE to indicate that the message is to be suppressed. **/ static gboolean log_writer_is_msg_suppressed(LogWriter *self, LogMessage *lm) { gboolean need_to_arm_suppress_timer; gboolean need_to_cancel_suppress_timer = FALSE; if (self->options->suppress <= 0) return FALSE; g_mutex_lock(&self->suppress_lock); if (self->last_msg) { if (_is_time_within_the_suppress_timeout(self, lm) && _is_message_a_repetition(lm, self->last_msg) && !_is_message_a_mark(lm)) { stats_counter_inc(self->metrics.suppressed_messages); self->last_msg_count++; /* we only create the timer if this is the first suppressed message, otherwise it is already running. */ need_to_arm_suppress_timer = self->last_msg_count == 1; g_mutex_unlock(&self->suppress_lock); /* this has to be outside of suppress_lock */ if (need_to_arm_suppress_timer) log_writer_arm_suppress_timer(self); msg_debug("Suppressing duplicate message", evt_tag_str("host", log_msg_get_value(lm, LM_V_HOST, NULL)), evt_tag_str("msg", log_msg_get_value(lm, LM_V_MESSAGE, NULL))); return TRUE; } else { if (self->last_msg_count) log_writer_emit_suppress_summary(self); else log_writer_release_last_message(self); need_to_cancel_suppress_timer = TRUE; } } log_writer_record_last_message(self, lm); g_mutex_unlock(&self->suppress_lock); if (need_to_cancel_suppress_timer) ml_batched_timer_cancel(&self->suppress_timer); return FALSE; } static void log_writer_postpone_mark_timer(LogWriter *self) { if (self->options->mark_freq > 0) ml_batched_timer_postpone(&self->mark_timer, self->options->mark_freq); } /* this is the callback function that gets called when the MARK timeout * elapsed. It runs in the main thread. */ static void log_writer_mark_timeout(void *cookie) { LogWriter *self = (LogWriter *)cookie; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; const gchar *hostname; gsize hostname_len; LogMessage *msg; main_loop_assert_main_thread(); msg = log_msg_new_mark(); path_options.ack_needed = FALSE; /* timeout: there was no new message on the writer or it is in periodical mode */ hostname = resolve_sockaddr_to_hostname(&hostname_len, msg->saddr, &self->options->host_resolve_options); log_msg_set_value(msg, LM_V_HOST, hostname, hostname_len); if (!log_writer_is_msg_suppressed(self, msg)) { log_queue_push_tail(self->queue, msg, &path_options); stats_counter_inc(self->metrics.processed_messages); } else { log_msg_drop(msg, &path_options, AT_PROCESSED); } /* we need to issue another MARK in all mark-mode cases that already * triggered this callback (dst-idle, host-idle, periodical). The * original setup of the timer is at a different location: * - log_writer_queue() for "*-idle" modes * - log_writer_init() for periodical mode */ log_writer_postpone_mark_timer(self); } /* NOTE: runs in the reader thread */ static void log_writer_queue(LogPipe *s, LogMessage *lm, const LogPathOptions *path_options) { LogWriter *self = (LogWriter *) s; LogPathOptions local_options; gint mark_mode = self->options->mark_mode; if (!path_options->flow_control_requested && ((self->proto == NULL || self->suspended) || !(self->flags & LW_SOFT_FLOW_CONTROL))) { /* NOTE: this code ACKs the message back if there's a write error in * order not to hang the client in case of a disk full */ path_options = log_msg_break_ack(lm, path_options, &local_options); } if (log_writer_is_msg_suppressed(self, lm)) { log_msg_drop(lm, path_options, AT_PROCESSED); return; } if (mark_mode != MM_INTERNAL && (lm->flags & LF_INTERNAL) && (lm->flags & LF_MARK)) { /* drop MARK messages generated by internal() in case our mark-mode != internal */ log_msg_drop(lm, path_options, AT_PROCESSED); return; } if (mark_mode == MM_DST_IDLE || (mark_mode == MM_HOST_IDLE && !(lm->flags & LF_LOCAL))) { /* in dst-idle and host-idle most, messages postpone the MARK itself */ log_writer_postpone_mark_timer(self); } stats_counter_inc(self->metrics.processed_messages); log_queue_push_tail(self->queue, lm, path_options); } static void log_writer_append_value(GString *result, LogMessage *lm, NVHandle handle, gboolean use_nil, gboolean append_space) { const gchar *value; gssize value_len; value = log_msg_get_value(lm, handle, &value_len); if (use_nil && value_len == 0) g_string_append_c(result, '-'); else { gchar *space; space = strchr(value, ' '); if (!space) g_string_append_len(result, value, value_len); else g_string_append_len(result, value, space - value); } if (append_space) g_string_append_c(result, ' '); } static void log_writer_do_padding(LogWriter *self, GString *result) { if (!self->options->padding) return; if(G_UNLIKELY(self->options->padding < result->len)) { msg_warning("Padding is too small to hold the full message", evt_tag_int("padding", self->options->padding), evt_tag_int("msg_size", result->len)); g_string_set_size(result, self->options->padding); return; } /* store the original length of the result */ gint len = result->len; gint padd_bytes = self->options->padding - result->len; /* set the size to the padded size, this will allocate the string */ g_string_set_size(result, self->options->padding); memset(result->str + len - 1, '\0', padd_bytes); } void log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result) { LogTemplate *template = NULL; UnixTime *stamp; guint32 seq_num; static NVHandle meta_seqid = 0; if (!meta_seqid) meta_seqid = log_msg_get_value_handle(".SDATA.meta.sequenceId"); if (lm->flags & LF_LOCAL) { seq_num = self->seq_num; } else { const gchar *seqid; gssize seqid_length; seqid = log_msg_get_value(lm, meta_seqid, &seqid_length); APPEND_ZERO(seqid, seqid, seqid_length); if (seqid[0]) seq_num = strtol(seqid, NULL, 10); else seq_num = 0; } /* no template was specified, use default */ stamp = &lm->timestamps[LM_TS_STAMP]; g_string_truncate(result, 0); if ((self->flags & LW_SYSLOG_PROTOCOL) || (self->options->options & LWO_SYSLOG_PROTOCOL)) { gssize len; /* we currently hard-wire version 1 */ g_string_append_c(result, '<'); format_uint32_padded(result, 0, 0, 10, lm->pri); g_string_append_c(result, '>'); g_string_append_c(result, '1'); g_string_append_c(result, ' '); append_format_unix_time(stamp, result, TS_FMT_ISO, time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->ut_sec), self->options->template_options.frac_digits); g_string_append_c(result, ' '); log_writer_append_value(result, lm, LM_V_HOST, TRUE, TRUE); log_writer_append_value(result, lm, LM_V_PROGRAM, TRUE, TRUE); log_writer_append_value(result, lm, LM_V_PID, TRUE, TRUE); log_writer_append_value(result, lm, LM_V_MSGID, TRUE, TRUE); len = result->len; log_msg_append_format_sdata(lm, result, seq_num); if (len == result->len) { /* NOTE: sd_param format did not generate any output, take it as an empty SD string */ g_string_append_c(result, '-'); } if (self->options->template) { g_string_append_c(result, ' '); if (lm->flags & LF_UTF8) g_string_append_len(result, "\xEF\xBB\xBF", 3); LogTemplateEvalOptions options = { &self->options->template_options, LTZ_SEND, seq_num, NULL, LM_VT_STRING }; log_template_append_format(self->options->template, lm, &options, result); } else { const gchar *p; p = log_msg_get_value(lm, LM_V_MESSAGE, &len); g_string_append_c(result, ' '); if (len != 0) { if (lm->flags & LF_UTF8) g_string_append_len(result, "\xEF\xBB\xBF", 3); g_string_append_len(result, p, len); } } g_string_append_c(result, '\n'); log_writer_do_padding(self, result); } else { if (self->options->template) { template = self->options->template; } else if (self->flags & LW_FORMAT_FILE) { template = self->options->file_template; } else if ((self->flags & LW_FORMAT_PROTO)) { template = self->options->proto_template; } if (template) { LogTemplateEvalOptions options = { &self->options->template_options, LTZ_SEND, seq_num, NULL, LM_VT_STRING }; log_template_format(template, lm, &options, result); } else { const gchar *p; gssize len; if (self->flags & LW_FORMAT_FILE) { format_unix_time(stamp, result, self->options->template_options.ts_format, time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->ut_sec), self->options->template_options.frac_digits); } else if (self->flags & LW_FORMAT_PROTO) { g_string_append_c(result, '<'); format_uint32_padded(result, 0, 0, 10, lm->pri); g_string_append_c(result, '>'); /* always use BSD timestamp by default, the use can override this using a custom template */ append_format_unix_time(stamp, result, TS_FMT_BSD, time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->ut_sec), self->options->template_options.frac_digits); } g_string_append_c(result, ' '); p = log_msg_get_value(lm, LM_V_HOST, &len); g_string_append_len(result, p, len); g_string_append_c(result, ' '); p = log_msg_get_value(lm, LM_V_LEGACY_MSGHDR, &len); if (len > 0) { g_string_append_len(result, p, len); } else { p = log_msg_get_value(lm, LM_V_PROGRAM, &len); if (len > 0) { g_string_append_len(result, p, len); p = log_msg_get_value(lm, LM_V_PID, &len); if (len > 0) { g_string_append_c(result, '['); g_string_append_len(result, p, len); g_string_append_c(result, ']'); } g_string_append_len(result, ": ", 2); } } p = log_msg_get_value(lm, LM_V_MESSAGE, &len); g_string_append_len(result, p, len); g_string_append_c(result, '\n'); log_writer_do_padding(self, result); } } if (self->options->options & LWO_NO_MULTI_LINE) { gchar *p; p = result->str; /* NOTE: the size is calculated to leave trailing new line */ while ((p = find_cr_or_lf_or_nul(p, result->str + result->len - p - 1))) { *p = ' '; p++; } } if (self->options->truncate_size != -1 && result->len > self->options->truncate_size) { const gint truncated_bytes = result->len - self->options->truncate_size; g_string_truncate(result, self->options->truncate_size); stats_counter_inc(self->metrics.truncated.count); stats_counter_add(self->metrics.truncated.bytes, truncated_bytes); } } static void log_writer_broken(LogWriter *self, gint notify_code) { log_writer_stop_watches(self); log_pipe_notify(self->control, notify_code, self); } static void log_writer_realloc_line_buffer(LogWriter *self) { self->line_buffer->str = g_malloc(self->line_buffer->allocated_len); self->line_buffer->str[0] = 0; self->line_buffer->len = 0; } /* * Write messages to the underlying file descriptor using the installed * LogProtoClient instance. This is called whenever the output is ready to accept * further messages, and once during config deinitialization, in order to * flush messages still in the queue, in the hope that most of them can be * written out. * * In threaded mode, this function is invoked as part of the "output" task * (in essence, this is the function that performs the output task). * */ static gboolean log_writer_flush_finalize(LogWriter *self) { LogProtoStatus status = log_proto_client_flush(self->proto); if (status == LPS_SUCCESS || status == LPS_PARTIAL) return TRUE; return FALSE; } static void log_writer_update_message_stats(LogWriter *self, const LogMessage *msg, gsize msg_len) { stats_aggregator_add_data_point(self->metrics.max_message_size, msg_len); stats_aggregator_add_data_point(self->metrics.average_messages_size, msg_len); if (self->metrics.message_delay) { UnixTime now; unix_time_set_now(&now); gint64 diff = unix_time_diff_in_msec(&now, &msg->timestamps[LM_TS_RECVD]); if (self->last_delay_update != now.ut_sec) { stats_counter_set_time(self->metrics.message_delay, diff); stats_counter_set_time(self->metrics.message_delay_sample_age, now.ut_sec); self->last_delay_update = now.ut_sec; } } } static gboolean log_writer_write_message(LogWriter *self, LogMessage *msg, LogPathOptions *path_options, gboolean *write_error) { gboolean consumed = FALSE; *write_error = FALSE; log_msg_refcache_start_consumer(msg, path_options); msg_set_context(msg); log_writer_format_log(self, msg, self->line_buffer); if (!(msg->flags & LF_INTERNAL)) { msg_debug("Outgoing message", evt_tag_printf("message", "%s", self->line_buffer->str)); } gsize msg_len = 0; if (self->line_buffer->len) { msg_len = self->line_buffer->len; LogProtoStatus status = log_proto_client_post(self->proto, msg, (guchar *)self->line_buffer->str, self->line_buffer->len, &consumed); self->partial_write = (status == LPS_PARTIAL); if (consumed) log_writer_realloc_line_buffer(self); if (status == LPS_ERROR) { if ((self->options->options & LWO_IGNORE_ERRORS) != 0) { if (!consumed) { g_free(self->line_buffer->str); log_writer_realloc_line_buffer(self); consumed = TRUE; } } else { *write_error = TRUE; consumed = FALSE; } } } else { msg_debug("Error posting log message as template() output resulted in an empty string, skipping message"); consumed = TRUE; } if (consumed) { if (msg->flags & LF_LOCAL) step_sequence_number(&self->seq_num); log_writer_update_message_stats(self, msg, msg_len); stats_byte_counter_add(&self->metrics.written_bytes, msg_len); log_msg_unref(msg); msg_set_context(NULL); log_msg_refcache_stop(); return TRUE; } else { msg_debug("Can't send the message rewind backlog", evt_tag_printf("message", "%s", self->line_buffer->str)); log_queue_rewind_backlog(self->queue, 1); log_msg_unref(msg); msg_set_context(NULL); log_msg_refcache_stop(); return FALSE; } } static inline LogMessage * log_writer_queue_pop_message(LogWriter *self, LogPathOptions *path_options, gboolean force_flush) { if (force_flush) return log_queue_pop_head_ignore_throttle(self->queue, path_options); else return log_queue_pop_head(self->queue, path_options); } static inline gboolean log_writer_process_handshake(LogWriter *self) { LogProtoStatus status = log_proto_client_handshake(self->proto); if (status != LPS_SUCCESS) return FALSE; return TRUE; } /* * @flush_mode specifies how hard LogWriter is trying to send messages to * the actual destination: * * * LW_FLUSH_NORMAL - business as usual, flush when the buffer is full * LW_FLUSH_FORCE - flush the buffer immediately please * */ static gboolean log_writer_flush(LogWriter *self, LogWriterFlushMode flush_mode) { gboolean write_error = FALSE; if (!self->proto) return FALSE; if (log_proto_client_handshake_in_progress(self->proto)) { return log_writer_process_handshake(self); } /* NOTE: in case we're reloading or exiting we flush all queued items as * long as the destination can consume it. This is not going to be an * infinite loop, since the reader will cease to produce new messages when * main_loop_io_worker_job_quit() is set. */ while ((!main_loop_worker_job_quit() || flush_mode == LW_FLUSH_FORCE) && !write_error) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *msg = log_writer_queue_pop_message(self, &path_options, flush_mode == LW_FLUSH_FORCE); if (!msg) break; ScratchBuffersMarker mark; scratch_buffers_mark(&mark); if (!log_writer_write_message(self, msg, &path_options, &write_error)) { scratch_buffers_reclaim_marked(mark); break; } scratch_buffers_reclaim_marked(mark); if (!write_error) stats_counter_inc(self->metrics.written_messages); } if (write_error) return FALSE; return log_writer_flush_finalize(self); } static gboolean log_writer_forced_flush(LogWriter *self) { return log_writer_flush(self, LW_FLUSH_FORCE); } static gboolean log_writer_process_in(LogWriter *self) { if (!self->proto) return FALSE; return (log_proto_client_process_in(self->proto) == LPS_SUCCESS); } static gboolean log_writer_process_out(LogWriter *self) { return log_writer_flush(self, LW_FLUSH_NORMAL); } static void log_writer_reopen_timeout(void *cookie) { LogWriter *self = (LogWriter *)cookie; log_pipe_notify(self->control, NC_REOPEN_REQUIRED, self); } static void log_writer_idle_timeout(void *cookie) { LogWriter *self = (LogWriter *) cookie; g_assert(!self->io_job.working); msg_verbose("Destination timeout has elapsed, closing connection", evt_tag_int("fd", log_proto_client_get_fd(self->proto))); log_pipe_notify(self->control, NC_CLOSE, self); } static void log_writer_init_watches(LogWriter *self) { IV_FD_INIT(&self->fd_watch); self->fd_watch.cookie = self; IV_TASK_INIT(&self->immed_io_task); self->immed_io_task.cookie = self; self->immed_io_task.handler = log_writer_io_handle_out; IV_TIMER_INIT(&self->suspend_timer); self->suspend_timer.cookie = self; ml_batched_timer_init(&self->suppress_timer); self->suppress_timer.cookie = self; self->suppress_timer.handler = (void (*)(void *)) log_writer_suppress_timeout; self->suppress_timer.ref_cookie = (gpointer (*)(gpointer)) log_pipe_ref; self->suppress_timer.unref_cookie = (void (*)(gpointer)) log_pipe_unref; ml_batched_timer_init(&self->mark_timer); self->mark_timer.cookie = self; self->mark_timer.handler = log_writer_mark_timeout; self->mark_timer.ref_cookie = (gpointer (*)(gpointer)) log_pipe_ref; self->mark_timer.unref_cookie = (void (*)(gpointer)) log_pipe_unref; IV_TIMER_INIT(&self->reopen_timer); self->reopen_timer.cookie = self; self->reopen_timer.handler = log_writer_reopen_timeout; IV_TIMER_INIT(&self->idle_timer); self->idle_timer.cookie = self; self->idle_timer.handler = log_writer_idle_timeout; IV_EVENT_INIT(&self->queue_filled); self->queue_filled.cookie = self; self->queue_filled.handler = log_writer_queue_filled; main_loop_io_worker_job_init(&self->io_job); self->io_job.user_data = self; self->io_job.work = (void (*)(void *, void *)) log_writer_work_perform; self->io_job.completion = (void (*)(void *, void *)) log_writer_work_finished; self->io_job.engage = (void (*)(void *)) log_pipe_ref; self->io_job.release = (void (*)(void *)) log_pipe_unref; } static void _register_aggregated_stats(LogWriter *self, StatsClusterKey *sc_key_input, gint stats_level, gint stats_type) { stats_aggregator_lock(); StatsClusterKey sc_key; gchar stats_instance[1024]; stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "msg_size_max"); stats_register_aggregator_maximum(stats_level, &sc_key, &self->metrics.max_message_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "msg_size_avg"); stats_register_aggregator_average(stats_level, &sc_key, &self->metrics.average_messages_size); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "eps"); stats_register_aggregator_cps(stats_level, &sc_key, sc_key_input, stats_type, &self->metrics.CPS); stats_aggregator_unlock(); } static void _unregister_aggregated_stats(LogWriter *self) { stats_aggregator_lock(); stats_unregister_aggregator(&self->metrics.max_message_size); stats_unregister_aggregator(&self->metrics.average_messages_size); stats_unregister_aggregator(&self->metrics.CPS); stats_aggregator_unlock(); } static void _register_raw_bytes_stats(LogWriter *self, gint stats_level) { stats_byte_counter_init(&self->metrics.written_bytes, self->metrics.written_bytes_key, stats_level, SBCP_KIB); } static void _unregister_raw_bytes_stats(LogWriter *self) { stats_byte_counter_deinit(&self->metrics.written_bytes, self->metrics.written_bytes_key); } static void _register_counters(LogWriter *self) { stats_lock(); gint level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : self->options->stats_level; if (self->options->suppress > 0) stats_register_counter(level, self->metrics.output_events_key, SC_TYPE_SUPPRESSED, &self->metrics.suppressed_messages); stats_register_counter(level, self->metrics.output_events_key, SC_TYPE_DROPPED, &self->metrics.dropped_messages); stats_register_counter(level, self->metrics.output_events_key, SC_TYPE_WRITTEN, &self->metrics.written_messages); gchar stats_instance[1024]; stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); StatsClusterKey sc_legacy_processed; stats_cluster_single_key_legacy_set_with_name(&sc_legacy_processed, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "processed"); stats_register_counter(level, &sc_legacy_processed, SC_TYPE_SINGLE_VALUE, &self->metrics.processed_messages); StatsClusterKey sc_key_truncated_count; stats_cluster_single_key_legacy_set_with_name(&sc_key_truncated_count, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "truncated_count"); stats_register_counter(level, &sc_key_truncated_count, SC_TYPE_SINGLE_VALUE, &self->metrics.truncated.count); StatsClusterKey sc_key_truncated_bytes; stats_cluster_single_key_legacy_set_with_name(&sc_key_truncated_bytes, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "truncated_bytes"); stats_register_counter(level, &sc_key_truncated_bytes, SC_TYPE_SINGLE_VALUE, &self->metrics.truncated.bytes); stats_register_counter(level, self->metrics.message_delay_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay); stats_register_counter(level, self->metrics.message_delay_sample_age_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample_age); UnixTime now; unix_time_set_now(&now); stats_counter_set_time(self->metrics.message_delay_sample_age, now.ut_sec); stats_unlock(); _register_aggregated_stats(self, self->metrics.output_events_key, level, SC_TYPE_WRITTEN); level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : STATS_LEVEL1; _register_raw_bytes_stats(self, level); } static gboolean log_writer_init(LogPipe *s) { LogWriter *self = (LogWriter *) s; if (self->queue == NULL) { return FALSE; } iv_event_register(&self->queue_filled); if ((self->options->options & LWO_NO_STATS) == 0 && !self->metrics.dropped_messages) _register_counters(self); if (self->options->mark_mode == MM_PERIODICAL) { /* periodical marks should be emitted even if no message is received, * so we need a timer right from the start */ log_writer_postpone_mark_timer(self); } return TRUE; } static void _unregister_counters(LogWriter *self) { stats_lock(); { stats_unregister_counter(self->metrics.output_events_key, SC_TYPE_DROPPED, &self->metrics.dropped_messages); stats_unregister_counter(self->metrics.output_events_key, SC_TYPE_SUPPRESSED, &self->metrics.suppressed_messages); stats_unregister_counter(self->metrics.output_events_key, SC_TYPE_WRITTEN, &self->metrics.written_messages); gchar stats_instance[1024]; stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); StatsClusterKey sc_legacy_processed; stats_cluster_single_key_legacy_set_with_name(&sc_legacy_processed, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "processed"); stats_unregister_counter(&sc_legacy_processed, SC_TYPE_SINGLE_VALUE, &self->metrics.processed_messages); StatsClusterKey sc_key_truncated_count; stats_cluster_single_key_legacy_set_with_name(&sc_key_truncated_count, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "truncated_count"); stats_unregister_counter(&sc_key_truncated_count, SC_TYPE_SINGLE_VALUE, &self->metrics.truncated.count); StatsClusterKey sc_key_truncated_bytes; stats_cluster_single_key_legacy_set_with_name(&sc_key_truncated_bytes, self->options->stats_source | SCS_DESTINATION, self->stats_id, stats_instance, "truncated_bytes"); stats_unregister_counter(&sc_key_truncated_bytes, SC_TYPE_SINGLE_VALUE, &self->metrics.truncated.bytes); stats_unregister_counter(self->metrics.message_delay_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay); stats_unregister_counter(self->metrics.message_delay_sample_age_key, SC_TYPE_SINGLE_VALUE, &self->metrics.message_delay_sample_age); } stats_unlock(); _unregister_aggregated_stats(self); _unregister_raw_bytes_stats(self); } static gboolean log_writer_deinit(LogPipe *s) { LogWriter *self = (LogWriter *) s; main_loop_assert_main_thread(); log_queue_reset_parallel_push(self->queue); log_writer_forced_flush(self); /* FIXME: by the time we arrive here, it must be guaranteed that no * _queue() call is running in a different thread, otherwise we'd need * some kind of locking. */ log_writer_stop_watches(self); iv_event_unregister(&self->queue_filled); if (iv_timer_registered(&self->reopen_timer)) iv_timer_unregister(&self->reopen_timer); ml_batched_timer_unregister(&self->suppress_timer); ml_batched_timer_unregister(&self->mark_timer); _unregister_counters(self); return TRUE; } static void log_writer_free(LogPipe *s) { LogWriter *self = (LogWriter *) s; log_writer_free_proto(self); if (self->line_buffer) g_string_free(self->line_buffer, TRUE); log_queue_unref(self->queue); if (self->last_msg) log_msg_unref(self->last_msg); g_free(self->stats_id); if (self->metrics.stats_kb) stats_cluster_key_builder_free(self->metrics.stats_kb); if (self->metrics.output_events_key) stats_cluster_key_free(self->metrics.output_events_key); if (self->metrics.written_bytes_key) stats_cluster_key_free(self->metrics.written_bytes_key); if (self->metrics.message_delay_key) stats_cluster_key_free(self->metrics.message_delay_key); if (self->metrics.message_delay_sample_age_key) stats_cluster_key_free(self->metrics.message_delay_sample_age_key); ml_batched_timer_free(&self->mark_timer); ml_batched_timer_free(&self->suppress_timer); g_mutex_clear(&self->suppress_lock); g_mutex_clear(&self->pending_proto_lock); g_cond_clear(&self->pending_proto_cond); log_pipe_free_method(s); } /* FIXME: this is inherently racy */ gboolean log_writer_has_pending_writes(LogWriter *self) { return !log_queue_is_empty_racy(self->queue) || !self->watches_running; } gboolean log_writer_opened(LogWriter *self) { return self->proto != NULL; } static void log_writer_free_proto(LogWriter *self) { if (self->proto) log_proto_client_free(self->proto); self->proto = NULL; } static void log_writer_set_proto(LogWriter *self, LogProtoClient *proto) { self->proto = proto; if (proto) { LogProtoClientFlowControlFuncs flow_control_funcs; flow_control_funcs.ack_callback = log_writer_msg_ack; flow_control_funcs.rewind_callback = log_writer_msg_rewind_cb; flow_control_funcs.user_data = self; log_proto_client_set_client_flow_control(self->proto, &flow_control_funcs); log_proto_client_set_options(self->proto, &self->options->proto_options.super); } } static void log_writer_set_pending_proto(LogWriter *self, LogProtoClient *proto, gboolean present) { self->pending_proto = proto; self->pending_proto_present = present; } LogProtoClient * log_writer_steal_proto(LogWriter *self) { if (self->proto == NULL) return NULL; LogProtoClient *proto = self->proto; log_writer_set_proto(self, NULL); return proto; } /* run in the main thread in reaction to a log_writer_reopen to change * the destination LogProtoClient instance. It needs to be ran in the main * thread as it reregisters the watches associated with the main * thread. */ static void log_writer_reopen_deferred(gpointer s) { gpointer *args = (gpointer *) s; LogWriter *self = args[0]; LogProtoClient *proto = args[1]; if (!proto) { iv_validate_now(); self->reopen_timer.expires = iv_now; self->reopen_timer.expires.tv_sec += self->options->time_reopen; if (iv_timer_registered(&self->reopen_timer)) iv_timer_unregister(&self->reopen_timer); iv_timer_register(&self->reopen_timer); } init_sequence_number(&self->seq_num); if (self->io_job.working) { /* NOTE: proto can be NULL but it is present... */ log_writer_set_pending_proto(self, proto, TRUE); return; } log_writer_stop_watches(self); if (self->partial_write) { log_queue_rewind_backlog_all(self->queue); } log_writer_free_proto(self); log_writer_set_proto(self, proto); if (proto) log_writer_start_watches(self); } /* * This function can be called from any threads, from the main thread * as well as I/O worker threads. It takes care about going to the * main thread to actually switch LogProtoClient under this writer. * * The writer may still be operating, (e.g. log_pipe_deinit/init is * not needed). * * In case we're running in a non-main thread, then by the time this * function returns, the reopen has finished. In case it is called * from the main thread, this function may defer updating self->proto * until the worker thread has finished. The reason for this * difference is: * * - if LogWriter is busy, then updating the LogProtoClient instance is * deferred to log_writer_work_finished(), but that runs in the * main thread. * * - normally, even this deferred update is waited for, but in case * we're in the main thread, we can't block. * * This situation could probably be improved, maybe the synchonous * return of log_writer_reopen() is not needed by call sites, but I * was not sure, and right before release I didn't want to take the * risky approach. */ void log_writer_reopen(LogWriter *s, LogProtoClient *proto) { LogWriter *self = (LogWriter *) s; gpointer args[] = { s, proto }; main_loop_call((MainLoopTaskFunc) log_writer_reopen_deferred, args, TRUE); if (!main_loop_is_main_thread()) { g_mutex_lock(&self->pending_proto_lock); while (self->pending_proto_present) { g_cond_wait(&self->pending_proto_cond, &self->pending_proto_lock); } g_mutex_unlock(&self->pending_proto_lock); } } static void _set_metric_options(LogWriter *self, const gchar *stats_id, StatsClusterKeyBuilder *kb) { if (self->stats_id) g_free(self->stats_id); self->stats_id = stats_id ? g_strdup(stats_id) : NULL; if (self->metrics.stats_kb) stats_cluster_key_builder_free(self->metrics.stats_kb); if (!kb) kb = stats_cluster_key_builder_new(); self->metrics.stats_kb = kb; /* building stats key for counters with legacy representation */ stats_cluster_key_builder_push(self->metrics.stats_kb); { gchar stats_instance[1024]; const gchar *instance_name = stats_cluster_key_builder_format_legacy_stats_instance(self->metrics.stats_kb, stats_instance, sizeof(stats_instance)); stats_cluster_key_builder_set_name(self->metrics.stats_kb, "output_events_total"); stats_cluster_key_builder_set_legacy_alias(self->metrics.stats_kb, self->options->stats_source | SCS_DESTINATION, self->stats_id, instance_name); stats_cluster_key_builder_add_label(self->metrics.stats_kb, stats_cluster_label("id", self->stats_id)); if (self->metrics.output_events_key) stats_cluster_key_free(self->metrics.output_events_key); self->metrics.output_events_key = stats_cluster_key_builder_build_logpipe(self->metrics.stats_kb); } stats_cluster_key_builder_pop(self->metrics.stats_kb); /* counters without a legacy alias, e.g. prometheus only */ stats_cluster_key_builder_push(self->metrics.stats_kb); { stats_cluster_key_builder_add_label(self->metrics.stats_kb, stats_cluster_label("id", self->stats_id)); if (self->metrics.written_bytes_key) stats_cluster_key_free(self->metrics.written_bytes_key); stats_cluster_key_builder_set_name(self->metrics.stats_kb, "output_event_bytes_total"); self->metrics.written_bytes_key = stats_cluster_key_builder_build_single(self->metrics.stats_kb); if (self->metrics.message_delay_key) stats_cluster_key_free(self->metrics.message_delay_key); /* Up to 49 days and 17 hours on 32 bit machines. */ stats_cluster_key_builder_set_name(self->metrics.stats_kb, "output_event_delay_sample_seconds"); stats_cluster_key_builder_set_unit(self->metrics.stats_kb, SCU_MILLISECONDS); self->metrics.message_delay_key = stats_cluster_key_builder_build_single(self->metrics.stats_kb); if (self->metrics.message_delay_sample_age_key) stats_cluster_key_free(self->metrics.message_delay_sample_age_key); stats_cluster_key_builder_set_name(self->metrics.stats_kb, "output_event_delay_sample_age_seconds"); stats_cluster_key_builder_set_unit(self->metrics.stats_kb, SCU_SECONDS); stats_cluster_key_builder_set_frame_of_reference(self->metrics.stats_kb, SCFOR_RELATIVE_TO_TIME_OF_QUERY); self->metrics.message_delay_sample_age_key = stats_cluster_key_builder_build_single(self->metrics.stats_kb); } stats_cluster_key_builder_pop(self->metrics.stats_kb); } void log_writer_set_options(LogWriter *self, LogPipe *control, LogWriterOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb) { self->control = control; self->options = options; if (control) self->super.expr_node = control->expr_node; _set_metric_options(self, stats_id, kb); } LogWriter * log_writer_new(guint32 flags, GlobalConfig *cfg) { LogWriter *self = g_new0(LogWriter, 1); log_pipe_init_instance(&self->super, cfg); self->super.init = log_writer_init; self->super.deinit = log_writer_deinit; self->super.queue = log_writer_queue; self->super.free_fn = log_writer_free; self->flags = flags; self->line_buffer = g_string_sized_new(128); self->pollable_state = -1; init_sequence_number(&self->seq_num); log_writer_init_watches(self); g_mutex_init(&self->suppress_lock); g_mutex_init(&self->pending_proto_lock); g_cond_init(&self->pending_proto_cond); log_pipe_add_info(&self->super, "writer"); return self; } void log_writer_options_defaults(LogWriterOptions *options) { options->template = NULL; options->flush_lines = -1; log_template_options_defaults(&options->template_options); options->time_reopen = -1; options->suppress = -1; options->padding = 0; options->mark_mode = MM_GLOBAL; options->mark_freq = -1; options->truncate_size = -1; host_resolve_options_defaults(&options->host_resolve_options); } void log_writer_options_set_template_escape(LogWriterOptions *options, gboolean enable) { if (options->template && options->template->def_inline) { log_template_set_escape(options->template, enable); } else { msg_error("Macro escaping can only be specified for inline templates"); } } void log_writer_options_set_mark_mode(LogWriterOptions *options, const gchar *mark_mode) { options->mark_mode = cfg_lookup_mark_mode(mark_mode); } /* * NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy * * Rationale: * - init is called from driver init (e.g. affile_sd_init), * - destroy is called from driver free method (e.g. affile_sd_free, NOT affile_sd_deinit) * * The reason: * - when initializing the reloaded configuration fails for some reason, * we have to fall back to the old configuration, thus we cannot dump * the information stored in the Options structure at deinit time, but * have to recover it when the old configuration is initialized. * * For the reasons above, init and destroy behave the following way: * * - init is idempotent, it can be called multiple times without leaking * memory, and without loss of information * - destroy is only called once, when the options are indeed to be destroyed * * Also important to note is that when init is called multiple times, the * GlobalConfig reference is the same, this means that it is enough to * remember whether init was called already and return w/o doing anything in * that case, which is actually how idempotency is implemented here. */ void log_writer_options_init(LogWriterOptions *options, GlobalConfig *cfg, guint32 option_flags) { if (options->initialized) return; log_template_options_init(&options->template_options, cfg); host_resolve_options_init(&options->host_resolve_options, &cfg->host_resolve_options); log_proto_client_options_init(&options->proto_options.super, cfg); options->options |= option_flags; if (options->flush_lines == -1) options->flush_lines = cfg->flush_lines; if (options->suppress == -1) options->suppress = cfg->suppress; if (options->time_reopen == -1) options->time_reopen = cfg->time_reopen; options->file_template = log_template_ref(cfg->file_template); options->proto_template = log_template_ref(cfg->proto_template); if (cfg->threaded) options->options |= LWO_THREADED; /* per-destination MARK messages */ if (options->mark_mode == MM_GLOBAL) { /* get the global option */ options->mark_mode = cfg->mark_mode; } if (options->mark_freq == -1) { /* not initialized, use the global mark freq */ options->mark_freq = cfg->mark_freq; } options->initialized = TRUE; } void log_writer_options_destroy(LogWriterOptions *options) { log_template_options_destroy(&options->template_options); host_resolve_options_destroy(&options->host_resolve_options); log_proto_client_options_destroy(&options->proto_options.super); log_template_unref(options->template); log_template_unref(options->file_template); log_template_unref(options->proto_template); options->initialized = FALSE; } gint log_writer_options_lookup_flag(const gchar *flag) { if (strcmp(flag, "syslog-protocol") == 0) return LWO_SYSLOG_PROTOCOL; if (strcmp(flag, "no-multi-line") == 0) return LWO_NO_MULTI_LINE; if (strcmp(flag, "threaded") == 0) return LWO_THREADED; if (strcmp(flag, "ignore-errors") == 0) return LWO_IGNORE_ERRORS; msg_error("Unknown dest writer flag", evt_tag_str("flag", flag)); return 0; } syslog-ng-syslog-ng-4.4.0/lib/logwriter.h000066400000000000000000000067701450431004300203220ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOG_WRITER_H_INCLUDED #define LOG_WRITER_H_INCLUDED #include "logpipe.h" #include "template/templates.h" #include "logqueue.h" #include "logproto/logproto-client.h" #include "stats/stats-cluster-key-builder.h" /* writer constructor flags */ #define LW_DETECT_EOF 0x0001 #define LW_FORMAT_FILE 0x0002 #define LW_FORMAT_PROTO 0x0004 #define LW_SYSLOG_PROTOCOL 0x0008 #define LW_SOFT_FLOW_CONTROL 0x0010 /* writer options (set by the user) */ #define LWO_SYSLOG_PROTOCOL 0x0001 #define LWO_NO_MULTI_LINE 0x0002 /* we don't want to have a dropped counter for this writer */ #define LWO_NO_STATS 0x0004 #define LWO_THREADED 0x0010 #define LWO_IGNORE_ERRORS 0x0020 typedef struct _LogWriterOptions { gboolean initialized; /* bitmask of LWO_* */ guint32 options; /* minimum number of entries to trigger a flush */ gint flush_lines; LogTemplate *template; LogTemplate *file_template; LogTemplate *proto_template; LogTemplateOptions template_options; HostResolveOptions host_resolve_options; LogProtoClientOptionsStorage proto_options; gint time_reopen; gint suppress; gint padding; gint mark_mode; gint mark_freq; gint stats_level; gint stats_source; gint truncate_size; } LogWriterOptions; typedef struct _LogWriter LogWriter; void log_writer_set_flags(LogWriter *self, guint32 flags); guint32 log_writer_get_flags(LogWriter *self); void log_writer_set_options(LogWriter *self, LogPipe *control, LogWriterOptions *options, const gchar *stats_id, StatsClusterKeyBuilder *kb); void log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result); gboolean log_writer_has_pending_writes(LogWriter *self); gboolean log_writer_opened(LogWriter *self); void log_writer_reopen(LogWriter *self, LogProtoClient *proto); LogProtoClient *log_writer_steal_proto(LogWriter *self); void log_writer_set_queue(LogWriter *self, LogQueue *queue); LogQueue *log_writer_get_queue(LogWriter *s); LogWriter *log_writer_new(guint32 flags, GlobalConfig *cfg); void log_writer_msg_rewind(LogWriter *self); void log_writer_options_set_template_escape(LogWriterOptions *options, gboolean enable); void log_writer_options_defaults(LogWriterOptions *options); void log_writer_options_init(LogWriterOptions *options, GlobalConfig *cfg, guint32 option_flags); void log_writer_options_destroy(LogWriterOptions *options); void log_writer_options_set_mark_mode(LogWriterOptions *options, const gchar *mark_mode); gint log_writer_options_lookup_flag(const gchar *flag); #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop-call.c000066400000000000000000000113571450431004300210230ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop-call.h" #include "tls-support.h" #include #include #include /************************************************************************************ * Cross-thread function calls into the main loop ************************************************************************************/ typedef struct _MainLoopTaskCallSite MainLoopTaskCallSite; struct _MainLoopTaskCallSite { struct iv_list_head list; MainLoopTaskFunc func; gpointer user_data; gpointer result; gboolean pending; gboolean wait; gboolean mainfree; GCond cond; GMutex lock; }; TLS_BLOCK_START { MainLoopTaskCallSite *call_info; } TLS_BLOCK_END; #define call_info __tls_deref(call_info) static GMutex main_task_lock; static struct iv_list_head main_task_queue = IV_LIST_HEAD_INIT(main_task_queue); static struct iv_event main_task_posted; static void main_loop_call_free(MainLoopTaskCallSite *site) { g_cond_clear(&site->cond); g_mutex_clear(&site->lock); g_free(site); } static void main_loop_wait_for_pending_call_to_finish(void) { g_mutex_lock(&main_task_lock); /* check if a previous call is being executed */ g_mutex_lock(&call_info->lock); if (call_info->pending) { /* yes, it is still running, indicate that we need to be woken up */ call_info->wait = TRUE; g_mutex_unlock(&call_info->lock); while (call_info->pending) g_cond_wait(&call_info->cond, &main_task_lock); } else { g_mutex_unlock(&call_info->lock); } g_mutex_unlock(&main_task_lock); } gpointer main_loop_call(MainLoopTaskFunc func, gpointer user_data, gboolean wait) { if (main_loop_is_main_thread()) return func(user_data); main_loop_wait_for_pending_call_to_finish(); /* call_info->lock is no longer needed, since we're the only ones using call_info now */ INIT_IV_LIST_HEAD(&call_info->list); call_info->pending = TRUE; call_info->func = func; call_info->user_data = user_data; call_info->wait = wait; g_mutex_lock(&main_task_lock); iv_list_add(&call_info->list, &main_task_queue); iv_event_post(&main_task_posted); if (wait) { while (call_info->pending) g_cond_wait(&call_info->cond, &main_task_lock); } g_mutex_unlock(&main_task_lock); return call_info->result; } static void main_loop_call_handler(gpointer user_data) { gboolean dofree, dowakeup; g_mutex_lock(&main_task_lock); while (!iv_list_empty(&main_task_queue)) { MainLoopTaskCallSite *site; gpointer result; site = iv_list_entry(main_task_queue.next, MainLoopTaskCallSite, list); iv_list_del_init(&site->list); g_mutex_unlock(&main_task_lock); result = site->func(site->user_data); g_mutex_lock(&site->lock); site->result = result; site->pending = FALSE; dowakeup = site->wait; dofree = site->mainfree; g_mutex_unlock(&site->lock); g_mutex_lock(&main_task_lock); if (dofree) main_loop_call_free(site); else if (dowakeup) g_cond_signal(&site->cond); } g_mutex_unlock(&main_task_lock); } void main_loop_call_thread_init(void) { call_info = g_new0(MainLoopTaskCallSite, 1); g_cond_init(&call_info->cond); g_mutex_init(&call_info->lock); } void main_loop_call_thread_deinit(void) { MainLoopTaskCallSite *site = call_info; g_mutex_lock(&site->lock); if (site->pending) { site->mainfree = TRUE; call_info = NULL; } g_mutex_unlock(&site->lock); if (call_info) main_loop_call_free(call_info); } void main_loop_call_init(void) { IV_EVENT_INIT(&main_task_posted); main_task_posted.cookie = NULL; main_task_posted.handler = main_loop_call_handler; iv_event_register(&main_task_posted); } void main_loop_call_deinit(void) { iv_event_unregister(&main_task_posted); } syslog-ng-syslog-ng-4.4.0/lib/mainloop-call.h000066400000000000000000000024671450431004300210320ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_CALL_H_INCLUDED #define MAINLOOP_CALL_H_INCLUDED 1 #include "mainloop.h" gpointer main_loop_call(MainLoopTaskFunc func, gpointer user_data, gboolean wait); void main_loop_call_thread_init(void); void main_loop_call_thread_deinit(void); void main_loop_call_init(void); void main_loop_call_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop-control.c000066400000000000000000000321171450431004300215650ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop.h" #include "control/control-commands.h" #include "control/control-connection.h" #include "messages.h" #include "cfg.h" #include "cfg-path.h" #include "apphook.h" #include "secret-storage/secret-storage.h" #include "cfg-walker.h" #include "logpipe.h" #include static gboolean _control_process_log_level(const gchar *level, GString *result) { if (!level) { /* query current log level */ return TRUE; } gint ll = msg_map_string_to_log_level(level); if (ll < 0) return FALSE; msg_set_log_level(ll); return TRUE; } static gboolean _control_process_compat_log_command(const gchar *level, const gchar *onoff, GString *result) { if (!level) return FALSE; gint ll = msg_map_string_to_log_level(level); if (ll < 0) return FALSE; if (onoff) { gboolean on = g_str_equal(onoff, "ON"); if (!on) ll = ll - 1; msg_set_log_level(ll); } return TRUE; } static void control_connection_message_log(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { gchar **cmds = g_strsplit(command->str, " ", 3); GString *result = g_string_sized_new(128); gboolean success; if (!cmds[1]) { g_string_assign(result, "FAIL Invalid arguments received"); goto exit; } gint orig_log_level = msg_get_log_level(); if (g_str_equal(cmds[1], "LEVEL")) success = _control_process_log_level(cmds[2], result); else success = _control_process_compat_log_command(cmds[1], cmds[2], result); if (orig_log_level != msg_get_log_level()) msg_info("Verbosity changed", evt_tag_int("log_level", msg_get_log_level())); if (success) g_string_printf(result, "OK syslog-ng log level set to %d", msg_get_log_level()); else g_string_assign(result, "FAIL Invalid arguments received"); exit: g_strfreev(cmds); control_connection_send_reply(cc, result); } static void control_connection_stop_process(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GString *result = g_string_new("OK Shutdown initiated"); MainLoop *main_loop = (MainLoop *) user_data; main_loop_exit(main_loop); control_connection_send_reply(cc, result); } static void control_connection_config(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { MainLoop *main_loop = (MainLoop *) user_data; GlobalConfig *config = main_loop_get_current_config(main_loop); GString *result = g_string_sized_new(128); gchar **arguments = g_strsplit(command->str, " ", 0); if (!arguments[1]) { g_string_assign(result, "FAIL Invalid arguments"); goto exit; } if (g_str_equal(arguments[1], "ID")) { cfg_format_id(config, result); goto exit; } if (g_str_equal(arguments[1], "GET")) { if (g_str_equal(arguments[2], "ORIGINAL")) { g_string_assign(result, config->original_config->str); goto exit; } else if (g_str_equal(arguments[2], "PREPROCESSED")) { g_string_assign(result, config->preprocess_config->str); goto exit; } } if (g_str_equal(arguments[1], "VERIFY")) { main_loop_verify_config(result, main_loop); goto exit; } g_string_assign(result, "FAIL Invalid arguments received"); exit: g_strfreev(arguments); control_connection_send_reply(cc, result); } static void show_ose_license_info(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { control_connection_send_reply(cc, g_string_new("OK You are using the Open Source Edition of syslog-ng.")); } static void _respond_config_reload_status(gint type, gpointer user_data) { gpointer *args = user_data; MainLoop *main_loop = (MainLoop *) args[0]; ControlConnection *cc = (ControlConnection *) args[1]; GString *reply; if (main_loop_was_last_reload_successful(main_loop)) reply = g_string_new("OK Config reload successful"); else reply = g_string_new("FAIL Config reload failed, reverted to previous config"); control_connection_send_reply(cc, reply); } static void control_connection_reload(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { MainLoop *main_loop = (MainLoop *) user_data; static gpointer args[2]; GError *error = NULL; if (!main_loop_reload_config_prepare(main_loop, &error)) { GString *result = g_string_new(""); g_string_printf(result, "FAIL %s, previous config remained intact", error->message); g_clear_error(&error); control_connection_send_reply(cc, result); return; } args[0] = main_loop; args[1] = cc; register_application_hook(AH_CONFIG_CHANGED, _respond_config_reload_status, args, AHM_RUN_ONCE); main_loop_reload_config_commence(main_loop); } static void control_connection_reopen(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GString *result = g_string_new("OK Re-open of log destination files initiated"); app_reopen_files(); control_connection_send_reply(cc, result); } static const gchar * secret_status_to_string(SecretStorageSecretState state) { switch (state) { case SECRET_STORAGE_STATUS_PENDING: return "PENDING"; case SECRET_STORAGE_SUCCESS: return "SUCCESS"; case SECRET_STORAGE_STATUS_FAILED: return "FAILED"; case SECRET_STORAGE_STATUS_INVALID_PASSWORD: return "INVALID_PASSWORD"; default: g_assert_not_reached(); } return "SHOULD NOT BE REACHED"; } gboolean secret_storage_status_accumulator(SecretStatus *status, gpointer user_data) { GString *status_str = (GString *) user_data; g_string_append_printf(status_str, "%s\t%s\n", status->key, secret_status_to_string(status->state)); return TRUE; } static GString * process_credentials_status(GString *result) { g_string_assign(result, "OK Credential storage status follows\n"); secret_storage_status_foreach(secret_storage_status_accumulator, (gpointer) result); return result; } static GString * process_credentials_add(GString *result, guint argc, gchar **arguments) { if (argc < 4) { g_string_assign(result, "FAIL missing arguments to add\n"); return result; } gchar *id = arguments[2]; gchar *secret = arguments[3]; if (secret_storage_store_secret(id, secret, strlen(secret))) g_string_assign(result, "OK Credentials stored successfully\n"); else g_string_assign(result, "FAIL Error while saving credentials\n"); secret_storage_wipe(secret, strlen(secret)); return result; } static void process_credentials(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { gchar **arguments = g_strsplit(command->str, " ", 4); guint argc = g_strv_length(arguments); GString *result = g_string_new(NULL); if (argc < 1) { g_string_assign(result, "FAIL missing subcommand\n"); g_strfreev(arguments); control_connection_send_reply(cc, result); return; } gchar *subcommand = arguments[1]; if (strcmp(subcommand, "status") == 0) result = process_credentials_status(result); else if (g_strcmp0(subcommand, "add") == 0) result = process_credentials_add(result, argc, arguments); else g_string_printf(result, "FAIL invalid subcommand %s\n", subcommand); g_strfreev(arguments); control_connection_send_reply(cc, result); } static void control_connection_list_files(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { MainLoop *main_loop = (MainLoop *) user_data; GlobalConfig *config = main_loop_get_current_config(main_loop); GString *result = g_string_new(""); for (GList *v = config->file_list; v; v = v->next) { CfgFilePath *cfg_file_path = (CfgFilePath *) v->data; g_string_append_printf(result, "%s: %s\n", cfg_file_path->path_type, cfg_file_path->file_path); } if (result->len == 0) g_string_assign(result, "No files available\n"); control_connection_send_reply(cc, result); } static void _append_arc(Arc *self, gpointer dummy, GPtrArray *arcs) { g_ptr_array_add(arcs, g_strdup_printf("{\"from\" : \"%p\", \"to\" : \"%p\", \"type\" : \"%s\"}", self->from, self->to, self->arc_type == ARC_TYPE_NEXT_HOP ? "next_hop" : "pipe_next")); }; static gchar * arcs_as_json(GHashTable *arcs) { GPtrArray *arcs_list = g_ptr_array_new_with_free_func(g_free); g_hash_table_foreach(arcs, (GHFunc)_append_arc, arcs_list); g_ptr_array_add(arcs_list, NULL); gchar *arcs_joined = g_strjoinv(", ", (gchar **)arcs_list->pdata); g_ptr_array_free(arcs_list, TRUE); gchar *json = g_strdup_printf("[%s]", arcs_joined); g_free(arcs_joined); return json; } static GList * _collect_info(LogPipe *self) { GList *info = g_list_copy_deep(self->info, (GCopyFunc)g_strdup, NULL); if (self->plugin_name) info = g_list_append(info, g_strdup(self->plugin_name)); if (self->expr_node) { gchar buf[128]; log_expr_node_format_location(self->expr_node, buf, sizeof(buf)); info = g_list_append(info, g_strdup(buf)); } if (log_pipe_get_persist_name(self)) info = g_list_append(info, g_strdup(log_pipe_get_persist_name(self))); return info; } static gchar * g_str_join_list(GList *self, gchar *separator) { if (!self) return g_strdup(""); if (g_list_length(self) == 1) return g_strdup(self->data); GString *joined = g_string_new(self->data); GList *rest = self->next; for (GList *e = rest; e; e = e->next) { g_string_append(joined, separator); g_string_append(joined, e->data); } return g_string_free(joined, FALSE); } static gchar * _add_quotes(gchar *self) { return g_strdup_printf("\"%s\"", self); } static void _append_node(LogPipe *self, gpointer dummy, GPtrArray *nodes) { GList *raw_info = _collect_info(self); GList *info_with_quotes = g_list_copy_deep(raw_info, (GCopyFunc)_add_quotes, NULL); g_list_free_full(raw_info, g_free); gchar *info = g_str_join_list(info_with_quotes, ", "); g_list_free_full(info_with_quotes, g_free); g_ptr_array_add(nodes, g_strdup_printf("{\"node\" : \"%p\", \"info\" : [%s]}", self, info)); g_free(info); }; static gchar * nodes_as_json(GHashTable *nodes) { GPtrArray *nodes_list = g_ptr_array_new_with_free_func(g_free); g_hash_table_foreach(nodes, (GHFunc)_append_node, nodes_list); g_ptr_array_add(nodes_list, NULL); gchar *nodes_joined = g_strjoinv(", ", (gchar **)nodes_list->pdata); g_ptr_array_free(nodes_list, TRUE); gchar *json = g_strdup_printf("[%s]", nodes_joined); g_free(nodes_joined); return json; } static GString * generate_json(GHashTable *nodes, GHashTable *arcs) { gchar *nodes_part = nodes_as_json(nodes); gchar *arcs_part = arcs_as_json(arcs); gchar *json = g_strdup_printf("{\"nodes\" : %s, \"arcs\" : %s}", nodes_part, arcs_part); GString *result = g_string_new(json); g_free(json); g_free(nodes_part); g_free(arcs_part); return result; } static void export_config_graph(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GHashTable *nodes; GHashTable *arcs; MainLoop *main_loop = (MainLoop *) user_data; GlobalConfig *cfg = main_loop_get_current_config(main_loop); cfg_walker_get_graph(cfg->tree.initialized_pipes, &nodes, &arcs); GString *result = generate_json(nodes, arcs); g_hash_table_destroy(nodes); g_hash_table_destroy(arcs); control_connection_send_reply(cc, result); } ControlCommand default_commands[] = { { "LOG", control_connection_message_log }, { "STOP", control_connection_stop_process }, { "RELOAD", control_connection_reload }, { "REOPEN", control_connection_reopen }, { "CONFIG", control_connection_config }, { "LICENSE", show_ose_license_info }, { "PWD", process_credentials }, { "LISTFILES", control_connection_list_files }, { "EXPORT_CONFIG_GRAPH", export_config_graph }, { NULL, NULL }, }; void main_loop_register_control_commands(MainLoop *main_loop) { int i; ControlCommand *cmd; for (i = 0; default_commands[i].command_name != NULL; i++) { cmd = &default_commands[i]; control_register_command(cmd->command_name, cmd->func, main_loop, cmd->threaded); } } syslog-ng-syslog-ng-4.4.0/lib/mainloop-control.h000066400000000000000000000021751450431004300215730ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_CONTROL_H_INCLUDED #define MAINLOOP_CONTROL_H_INCLUDED void main_loop_register_control_commands(MainLoop *main_loop); #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop-io-worker.c000066400000000000000000000110231450431004300220140ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop-io-worker.h" #include "mainloop-worker.h" #include "mainloop-call.h" #include "logqueue.h" #include "apphook.h" /************************************************************************************ * I/O worker threads ************************************************************************************/ static struct iv_work_pool main_loop_io_workers; static void _release(MainLoopIOWorkerJob *self) { if (self->release) self->release(self->user_data); } static void _engage(MainLoopIOWorkerJob *self) { if (self->engage) self->engage(self->user_data); } gboolean main_loop_io_worker_job_submit(MainLoopIOWorkerJob *self, gpointer arg) { main_loop_assert_main_thread(); g_assert(self->working == FALSE); if (main_loop_workers_quit) return FALSE; _engage(self); main_loop_worker_job_start(); self->working = TRUE; self->arg = arg; iv_work_pool_submit_work(&main_loop_io_workers, &self->work_item); return TRUE; } #if SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION void main_loop_io_worker_job_submit_continuation(MainLoopIOWorkerJob *self, gpointer arg) { main_loop_assert_worker_thread(); g_assert(self->working == FALSE); _engage(self); main_loop_worker_job_start(); self->working = TRUE; self->arg = arg; iv_work_pool_submit_continuation(&main_loop_io_workers, &self->work_item); } #endif /* NOTE: runs in the actual worker thread spawned by the * main_loop_io_workers thread pool */ static void _work(MainLoopIOWorkerJob *self) { self->work(self->user_data, self->arg); main_loop_worker_invoke_batch_callbacks(); main_loop_worker_run_gc(); } /* NOTE: runs in the main thread */ static void _complete(MainLoopIOWorkerJob *self) { self->working = FALSE; if (self->completion) self->completion(self->user_data, self->arg); main_loop_worker_job_complete(); _release(self); } void main_loop_io_worker_job_init(MainLoopIOWorkerJob *self) { IV_WORK_ITEM_INIT(&self->work_item); self->work_item.cookie = self; self->work_item.work = (void (*)(void *)) _work; self->work_item.completion = (void (*)(void *)) _complete; } static gint get_processor_count(void) { #ifdef _SC_NPROCESSORS_ONLN return sysconf(_SC_NPROCESSORS_ONLN); #else return -1; #endif } static void main_loop_io_worker_thread_start(void *cookie) { main_loop_worker_thread_start(MLW_ASYNC_WORKER); } static void main_loop_io_worker_thread_stop(void *cookie) { main_loop_worker_thread_stop(); } static void __pre_pre_init_hook(gint type, gpointer user_data) { main_loop_worker_allocate_thread_space(main_loop_io_workers.max_threads); } void main_loop_io_worker_init(void) { if (main_loop_io_workers.max_threads == 0) { main_loop_io_workers.max_threads = MIN(MAX(MAIN_LOOP_MIN_WORKER_THREADS, get_processor_count()), MAIN_LOOP_MAX_WORKER_THREADS); } main_loop_io_workers.thread_start = main_loop_io_worker_thread_start; main_loop_io_workers.thread_stop = main_loop_io_worker_thread_stop; iv_work_pool_create(&main_loop_io_workers); register_application_hook(AH_CONFIG_PRE_PRE_INIT, __pre_pre_init_hook, NULL, AHM_RUN_REPEAT); } void main_loop_io_worker_deinit(void) { iv_work_pool_put(&main_loop_io_workers); } static GOptionEntry main_loop_io_worker_options[] = { { "worker-threads", 0, 0, G_OPTION_ARG_INT, &main_loop_io_workers.max_threads, "Set the number of I/O worker threads", "" }, { NULL }, }; void main_loop_io_worker_add_options(GOptionContext *ctx) { g_option_context_add_main_entries(ctx, main_loop_io_worker_options, NULL); } syslog-ng-syslog-ng-4.4.0/lib/mainloop-io-worker.h000066400000000000000000000035671450431004300220370ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_IO_WORKER_H_INCLUDED #define MAINLOOP_IO_WORKER_H_INCLUDED 1 #include "mainloop-worker.h" #include typedef struct _MainLoopIOWorkerJob { void (*engage)(gpointer user_data); void (*work)(gpointer user_data, gpointer arg); void (*completion)(gpointer user_data, gpointer arg); void (*release)(gpointer user_data); gpointer user_data; gpointer arg; gboolean working; struct iv_work_item work_item; } MainLoopIOWorkerJob; void main_loop_io_worker_job_init(MainLoopIOWorkerJob *self); gboolean main_loop_io_worker_job_submit(MainLoopIOWorkerJob *self, gpointer arg); #if SYSLOG_NG_HAVE_IV_WORK_POOL_SUBMIT_CONTINUATION void main_loop_io_worker_job_submit_continuation(MainLoopIOWorkerJob *self, gpointer arg); #endif void main_loop_io_worker_add_options(GOptionContext *ctx); void main_loop_io_worker_init(void); void main_loop_io_worker_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop-threaded-worker.c000066400000000000000000000104751450431004300231770ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop-threaded-worker.h" #include "mainloop-call.h" #include static void _signal_startup_finished(MainLoopThreadedWorker *self, gboolean startup_result) { g_mutex_lock(&self->lock); self->startup.finished = TRUE; self->startup.result &= startup_result; g_cond_signal(&self->startup.cond); g_mutex_unlock(&self->lock); } static gboolean _thread_init(MainLoopThreadedWorker *self) { gboolean result = TRUE; main_loop_worker_thread_start(self->worker_type); if (self->thread_init) result = self->thread_init(self); _signal_startup_finished(self, result); return result; } static void _thread_deinit(MainLoopThreadedWorker *self) { if (self->thread_deinit) self->thread_deinit(self); main_loop_call((MainLoopTaskFunc) main_loop_worker_job_complete, NULL, TRUE); main_loop_worker_thread_stop(); } static void _request_worker_exit(gpointer st) { MainLoopThreadedWorker *self = st; return self->request_exit(self); } static gpointer _worker_thread_func(gpointer st) { MainLoopThreadedWorker *self = st; iv_init(); if (_thread_init(self)) self->run(self); _thread_deinit(self); iv_deinit(); /* NOTE: this assert aims to validate that the worker thread in fact * invokes main_loop_worker_invoke_batch_callbacks() during its operation. * Please do so every once a couple of messages, hopefully you have a * natural barrier that lets you decide when, the easiest would be * log-fetch-limit(), but other limits may also be applicable. */ main_loop_worker_assert_batch_callbacks_were_processed(); return NULL; } static gboolean _wait_for_startup_finished(MainLoopThreadedWorker *self) { g_mutex_lock(&self->lock); while (!self->startup.finished) g_cond_wait(&self->startup.cond, &self->lock); g_mutex_unlock(&self->lock); return self->startup.result; } gboolean main_loop_threaded_worker_start(MainLoopThreadedWorker *self) { /* NOTE: we can only start up once */ g_assert(!self->startup.finished); self->startup.result = TRUE; main_loop_assert_main_thread(); main_loop_worker_job_start(); main_loop_worker_register_exit_notification_callback(_request_worker_exit, self); self->thread = g_thread_new(NULL, _worker_thread_func, self); return _wait_for_startup_finished(self); } void main_loop_threaded_worker_init(MainLoopThreadedWorker *self, MainLoopWorkerType worker_type, gpointer data) { self->worker_type = worker_type; g_cond_init(&self->startup.cond); g_mutex_init(&self->lock); self->data = data; self->startup.finished = FALSE; self->startup.result = FALSE; } void main_loop_threaded_worker_clear(MainLoopThreadedWorker *self) { /* by the time main_loop_threaded_worker_clear() is called, the mainloop * should have terminated the thread with its request_exit() method. The * mainloop also ensures that these threads actually exit. If the code * hangs on this g_thread_join(), your worker probably did not respond to * the request_exit() call or there's a bug in mainloop. * * With that in mind, g_thread_join() would return immediately and the * only side effect is that it drops the reference to self->thread. */ if (self->thread) g_thread_join(self->thread); g_cond_clear(&self->startup.cond); g_mutex_clear(&self->lock); } syslog-ng-syslog-ng-4.4.0/lib/mainloop-threaded-worker.h000066400000000000000000000037471450431004300232100ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_THREADED_WORKER_H_INCLUDED #define MAINLOOP_THREADED_WORKER_H_INCLUDED #include "mainloop-worker.h" typedef void (*MainLoopThreadedWorkerFunc)(gpointer user_data); typedef struct _MainLoopThreadedWorker MainLoopThreadedWorker; struct _MainLoopThreadedWorker { gpointer data; MainLoopWorkerType worker_type; GThread *thread; GMutex lock; struct { GCond cond; gboolean finished; gboolean result; } startup; gboolean (*thread_init)(MainLoopThreadedWorker *s); void (*thread_deinit)(MainLoopThreadedWorker *s); void (*request_exit)(MainLoopThreadedWorker *self); void (*run)(MainLoopThreadedWorker *self); }; gboolean main_loop_threaded_worker_start(MainLoopThreadedWorker *self); void main_loop_threaded_worker_init(MainLoopThreadedWorker *self, MainLoopWorkerType worker_type, gpointer data); void main_loop_threaded_worker_clear(MainLoopThreadedWorker *self); #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop-worker.c000066400000000000000000000336641450431004300214260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop-worker.h" #include "mainloop-call.h" #include "tls-support.h" #include "apphook.h" #include "messages.h" #include "scratch-buffers.h" #include "atomic.h" #include TLS_BLOCK_START { /* Thread IDs are low numbered integers that can be used to index * per-thread data in an array. IDs get reused and the smallest possible * ID is allocated for newly started threads. */ /* the thread id is shifted by one, to make 0 the uninitialized state, * e.g. everything that sets it adds +1, everything that queries it * subtracts 1 */ gint main_loop_worker_id; MainLoopWorkerType main_loop_worker_type; struct iv_list_head batch_callbacks; } TLS_BLOCK_END; #define main_loop_worker_id __tls_deref(main_loop_worker_id) #define batch_callbacks __tls_deref(batch_callbacks) #define main_loop_worker_type __tls_deref(main_loop_worker_type) GQueue sync_call_actions = G_QUEUE_INIT; /* cause workers to stop, no new I/O jobs to be submitted */ volatile gboolean main_loop_workers_quit; volatile gboolean is_reloading_scheduled; /* number of I/O worker jobs running */ static GAtomicCounter main_loop_jobs_running; static struct iv_task main_loop_workers_reenable_jobs_task; /* thread ID allocation */ static GMutex main_loop_workers_idmap_lock; #define MAIN_LOOP_IDMAP_BITS_PER_ROW (sizeof(guint64)*8) #define MAIN_LOOP_IDMAP_ROWS (MAIN_LOOP_MAX_WORKER_THREADS / MAIN_LOOP_IDMAP_BITS_PER_ROW) static guint64 main_loop_workers_idmap[MAIN_LOOP_IDMAP_ROWS]; static gint main_loop_max_workers = 0; static gint main_loop_estimated_number_of_workers = 0; /* NOTE: return a zero based index for the current thread, to be used in * array indexes. -1 means that the thread does not have an ID */ gint main_loop_worker_get_thread_index(void) { return main_loop_worker_id - 1; } static void _allocate_thread_id(void) { g_mutex_lock(&main_loop_workers_idmap_lock); /* the maximum number of threads must be dividible by 64, the array * main_loop_workers_idmap is sized accordingly, e.g. the remainder could * not be represented in the array as is. */ G_STATIC_ASSERT((MAIN_LOOP_MAX_WORKER_THREADS % MAIN_LOOP_IDMAP_BITS_PER_ROW) == 0); main_loop_worker_id = 0; for (gint thread_index = 0; thread_index < MAIN_LOOP_MAX_WORKER_THREADS; thread_index++) { gint row = thread_index / MAIN_LOOP_IDMAP_BITS_PER_ROW; gint bit_in_row = thread_index % MAIN_LOOP_IDMAP_BITS_PER_ROW; if ((main_loop_workers_idmap[row] & (1ULL << bit_in_row)) == 0) { /* thread_index not yet used */ main_loop_workers_idmap[row] |= (1ULL << bit_in_row); main_loop_worker_id = (thread_index + 1); break; } } g_mutex_unlock(&main_loop_workers_idmap_lock); if (main_loop_worker_id == 0) { msg_warning_once("Unable to allocate a unique thread ID. This can only " "happen if the number of syslog-ng worker threads exceeds the " "compile time constant MAIN_LOOP_MAX_WORKER_THREADS. " "This is not a fatal problem but can be a cause for " "decreased performance. Increase this number and recompile " "or contact the syslog-ng authors", evt_tag_int("max-worker-threads-hard-limit", MAIN_LOOP_MAX_WORKER_THREADS)); } if (main_loop_worker_id > main_loop_max_workers) { msg_warning_once("The actual number of worker threads exceeds the number of threads " "estimated at startup. This indicates a bug in thread estimation, " "which is not fatal but could cause decreased performance. Please " "contact the syslog-ng authors with your config to help troubleshoot " "this issue", evt_tag_int("worker-id", main_loop_worker_id), evt_tag_int("max-worker-threads", main_loop_max_workers)); main_loop_worker_id = 0; } } static void _release_thread_id(void) { g_mutex_lock(&main_loop_workers_idmap_lock); if (main_loop_worker_id) { const gint thread_index = main_loop_worker_get_thread_index(); gint row = thread_index / MAIN_LOOP_IDMAP_BITS_PER_ROW; gint bit_in_row = thread_index % MAIN_LOOP_IDMAP_BITS_PER_ROW; main_loop_workers_idmap[row] &= ~(1ULL << (bit_in_row)); main_loop_worker_id = 0; } g_mutex_unlock(&main_loop_workers_idmap_lock); } gboolean main_loop_worker_is_worker_thread(void) { return main_loop_worker_type > MLW_UNKNOWN; } typedef struct _WorkerExitNotification { WorkerExitNotificationFunc func; gpointer user_data; } WorkerExitNotification; static GList *exit_notification_list = NULL; void main_loop_worker_register_exit_notification_callback(WorkerExitNotificationFunc func, gpointer user_data) { WorkerExitNotification *cfunc = g_new(WorkerExitNotification, 1); cfunc->func = func; cfunc->user_data = user_data; exit_notification_list = g_list_append(exit_notification_list, cfunc); } static void _invoke_worker_exit_callback(WorkerExitNotification *func) { func->func(func->user_data); } static void _request_all_threads_to_exit(void) { g_list_foreach(exit_notification_list, (GFunc) _invoke_worker_exit_callback, NULL); g_list_foreach(exit_notification_list, (GFunc) g_free, NULL); g_list_free(exit_notification_list); exit_notification_list = NULL; main_loop_workers_quit = TRUE; } /* Call this function from worker threads, when you start up */ void main_loop_worker_thread_start(MainLoopWorkerType worker_type) { main_loop_worker_type = worker_type; _allocate_thread_id(); INIT_IV_LIST_HEAD(&batch_callbacks); g_mutex_lock(&workers_running_lock); main_loop_workers_running++; g_mutex_unlock(&workers_running_lock); app_thread_start(); } /* Call this function from worker threads, when you stop */ void main_loop_worker_thread_stop(void) { app_thread_stop(); _release_thread_id(); g_mutex_lock(&workers_running_lock); main_loop_workers_running--; g_cond_signal(&thread_halt_cond); g_mutex_unlock(&workers_running_lock); } void main_loop_worker_run_gc(void) { scratch_buffers_explicit_gc(); } /* * This function is called in the main thread prior to starting the * processing of a work item in a worker thread. */ void main_loop_worker_job_start(void) { g_atomic_counter_inc(&main_loop_jobs_running); } typedef struct { void (*func)(gpointer user_data); gpointer user_data; } SyncCallAction; void _register_sync_call_action(GQueue *q, void (*func)(gpointer user_data), gpointer user_data) { SyncCallAction *action = g_new0(SyncCallAction, 1); action->func = func; action->user_data = user_data; g_queue_push_tail(q, action); } void _consume_action(SyncCallAction *action) { action->func(action->user_data); g_free(action); } static void _invoke_sync_call_actions(void) { while (!g_queue_is_empty(&sync_call_actions)) { SyncCallAction *action = g_queue_pop_head(&sync_call_actions); _consume_action(action); } } /* * This function is called in the main thread after a job was finished in * one of the worker threads. * * If an intrusive operation (reload, termination) is pending and the number * of workers has dropped to zero, it commences with the intrusive * operation, as in that case we can safely assume that all workers exited. */ void main_loop_worker_job_complete(void) { main_loop_assert_main_thread(); gboolean reached_zero = g_atomic_counter_dec_and_test(&main_loop_jobs_running); if (main_loop_workers_quit && reached_zero) { /* NOTE: we can't reenable I/O jobs by setting * main_loop_io_workers_quit to FALSE right here, because a task * generated by the old config might still be sitting in the task * queue, to be invoked once we return from here. Tasks cannot be * cancelled, thus we have to get to the end of the currently running * task queue. * * Thus we register another task * (&main_loop_io_workers_reenable_jobs_task), which is guaranteed to * be added to the end of the task queue, which reenables task * submission. * * * A second constraint is that any tasks submitted by the reload * logic (sitting behind the sync_func() call below), MUST be * registered after the reenable_jobs_task, because otherwise some * I/O events will be missed, due to main_loop_io_workers_quit being * TRUE. * * * |OldTask1|OldTask2|OldTask3| ReenableTask |NewTask1|NewTask2|NewTask3| * ^ * | ivykis task list * * OldTasks get dropped because _quit is TRUE, NewTasks have to be * executed properly, otherwise we'd hang. */ iv_task_register(&main_loop_workers_reenable_jobs_task); } } /* * Register a function to be called back when the current I/O job is * finished (in the worker thread). * * NOTE: we only support one pending callback at a time, may become a list of callbacks if needed in the future */ void main_loop_worker_register_batch_callback(WorkerBatchCallback *cb) { iv_list_add(&cb->list, &batch_callbacks); } void main_loop_worker_invoke_batch_callbacks(void) { struct iv_list_head *lh, *lh2; iv_list_for_each_safe(lh, lh2, &batch_callbacks) { WorkerBatchCallback *cb = iv_list_entry(lh, WorkerBatchCallback, list); iv_list_del_init(&cb->list); cb->func(cb->user_data); } } void main_loop_worker_assert_batch_callbacks_were_processed(void) { g_assert(iv_list_empty(&batch_callbacks)); } static void _reenable_worker_jobs(void *s) { _invoke_sync_call_actions(); main_loop_workers_quit = FALSE; if (is_reloading_scheduled) msg_notice("Configuration reload finished"); is_reloading_scheduled = FALSE; } void main_loop_worker_sync_call(void (*func)(gpointer user_data), gpointer user_data) { main_loop_assert_main_thread(); _register_sync_call_action(&sync_call_actions, func, user_data); /* * This might seem racy as we are reading an atomic counter without * testing it for its zero value. This is safe, because: * * - the only case we increment main_loop_jobs_running from the non-main * thread is when we submit slave jobs to the worker pool * * - slave jobs are submitted by worker jobs at a point where * main_loop_jobs_running cannot be zero (since they are running) * * - decrementing main_loop_jobs_running always happens in the main * thread (in main_loop_worker_job_complete) * * - this function is called by the main thread. * * With all this said, checking the main_loop_jobs_running is zero is not * in fact racy as once it reaches zero there's no concurrency. If it's * non-zero, then the _complete() callbacks are yet to run, but that * always happens in the thread we are executing now. */ if (g_atomic_counter_get(&main_loop_jobs_running) == 0) { _reenable_worker_jobs(NULL); } else { _request_all_threads_to_exit(); } } /* This function is intended to be used from test programs to properly * synchronize threaded worker startups and then trigger everything to exit * and wait for that too. This is useful in LogThreadedDestDriver test * cases, where the test program itself is the "main" thread and we don't * want to launch an entire main loop, because in that case we'd be forced * to feed the worker thread from ivykis callbacks, which is a lot more * difficult to write/maintain. * * This function clearly shows the level of ugly couplings between the * various mainloop components. (e.g. mainloop and mainloop worker). I * consider that this should be part of the mainloop layer (semantically, it * is the main loop that we are launching in a special mode. This is also * indicated by the iv_main() call below). However its implementation * requires access to the main_loop_workers variable. */ void main_loop_sync_worker_startup_and_teardown(void) { struct iv_task request_exit; if (g_atomic_counter_get(&main_loop_jobs_running) == 0) return; IV_TASK_INIT(&request_exit); request_exit.handler = (void (*)(void *)) _request_all_threads_to_exit; iv_task_register(&request_exit); _register_sync_call_action(&sync_call_actions, (void (*)(gpointer user_data)) iv_quit, NULL); iv_main(); } gint main_loop_worker_get_max_number_of_threads(void) { return main_loop_max_workers; } void main_loop_worker_allocate_thread_space(gint num_threads) { main_loop_estimated_number_of_workers += num_threads; } void main_loop_worker_finalize_thread_space(void) { main_loop_max_workers = main_loop_estimated_number_of_workers; main_loop_estimated_number_of_workers = 0; } static void __pre_init_hook(gint type, gpointer user_data) { main_loop_worker_finalize_thread_space(); } void main_loop_worker_init(void) { IV_TASK_INIT(&main_loop_workers_reenable_jobs_task); main_loop_workers_reenable_jobs_task.handler = _reenable_worker_jobs; register_application_hook(AH_CONFIG_PRE_INIT, __pre_init_hook, NULL, AHM_RUN_REPEAT); } void main_loop_worker_deinit(void) { } syslog-ng-syslog-ng-4.4.0/lib/mainloop-worker.h000066400000000000000000000065261450431004300214300ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_WORKER_H_INCLUDED #define MAINLOOP_WORKER_H_INCLUDED 1 #include "mainloop.h" #include #define MAIN_LOOP_MIN_WORKER_THREADS 2 #define MAIN_LOOP_MAX_WORKER_THREADS 256 typedef enum { MLW_UNKNOWN, MLW_ASYNC_WORKER = 1, MLW_THREADED_OUTPUT_WORKER, MLW_THREADED_INPUT_WORKER, MAIN_LOOP_WORKER_TYPE_MAX } MainLoopWorkerType; /* * A batch callback is registered during the processing of messages in a * given thread. Batch callbacks are invoked when the batch is complete. * * This mechanism is used by LogQueueFifo implementation, that consumes * messages into a per-thread, unlocked queue first and once the whole batch * is in, it grabs a lock and propagates the elements towards the consumer. */ typedef struct _WorkerBatchCallback { struct iv_list_head list; MainLoopTaskFunc func; gpointer user_data; } WorkerBatchCallback; static inline void worker_batch_callback_init(WorkerBatchCallback *self) { INIT_IV_LIST_HEAD(&self->list); } void main_loop_worker_register_batch_callback(WorkerBatchCallback *cb); void main_loop_worker_invoke_batch_callbacks(void); void main_loop_worker_assert_batch_callbacks_were_processed(void); typedef void (*WorkerExitNotificationFunc)(gpointer user_data); gint main_loop_worker_get_thread_index(void); void main_loop_worker_job_start(void); void main_loop_worker_job_complete(void); void main_loop_worker_thread_start(MainLoopWorkerType worker_type); void main_loop_worker_thread_stop(void); void main_loop_worker_run_gc(void); void main_loop_worker_register_exit_notification_callback(WorkerExitNotificationFunc func, gpointer user_data); gboolean main_loop_worker_is_worker_thread(void); void main_loop_worker_sync_call(void (*func)(void *user_data), void *user_data); void main_loop_sync_worker_startup_and_teardown(void); void main_loop_worker_init(void); void main_loop_worker_deinit(void); gint main_loop_worker_get_max_number_of_threads(void); void main_loop_worker_allocate_thread_space(gint num_threads); void main_loop_worker_finalize_thread_space(void); extern volatile gboolean main_loop_workers_quit; extern volatile gboolean is_reloading_scheduled; static inline gboolean main_loop_worker_job_quit(void) { return main_loop_workers_quit; } static inline void main_loop_assert_worker_thread(void) { #if SYSLOG_NG_ENABLE_DEBUG g_assert(main_loop_worker_is_worker_thread()); #endif } #endif syslog-ng-syslog-ng-4.4.0/lib/mainloop.c000066400000000000000000000552051450431004300201120ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mainloop.h" #include "mainloop-worker.h" #include "mainloop-io-worker.h" #include "mainloop-call.h" #include "mainloop-control.h" #include "apphook.h" #include "cfg.h" #include "stats/stats-registry.h" #include "stats/stats-counter.h" #include "stats/stats-cluster-single.h" #include "messages.h" #include "children.h" #include "control/control-main.h" #include "reloc.h" #include "service-management.h" #include "persist-state.h" #include "run-id.h" #include "host-id.h" #include "debugger/debugger-main.h" #include "plugin.h" #include "resolved-configurable-paths.h" #include "scratch-buffers.h" #include "timeutils/misc.h" #include "stats/stats-control.h" #include "healthcheck/healthcheck-control.h" #include "signal-handler.h" #include "cfg-monitor.h" #include #include #include #include #include #include #include volatile gint main_loop_workers_running; /** * Processing model * ================ * * This comment documents how the work performed by syslog-ng is * partitioned between threads. First of all it is useful to know that * the configuration is translated to a tree of LogPipe instances, as * described in a comment in logpipe.h. * * The basic assumptions for threading: * - configuration file is parsed in the main thread * - the log pipe tree is built in the main thread * - processing of messages is stalled while the * configuration is reloaded * - the _queue() operation for LogPipe instances can happen in * multiple threads * - notifications across LogPipe instances happen in the main thread * * This boils down to: * =================== * - If not otherwise specified LogPipe derived classes can only be * instantiated (e.g. new()) or initialized/deinitialized (_init/deinit) * in the main thread. Exceptions to this rule are documented below. * - All queue operations finish before either deinit is called. * - Locking is only needed between multiple invocations of _queue() * in parallel threads, and any other main thread activity. * * Threading model * =============== * - the main thread manages the configuration and polls for I/O * using epoll * - whenever an I/O event happens, work may be delegated to worker * threads. Currently only the LogReader/LogWriter classes make use * of worker threads, everything else remains in the main thread * (internal messages, incoming connections, etc). * - _all_ I/O polling must be registered in the main thread (update_watches * and friends) * */ ThreadId main_thread_handle; GCond thread_halt_cond; GMutex workers_running_lock; struct _MainLoop { /* * This variable is used to detect that syslog-ng is being terminated, in which * case ongoing reload operations are aborted. * * The variable is deeply embedded in various mainloop callbacks to get out * of an ongoing reload and start doing the termination instead. A better * solution would be to use a queue for intrusive, worker-stopping * operations and serialize such tasks so they won't interfere which each other. * * This interference is now implemented by conditionals scattered around the code. * * Example: * * reload is now taking two steps (marked R in the figure below) * 1) parse the configuration and request worker threads to be stopped * 2) apply the configuration once all threads exited * * termination is also taking two steps * 1) send out the shutting down message and start waiting 100msec * 2) terminate the mainloop * * The problem happens when reload and termination happen at around the same * time and these steps are interleaved. * * Normal operation: RRTT (e.g. reload finishes, then termination) * Problematic case: RTRT (e.g. reload starts, termination starts, config apply, terminate) * * In the problematic case, two independent operations do similar things to * the mainloop, and to prevent misfortune we need to handle this case explicitly. * * Were the two operations serialized by some kind of queue, the problems * would be gone. */ gboolean _is_terminating; gboolean last_config_reload_successful; time_t last_config_reload_time; /* signal handling */ struct iv_signal sighup_poll; struct iv_signal sigterm_poll; struct iv_signal sigint_poll; struct iv_signal sigchild_poll; struct iv_signal sigusr1_poll; struct iv_event exit_requested; struct iv_timer exit_timer; /* Currently running configuration, should not be used outside the mainloop * logic. If anything needs access to the GlobalConfig instance at runtime, * it needs to save that during initialization. If anything needs the * config being parsed (e.g. in the bison generated code), it should * consult the value of "configuration", which is NULL after the parsing is * finished. */ GlobalConfig *current_configuration; /* the old configuration that is being reloaded */ GlobalConfig *old_config; /* the pending configuration we wish to switch to */ GlobalConfig *new_config; MainLoopOptions *options; ControlServer *control_server; CfgMonitor *cfg_monitor; struct { StatsCounterItem *last_reload; StatsCounterItem *last_successful_reload; StatsCounterItem *last_cfgfile_mtime; } metrics; }; static MainLoop main_loop; MainLoop * main_loop_get_instance(void) { return &main_loop; } void main_loop_set_server_mode(MainLoop *self, gboolean server_mode) { self->options->server_mode = server_mode; } gboolean main_loop_is_server_mode(MainLoop *self) { return self->options->server_mode; } /* called when syslog-ng first starts up */ gboolean main_loop_initialize_state(GlobalConfig *cfg, const gchar *persist_filename) { cfg->state = persist_state_new(persist_filename); persist_state_set_global_error_handler(cfg->state, (gpointer)main_loop_exit, (gpointer)main_loop_get_instance()); if (!persist_state_start(cfg->state)) return FALSE; if (!run_id_init(cfg->state)) return FALSE; if (!host_id_init(cfg->state)) return FALSE; if (!cfg_init(cfg)) { cfg_deinit(cfg); persist_state_cancel(cfg->state); return FALSE; } persist_state_commit(cfg->state); return TRUE; } gboolean main_loop_is_terminating(MainLoop *self) { return self->_is_terminating; } gboolean main_loop_was_last_reload_successful(MainLoop *self) { return self->last_config_reload_successful; } static void main_loop_reload_config_finished(MainLoop *self) { app_config_changed(); self->new_config = NULL; self->old_config = NULL; } static void main_loop_reload_config_revert(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; cfg_persist_config_move(self->new_config, self->old_config); cfg_deinit(self->new_config); if (!cfg_init(self->old_config)) { /* hmm. hmmm, error reinitializing old configuration, we're hosed. * Best is to kill ourselves in the hope that the supervisor * restarts us. */ kill(getpid(), SIGQUIT); g_assert_not_reached(); } persist_config_free(self->old_config->persist); self->old_config->persist = NULL; cfg_free(self->new_config); self->current_configuration = self->old_config; main_loop_reload_config_finished(self); } /* called to apply the new configuration once all I/O worker threads have finished */ static void main_loop_reload_config_apply(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; if (main_loop_is_terminating(self)) { if (self->new_config) { cfg_free(self->new_config); self->new_config = NULL; } is_reloading_scheduled = FALSE; return; } self->old_config->persist = persist_config_new(); cfg_deinit(self->old_config); cfg_persist_config_move(self->old_config, self->new_config); /* The threads have stopped, deinit methods were called, but * self->current_configuration still points to the old config. We either * go to the new config is cfg_init() is successful (just below) or revert * to the old one if it's not. * */ app_config_stopped(); self->last_config_reload_successful = cfg_init(self->new_config); if (!self->last_config_reload_successful) { msg_error("Error initializing new configuration, reverting to old config"); service_management_publish_status("Error initializing new configuration, using the old config"); main_loop_reload_config_revert(self); return; } msg_verbose("New configuration initialized"); persist_config_free(self->new_config->persist); self->new_config->persist = NULL; cfg_free(self->old_config); self->current_configuration = self->new_config; service_management_clear_status(); msg_notice("Configuration reload request received, reloading configuration"); stats_counter_set(self->metrics.last_successful_reload, (gsize) self->last_config_reload_time); /* this is already running with the new config in place */ main_loop_reload_config_finished(self); } /* initiate configuration reload */ gboolean main_loop_reload_config_prepare(MainLoop *self, GError **error) { g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); self->last_config_reload_successful = FALSE; self->last_config_reload_time = time(NULL); if (main_loop_is_terminating(self)) { g_set_error(error, MAIN_LOOP_ERROR, MAIN_LOOP_ERROR_RELOAD_FAILED, "Unable to trigger a reload while a termination is in progress"); return FALSE; } if (is_reloading_scheduled) { g_set_error(error, MAIN_LOOP_ERROR, MAIN_LOOP_ERROR_RELOAD_FAILED, "Unable to trigger a reload while another reload attempt is in progress"); return FALSE; } service_management_publish_status("Reloading configuration"); stats_counter_set(self->metrics.last_reload, (gsize) self->last_config_reload_time); self->old_config = self->current_configuration; self->new_config = cfg_new(0); if (!cfg_read_config(self->new_config, resolved_configurable_paths.cfgfilename, NULL)) { cfg_free(self->new_config); self->new_config = NULL; self->old_config = NULL; service_management_publish_status("Error parsing new configuration, using the old config"); g_set_error(error, MAIN_LOOP_ERROR, MAIN_LOOP_ERROR_RELOAD_FAILED, "Syntax error parsing configuration file"); return FALSE; } is_reloading_scheduled = TRUE; return TRUE; } void main_loop_reload_config_commence(MainLoop *self) { g_assert(is_reloading_scheduled == TRUE); main_loop_worker_sync_call(main_loop_reload_config_apply, self); } void main_loop_reload_config(MainLoop *self) { GError *error = NULL; if (!main_loop_reload_config_prepare(self, &error)) { msg_error("Error reloading configuration", evt_tag_str("reason", error->message)); g_clear_error(&error); return; } main_loop_reload_config_commence(self); } static void block_till_workers_exit(void) { gint64 end_time = g_get_monotonic_time() + 15 * G_USEC_PER_SEC; g_mutex_lock(&workers_running_lock); while (main_loop_workers_running) { if (!g_cond_wait_until(&thread_halt_cond, &workers_running_lock, end_time)) { /* timeout has passed. */ fprintf(stderr, "Main thread timed out (15s) while waiting workers threads to exit. " "workers_running: %d. Continuing ...\n", main_loop_workers_running); break; } } g_mutex_unlock(&workers_running_lock); } GlobalConfig * main_loop_get_current_config(MainLoop *self) { return self->current_configuration; } GlobalConfig * main_loop_get_pending_new_config(MainLoop *self) { return self->new_config; } /* main_loop_verify_config * compares active configuration versus config file */ void main_loop_verify_config(GString *result, MainLoop *self) { const gchar *file_path = resolved_configurable_paths.cfgfilename; gchar *config_mem = self -> current_configuration -> original_config -> str; GError *err = NULL; gchar *file_contents; if (!g_file_get_contents(file_path, &file_contents, NULL, &err)) { g_string_assign(result, "Cannot read configuration file: "); g_string_append(result, err -> message); g_error_free(err); err = NULL; return; } if (strcmp(file_contents, config_mem) == 0) g_string_assign(result, "Configuration file matches active configuration"); else g_string_assign(result, "Configuration file does not match active configuration"); g_free(file_contents); } /************************************************************************************ * synchronized exit ************************************************************************************/ static void main_loop_exit_finish(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; /* deinit the current configuration, as at this point we _know_ that no * threads are running. This will unregister ivykis tasks and timers * that could fire while the configuration is being destructed */ cfg_deinit(self->current_configuration); iv_quit(); } static void main_loop_exit_timer_elapsed(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; main_loop_worker_sync_call(main_loop_exit_finish, self); } static void main_loop_exit_initiate(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; if (main_loop_is_terminating(self)) return; control_server_cancel_workers(self->control_server); app_pre_shutdown(); msg_notice("syslog-ng shutting down", evt_tag_str("version", SYSLOG_NG_VERSION)); IV_TIMER_INIT(&self->exit_timer); iv_validate_now(); self->exit_timer.expires = iv_now; self->exit_timer.handler = main_loop_exit_timer_elapsed; self->exit_timer.cookie = self; timespec_add_msec(&self->exit_timer.expires, 100); iv_timer_register(&self->exit_timer); self->_is_terminating = TRUE; } /************************************************************************************ * signal handlers ************************************************************************************/ static void sig_hup_handler(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; main_loop_reload_config(self); } static void sig_term_handler(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; main_loop_exit_initiate(self); } static void sig_int_handler(gpointer user_data) { MainLoop *self = (MainLoop *) user_data; main_loop_exit_initiate(self); signal_handler_exec_external_handler(SIGINT); } static void sig_child_handler(gpointer user_data) { pid_t pid; int status; /* this may handle multiple SIGCHLD signals, however it doesn't * matter if one or multiple SIGCHLD was received assuming that * all exited child process are waited for */ do { pid = waitpid(-1, &status, WNOHANG); child_manager_sigchild(pid, status); signal_handler_exec_external_handler(SIGCHLD); } while (pid > 0); } static void sig_usr1_handler(gpointer user_data) { app_reopen_files(); } static void _ignore_signal(gint signum) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(signum, &sa, NULL); } static void _register_signal_handler(struct iv_signal *signal_poll, gint signum, void (*handler)(void *), gpointer user_data) { IV_SIGNAL_INIT(signal_poll); signal_poll->signum = signum; signal_poll->flags = IV_SIGNAL_FLAG_EXCLUSIVE; signal_poll->cookie = user_data; signal_poll->handler = handler; iv_signal_register(signal_poll); } static void setup_signals(MainLoop *self) { _ignore_signal(SIGPIPE); _register_signal_handler(&self->sighup_poll, SIGHUP, sig_hup_handler, self); _register_signal_handler(&self->sigchild_poll, SIGCHLD, sig_child_handler, self); _register_signal_handler(&self->sigterm_poll, SIGTERM, sig_term_handler, self); _register_signal_handler(&self->sigint_poll, SIGINT, sig_int_handler, self); _register_signal_handler(&self->sigusr1_poll, SIGUSR1, sig_usr1_handler, self); } /************************************************************************************ * syslog-ng main loop ************************************************************************************/ static void _register_event(struct iv_event *event, void (*handler)(void *), gpointer user_data) { IV_EVENT_INIT(event); event->handler = handler; event->cookie = user_data; iv_event_register(event); } static void main_loop_init_events(MainLoop *self) { _register_event(&self->exit_requested, main_loop_exit_initiate, self); } void main_loop_exit(MainLoop *self) { iv_event_post(&self->exit_requested); return; } static void _register_metrics(MainLoop *self) { /* MainLoop metrics are on stats-level 0 as they "go through" several * configuration changes */ stats_lock(); StatsClusterKey k; stats_cluster_single_key_set(&k, "last_config_reload_timestamp_seconds", NULL, 0); stats_register_counter(0, &k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_reload); stats_cluster_single_key_set(&k, "last_successful_config_reload_timestamp_seconds", NULL, 0); stats_register_counter(0, &k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_successful_reload); stats_cluster_single_key_set(&k, "last_config_file_modification_timestamp_seconds", NULL, 0); stats_register_counter(0, &k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_cfgfile_mtime); stats_unlock(); } static void _unregister_metrics(MainLoop *self) { stats_lock(); StatsClusterKey k; stats_cluster_single_key_set(&k, "last_config_reload_timestamp_seconds", NULL, 0); stats_unregister_counter(&k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_reload); stats_cluster_single_key_set(&k, "last_successful_config_reload_timestamp_seconds", NULL, 0); stats_unregister_counter(&k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_successful_reload); stats_cluster_single_key_set(&k, "last_config_file_modification_timestamp_seconds", NULL, 0); stats_unregister_counter(&k, SC_TYPE_SINGLE_VALUE, &self->metrics.last_cfgfile_mtime); stats_unlock(); } static void _cfg_file_modified(const CfgMonitorEvent *event, gpointer c) { MainLoop *self = (MainLoop *) c; stats_counter_set(self->metrics.last_cfgfile_mtime, (gsize) event->st.st_mtime); } void main_loop_init(MainLoop *self, MainLoopOptions *options) { service_management_publish_status("Starting up..."); g_mutex_init(&workers_running_lock); self->options = options; scratch_buffers_automatic_gc_init(); main_loop_worker_init(); main_loop_io_worker_init(); main_loop_call_init(); main_loop_init_events(self); setup_signals(self); self->current_configuration = cfg_new(0); if (self->options->disable_module_discovery) self->current_configuration->use_plugin_discovery = FALSE; _register_metrics(self); } static inline void _init_reload_metrics(MainLoop *self) { time_t config_init_time = time(NULL); stats_counter_set(self->metrics.last_reload, (gsize) config_init_time); stats_counter_set(self->metrics.last_successful_reload, (gsize) config_init_time); } /* * Returns: exit code to be returned to the calling process, 0 on success. */ int main_loop_read_and_init_config(MainLoop *self) { MainLoopOptions *options = self->options; _init_reload_metrics(self); if (!cfg_read_config(self->current_configuration, resolved_configurable_paths.cfgfilename, options->preprocess_into)) { return 1; } if (options->config_id) { GString *config_id = g_string_sized_new(128); cfg_format_id(self->current_configuration, config_id); fprintf(stdout, "%s\n", config_id->str); g_string_free(config_id, TRUE); return 0; } if (options->syntax_only || options->preprocess_into) { return 0; } app_config_stopped(); if (!main_loop_initialize_state(self->current_configuration, resolved_configurable_paths.persist_file)) { return 2; } self->control_server = control_init(resolved_configurable_paths.ctlfilename); self->cfg_monitor = cfg_monitor_new(); cfg_monitor_add_watch(self->cfg_monitor, _cfg_file_modified, self); cfg_monitor_start(self->cfg_monitor); main_loop_register_control_commands(self); stats_register_control_commands(); healthcheck_register_control_commands(); return 0; } static void main_loop_free_config(MainLoop *self) { cfg_free(self->current_configuration); self->current_configuration = NULL; } void main_loop_deinit(MainLoop *self) { main_loop_free_config(self); if (self->cfg_monitor) { cfg_monitor_stop(self->cfg_monitor); cfg_monitor_free(self->cfg_monitor); } control_deinit(self->control_server); iv_event_unregister(&self->exit_requested); main_loop_call_deinit(); main_loop_io_worker_deinit(); main_loop_worker_deinit(); block_till_workers_exit(); scratch_buffers_automatic_gc_deinit(); g_mutex_clear(&workers_running_lock); _unregister_metrics(self); } void main_loop_run(MainLoop *self) { msg_notice("syslog-ng starting up", evt_tag_str("version", SYSLOG_NG_VERSION)); /* main loop */ service_management_indicate_readiness(); service_management_clear_status(); if (self->options->interactive_mode) { cfg_load_module(self->current_configuration, "mod-python"); debugger_start(self, self->current_configuration); } app_running(); iv_main(); service_management_publish_status("Shutting down..."); } void main_loop_add_options(GOptionContext *ctx) { main_loop_io_worker_add_options(ctx); } void main_loop_thread_resource_init(void) { g_cond_init(&thread_halt_cond); main_thread_handle = get_thread_id(); } void main_loop_thread_resource_deinit(void) { g_cond_clear(&thread_halt_cond); } gboolean main_loop_is_control_server_running(MainLoop *self) { return self->control_server != NULL; } GQuark main_loop_error_quark(void) { return g_quark_from_static_string("main-loop-error-quark"); } syslog-ng-syslog-ng-4.4.0/lib/mainloop.h000066400000000000000000000061621450431004300201150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MAINLOOP_H_INCLUDED #define MAINLOOP_H_INCLUDED #include "syslog-ng.h" #include "thread-utils.h" extern volatile gint main_loop_workers_running; typedef struct _MainLoop MainLoop; typedef struct _MainLoopOptions { gchar *preprocess_into; gboolean syntax_only; gboolean config_id; gboolean interactive_mode; gboolean server_mode; gboolean disable_module_discovery; } MainLoopOptions; extern ThreadId main_thread_handle; extern GCond thread_halt_cond; extern GMutex workers_running_lock; typedef gpointer (*MainLoopTaskFunc)(gpointer user_data); static inline void main_loop_assert_main_thread(void) { #if SYSLOG_NG_ENABLE_DEBUG g_assert(threads_equal(main_thread_handle, get_thread_id())); #endif } static inline gboolean main_loop_is_main_thread(void) { return threads_equal(main_thread_handle, get_thread_id()); } gboolean main_loop_reload_config_prepare(MainLoop *self, GError **error); void main_loop_reload_config_commence(MainLoop *self); void main_loop_reload_config(MainLoop *self); void main_loop_verify_config(GString *result, MainLoop *self); gboolean main_loop_is_terminating(MainLoop *self); void main_loop_exit(MainLoop *self); int main_loop_read_and_init_config(MainLoop *self); gboolean main_loop_was_last_reload_successful(MainLoop *self); void main_loop_run(MainLoop *self); MainLoop *main_loop_get_instance(void); GlobalConfig *main_loop_get_current_config(MainLoop *self); GlobalConfig *main_loop_get_pending_new_config(MainLoop *self); void main_loop_init(MainLoop *self, MainLoopOptions *options); void main_loop_deinit(MainLoop *self); void main_loop_add_options(GOptionContext *ctx); gboolean main_loop_is_server_mode(MainLoop *self); void main_loop_set_server_mode(MainLoop *self, gboolean server_mode); gboolean main_loop_initialize_state(GlobalConfig *cfg, const gchar *persist_filename); void main_loop_thread_resource_init(void); void main_loop_thread_resource_deinit(void); gboolean main_loop_is_control_server_running(MainLoop *self); #define MAIN_LOOP_ERROR main_loop_error_quark() GQuark main_loop_error_quark(void); enum MainLoopError { MAIN_LOOP_ERROR_FAILED, MAIN_LOOP_ERROR_RELOAD_FAILED, }; #endif syslog-ng-syslog-ng-4.4.0/lib/memtrace.c000066400000000000000000000354121450431004300200670ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #if SYSLOG_NG_ENABLE_MEMTRACE #define REALLY_TRACE_MALLOC 1 #define SYSLOG_NG_ENABLE_HEAP_TRACE 1 #include #include #include #include #include #include #include #include #include #include #define MEMTRACE_BACKTRACE_LEN 64 #define MEMTRACE_BACKTRACE_BUF_LEN (MEMTRACE_BACKTRACE_LEN * 11 + 1) #define MEMTRACE_CANARY_SIZE 2 #define MEMTRACE_CANARY_FILL 0xcd #define MEMTRACE_CANARY_CHECK 0xcdcdcdcd #define MEMTRACE_CANARY_OVERHEAD sizeof(ZMemTraceCanary) * 2 typedef struct _ZMemTraceCanary { gint size; gint neg_size; guint32 canary[MEMTRACE_CANARY_SIZE]; } ZMemTraceCanary; typedef struct _ZMemTraceEntry { guint32 next; guint32 ptr; guint32 size; gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; } ZMemTraceEntry; typedef struct _ZMemTraceHead { guint32 list; GMutex lock; gulong size; } ZMemTraceHead; #define MEMTRACE_HASH_SIZE 32768 #define MEMTRACE_HASH_MASK (32767 << 3) #define MEMTRACE_HASH_SHIFT 3 /* at most this amount of blocks can be allocated at the same time * This preallocates MEMTRACE_HEAP_SIZE * sizeof(ZMemTraceEntry), * which is 268 bytes currently. (17MB) */ #define MEMTRACE_HEAP_SIZE 65536 #define MEMTRACE_TEMP_HEAP_SIZE 32768 ZMemTraceHead mem_trace_hash[MEMTRACE_HASH_SIZE]; ZMemTraceEntry mem_trace_heap[MEMTRACE_HEAP_SIZE]; guint32 mem_trace_free_list = -1; guint32 mem_block_count = 0, mem_allocated_size = 0, mem_alloc_count = 0; gboolean mem_trace_initialized = FALSE; GMutex mem_trace_lock; gint mem_trace_log_fd = -1; gchar *mem_trace_filename = "/var/tmp/zorp-memtrace.log"; gboolean mem_trace_canaries = TRUE; gchar temp_heap[MEMTRACE_TEMP_HEAP_SIZE]; gint temp_brk = 0; gint mem_trace_recurse = 0; #define TMP_ALLOCATED(ptr) (((guint32) ((char *) ptr - temp_heap)) < MEMTRACE_TEMP_HEAP_SIZE) void *(*old_malloc)(size_t size); void (*old_free)(void *ptr); void *(*old_realloc)(void *ptr, size_t size); void *(*old_calloc)(size_t nmemb, size_t size); void z_mem_trace_init(gchar *tracefile) { int i; if (!mem_trace_initialized) { mem_trace_initialized = TRUE; for (i = 0; i < MEMTRACE_HEAP_SIZE; i++) { mem_trace_heap[i].next = i+1; } mem_trace_heap[MEMTRACE_HEAP_SIZE - 1].next = -1; mem_trace_free_list = 0; for (i = 0; i < MEMTRACE_HASH_SIZE; i++) { mem_trace_hash[i].list = -1; g_mutex_init(&mem_trace_hash[i].lock); } old_malloc = dlsym(RTLD_NEXT, "malloc"); old_free = dlsym(RTLD_NEXT, "free"); old_realloc = dlsym(RTLD_NEXT, "realloc"); old_calloc = dlsym(RTLD_NEXT, "calloc"); if (tracefile) { mem_trace_filename = g_new0(gchar, strlen("/var/tmp/") + strlen(tracefile) + 1); g_snprintf(mem_trace_filename, strlen("/var/tmp/") + strlen(tracefile) + 1, "%s%s", "/var/tmp/", tracefile); } } } static guint32 z_mem_trace_hash(guint32 ptr) { return (ptr & MEMTRACE_HASH_MASK) >> MEMTRACE_HASH_SHIFT; } void z_mem_trace_bt(gpointer backtrace[]) { /* NOTE: this is i386 specific */ gpointer x; gpointer *ebp = &x+1; gint i = 0; while ((ebp > &x) && *ebp && i < MEMTRACE_BACKTRACE_LEN - 1) { gpointer value = *(ebp + 1); backtrace[i] = value; i++; ebp = *ebp; } backtrace[i] = NULL; } static char * z_mem_trace_format_bt(gpointer backtrace[], gchar *buf, gint buflen) { gchar *p = buf; gint i, len; for (i = 0; i < MEMTRACE_BACKTRACE_LEN && buflen >= 12 && backtrace[i]; i++) { len = sprintf(buf, "%p,", backtrace[i]); buf += len; buflen -= len; } return p; } static void z_mem_trace_printf(char *format, ...) { gchar buf[1024]; gint len; va_list l; va_start(l, format); len = vsnprintf(buf, sizeof(buf), format, l); va_end(l); mem_trace_log_fd = open(mem_trace_filename, O_CREAT | O_WRONLY | O_APPEND, 0600); if (mem_trace_log_fd != -1) { write(mem_trace_log_fd, buf, len); close(mem_trace_log_fd); } } void z_mem_trace_stats(void) { z_mem_trace_printf("time: %d, allocs: %ld, blocks: %ld, size: %ld\n", time(NULL), mem_alloc_count, mem_block_count, mem_allocated_size); } static gpointer z_mem_trace_check_canaries(gpointer ptr); void z_mem_trace_dump(void) { int i; z_mem_trace_printf("memdump begins\n"); for (i = 0; i < MEMTRACE_HASH_SIZE; i++) { ZMemTraceHead *head = &mem_trace_hash[i]; ZMemTraceEntry *entry; int cur; g_mutex_lock(&head->lock); cur = head->list; while (cur != -1) { char backtrace_buf[MEMTRACE_BACKTRACE_BUF_LEN]; entry = &mem_trace_heap[cur]; z_mem_trace_printf("ptr=%p, size=%d, backtrace=%s\n", entry->ptr, entry->size, z_mem_trace_format_bt(entry->backtrace, backtrace_buf, sizeof(backtrace_buf))); if (mem_trace_canaries) { z_mem_trace_check_canaries((gpointer)entry->ptr); } cur = entry->next; } g_mutex_unlock(&head->lock); } } /** * @ptr raw pointer * @size original size * * returns the pointer to be returned */ static gpointer z_mem_trace_fill_canaries(gpointer ptr, gint size) { if (!ptr) return ptr; if (mem_trace_canaries) { ZMemTraceCanary *p_before = (ZMemTraceCanary *) ptr; ZMemTraceCanary *p_after = (ZMemTraceCanary *)(((gchar *) ptr) + sizeof(ZMemTraceCanary) + size); memset(p_before->canary, MEMTRACE_CANARY_FILL, sizeof(p_before->canary)); memset(p_after->canary, MEMTRACE_CANARY_FILL, sizeof(p_after->canary)); p_before->size = p_after->size = size; p_before->neg_size = p_after->neg_size = -size; return (gpointer) (p_before + 1); } else return ptr; } /** * @ptr user pointer * * returns the pointer to be freed * * Aborts if the canaries are touched. * */ static gpointer z_mem_trace_check_canaries(gpointer ptr) { if (!ptr) return ptr; if (mem_trace_canaries) { ZMemTraceCanary *p_before = ((ZMemTraceCanary *) ptr) - 1; ZMemTraceCanary *p_after; int i; if (p_before->size != -p_before->neg_size) { z_mem_trace_printf("Inconsystency in canaries; ptr=%p\n", ptr); abort(); } p_after = (ZMemTraceCanary *) (((gchar *) ptr) + p_before->size); if (p_after->size != p_before->size || p_after->neg_size != p_before->neg_size) { z_mem_trace_printf("Inconsystency in canaries; ptr=%p\n", ptr); abort(); } for (i = 0; i < MEMTRACE_CANARY_SIZE; i++) { if (p_before->canary[i] != p_after->canary[i] || p_before->canary[i] != MEMTRACE_CANARY_CHECK) { z_mem_trace_printf("Touched canary; ptr=%p\n", ptr); abort(); } } return (gpointer) p_before; } return ptr; } static gboolean z_mem_trace_add(gpointer ptr, gint size, gpointer backtrace[]) { guint32 hash, new_ndx; ZMemTraceEntry *new; ZMemTraceHead *head; gchar backtrace_buf[8192]; hash = z_mem_trace_hash((guint32) ptr); g_mutex_lock(&mem_trace_lock); if (mem_trace_free_list == -1) { return FALSE; } mem_block_count++; mem_alloc_count++; if ((mem_alloc_count % 1000) == 0) z_mem_trace_stats(); mem_allocated_size += size; new_ndx = mem_trace_free_list; new = &mem_trace_heap[new_ndx]; mem_trace_free_list = mem_trace_heap[mem_trace_free_list].next; g_mutex_unlock(&mem_trace_lock); new->ptr = (guint32) ptr; new->size = size; memmove(new->backtrace, backtrace, sizeof(new->backtrace)); head = &mem_trace_hash[hash]; g_mutex_lock(&head->lock); new->next = head->list; head->list = new_ndx; g_mutex_unlock(&head->lock); #if REALLY_TRACE_MALLOC z_mem_trace_printf("memtrace addblock; ptr=%p, size=%d, backtrace=%s\n", ptr, size, z_mem_trace_format_bt(backtrace, backtrace_buf, sizeof(backtrace_buf))); #endif return TRUE; } static gboolean z_mem_trace_del(gpointer ptr) { guint32 hash, *prev, cur; ZMemTraceHead *head; ZMemTraceEntry *entry; gchar backtrace_buf[8192]; hash = z_mem_trace_hash((guint32) ptr); head = &mem_trace_hash[hash]; g_mutex_lock(&head->lock); prev = &head->list; cur = head->list; while (cur != -1 && mem_trace_heap[cur].ptr != (guint32) ptr) { prev = &mem_trace_heap[cur].next; cur = mem_trace_heap[cur].next; } if (cur == -1) { g_mutex_unlock(&head->lock); return FALSE; } *prev = mem_trace_heap[cur].next; g_mutex_unlock(&head->lock); g_mutex_lock(&mem_trace_lock); entry = &mem_trace_heap[cur]; #if REALLY_TRACE_MALLOC z_mem_trace_printf("memtrace delblock; ptr=%p, size=%d, backtrace=%s\n", (void *) entry->ptr, entry->size, z_mem_trace_format_bt(entry->backtrace, backtrace_buf, sizeof(backtrace_buf))); #endif mem_trace_heap[cur].next = mem_trace_free_list; mem_trace_free_list = cur; mem_block_count--; mem_allocated_size -= mem_trace_heap[cur].size; g_mutex_unlock(&mem_trace_lock); return TRUE; } static inline guint32 z_mem_trace_lookup_chain(gpointer ptr, ZMemTraceHead *head) { guint32 cur = -1; cur = head->list; while (cur != -1 && mem_trace_heap[cur].ptr != (guint32) ptr) { cur = mem_trace_heap[cur].next; } return cur; } static int z_mem_trace_getsize(gpointer ptr) { guint32 hash, cur; int size; ZMemTraceHead *head; hash = z_mem_trace_hash((guint32) ptr); head = &mem_trace_hash[hash]; g_mutex_lock(&head->lock); cur = z_mem_trace_lookup_chain(ptr, head); if (cur != -1) { size = mem_trace_heap[cur].size; g_mutex_unlock(&head->lock); return size; } g_mutex_unlock(&head->lock); return -1; } void * z_malloc(size_t size, gpointer backtrace[]) { gpointer *raw_ptr, *user_ptr; raw_ptr = old_malloc(size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); user_ptr = z_mem_trace_fill_canaries(raw_ptr, size); if (user_ptr && !z_mem_trace_add(user_ptr, size, backtrace)) { gchar buf[MEMTRACE_BACKTRACE_BUF_LEN]; old_free(raw_ptr); z_mem_trace_printf("Out of free memory blocks; backtrace='%s'\n", z_mem_trace_format_bt(backtrace, buf, sizeof(buf))); z_mem_trace_stats(); return NULL; } return user_ptr; } void z_free(void *user_ptr, gpointer backtrace[]) { gchar backtrace_buf[MEMTRACE_BACKTRACE_BUF_LEN]; gpointer raw_ptr; gint size; raw_ptr = z_mem_trace_check_canaries(user_ptr); size = z_mem_trace_getsize(user_ptr); if (size != -1) memset(user_ptr, 0xcd, size); if (user_ptr && !z_mem_trace_del(user_ptr)) { z_mem_trace_printf("Trying to free a non-existing memory block; ptr=%p, backtrace='%s'\n", user_ptr, z_mem_trace_format_bt(backtrace, backtrace_buf, sizeof(backtrace_buf))); assert(0); } if (!TMP_ALLOCATED(raw_ptr)) old_free(raw_ptr); } void * z_realloc(void *user_ptr, size_t size, gpointer backtrace[]) { void *new_ptr, *raw_ptr = NULL; int old_size = 0; gchar buf[MEMTRACE_BACKTRACE_BUF_LEN]; if (user_ptr) { raw_ptr = z_mem_trace_check_canaries(user_ptr); old_size = z_mem_trace_getsize(user_ptr); if (old_size == -1 || !z_mem_trace_del(user_ptr)) { z_mem_trace_printf("Trying to realloc a non-existing memory block; ptr=%p, size='%d', info='%s'", user_ptr, size, z_mem_trace_format_bt(backtrace, buf, sizeof(buf))); assert(0); } } if (TMP_ALLOCATED(raw_ptr)) { /* this ptr was allocated on the temp heap, move it to real heap */ z_mem_trace_printf("reallocing space on the temp heap, moving..., ptr=%p, temp_heap=%p, diff=%d, old_size=%d\n", raw_ptr, temp_heap, (char *) raw_ptr-temp_heap, old_size); new_ptr = old_malloc(size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); if (new_ptr) { new_ptr = z_mem_trace_fill_canaries(new_ptr, size); /* copy user data */ memmove(new_ptr, user_ptr, old_size); } } else { new_ptr = old_realloc(raw_ptr, size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); /* fill_canaries doesn't touch data, only fills the canary info */ new_ptr = z_mem_trace_fill_canaries(new_ptr, size); } if (new_ptr) { z_mem_trace_add(new_ptr, size, backtrace); } return new_ptr; } void * z_calloc(size_t nmemb, size_t size, gpointer backtrace[]) { void *user_ptr, *raw_ptr; if (old_calloc == NULL) { raw_ptr = &temp_heap[temp_brk]; temp_brk += nmemb * size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD; assert(temp_brk < MEMTRACE_TEMP_HEAP_SIZE); } else raw_ptr = old_calloc(nmemb, size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); user_ptr = z_mem_trace_fill_canaries(raw_ptr, nmemb * size); z_mem_trace_add(user_ptr, nmemb * size, backtrace); return user_ptr; } #undef malloc #undef free #undef realloc #undef calloc /* look up return address */ void * malloc(size_t size) { gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; z_mem_trace_bt(backtrace); return z_malloc(size, backtrace); } void free(void *ptr) { gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; z_mem_trace_bt(backtrace); return z_free(ptr, backtrace); } void * realloc(void *ptr, size_t size) { gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; z_mem_trace_bt(backtrace); return z_realloc(ptr, size, backtrace); } void * calloc(size_t nmemb, size_t size) { gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; z_mem_trace_bt(backtrace); return z_calloc(nmemb, size, backtrace); } #else void z_mem_trace_init(const gchar *memtrace_file) { } void z_mem_trace_stats(void) { } void z_mem_trace_dump(void) { } #endif syslog-ng-syslog-ng-4.4.0/lib/memtrace.h000066400000000000000000000027041450431004300200720ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ZORP_MEMTRACE_H_INCLUDED #define ZORP_MEMTRACE_H_INCLUDED void z_mem_trace_init(const gchar *memtrace_file); void z_mem_trace_stats(void); void z_mem_trace_dump(void); #if SYSLOG_NG_ENABLE_MEMTRACE #include void *z_malloc(size_t size, gpointer backtrace[]); void z_free(void *ptr, gpointer backtrace[]); void *z_realloc(void *ptr, size_t size, gpointer backtrace[]); void *z_calloc(size_t nmemb, size_t size, gpointer backtrace[]); #endif #endif syslog-ng-syslog-ng-4.4.0/lib/merge-grammar.py000077500000000000000000000046261450431004300212310ustar00rootroot00000000000000#!/usr/bin/env python3 ############################################################################# # Copyright (c) 2010-2017 Balabit # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# # # TODOs: # * be more clever about which rules to include as bison generates a lot of # warnings about unused rules # from __future__ import print_function import fileinput import os import sys import codecs grammar_file = os.path.join(os.environ.get('top_srcdir', ''), 'lib/cfg-grammar.y') if not os.path.isfile(grammar_file): grammar_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cfg-grammar.y') if not os.path.isfile(grammar_file): sys.exit('Error opening cfg-grammar.y') def print_to_stdout(line): if sys.hexversion >= 0x3000000: sys.stdout.buffer.write(line.encode("utf-8")) else: print(line.encode("utf-8"), end='') def include_block(block_type): start_marker = 'START_' + block_type end_marker = 'END_' + block_type with codecs.open(grammar_file, encoding="utf-8") as f: in_block = False for line in f: if start_marker in line: in_block = True elif end_marker in line: in_block = False elif in_block: print_to_stdout(line) for line in fileinput.input(openhook=fileinput.hook_encoded("utf-8")): if 'INCLUDE_DECLS' in line: include_block('DECLS') elif 'INCLUDE_RULES' in line: include_block('RULES') else: print_to_stdout(line) syslog-ng-syslog-ng-4.4.0/lib/messages.c000066400000000000000000000247021450431004300201010ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "messages.h" #include "timeutils/cache.h" #include "logmsg/logmsg.h" #include #include #include #include #include #include #include enum { /* processing a non-internal message, we're definitely not recursing */ RECURSE_STATE_OK = 0, /* processing an internal message currently, followup internal messages will be suppressed */ RECURSE_STATE_WATCH = 1, /* suppress all internal messages */ RECURSE_STATE_SUPPRESS = 2 }; typedef struct _MsgContext { guint16 recurse_state; guint recurse_warning:1; gchar recurse_trigger[128]; } MsgContext; static gint active_log_level = -1; static gint cmdline_log_level = -1; gboolean startup_debug_flag = 0; gboolean debug_flag = 0; gboolean verbose_flag = 0; gboolean trace_flag = 0; gboolean log_stderr = FALSE; gboolean skip_timestamp_on_stderr = FALSE; static MsgPostFunc msg_post_func; static EVTCONTEXT *evt_context; static GPrivate msg_context_private = G_PRIVATE_INIT(g_free); static GMutex evtlog_lock; static MsgContext * msg_get_context(void) { MsgContext *context; context = g_private_get(&msg_context_private); if (!context) { context = g_new0(MsgContext, 1); g_private_replace(&msg_context_private, context); } return context; } void msg_set_context(LogMessage *msg) { MsgContext *context = msg_get_context(); if (msg && (msg->flags & LF_INTERNAL)) { if (msg->recursed) context->recurse_state = RECURSE_STATE_SUPPRESS; else context->recurse_state = RECURSE_STATE_WATCH; } else { context->recurse_state = RECURSE_STATE_OK; } } static gboolean msg_limit_internal_message(const gchar *msg) { MsgContext *context; if (!evt_context) return FALSE; context = msg_get_context(); if (context->recurse_state >= RECURSE_STATE_SUPPRESS) { if (!context->recurse_warning) { msg_event_send( msg_event_create(EVT_PRI_WARNING, "internal() messages are looping back, preventing loop by suppressing all internal messages until the current message is processed", evt_tag_str("trigger-msg", context->recurse_trigger), evt_tag_str("first-suppressed-msg", msg), NULL)); context->recurse_warning = TRUE; } return FALSE; } return TRUE; } static gchar * msg_format_timestamp(gchar *buf, gsize buflen) { struct tm tm; GTimeVal now; gint len; time_t now_sec; g_get_current_time(&now); now_sec = now.tv_sec; cached_localtime(&now_sec, &tm); len = strftime(buf, buflen, "%Y-%m-%dT%H:%M:%S", &tm); if (len < buflen) g_snprintf(buf + len, buflen - len, ".%06ld", now.tv_usec); return buf; } static void msg_send_formatted_message_to_stderr(const char *msg) { gchar tmtime[128]; if (skip_timestamp_on_stderr) fprintf(stderr, "%s\n", msg); else fprintf(stderr, "[%s] %s\n", msg_format_timestamp(tmtime, sizeof(tmtime)), msg); } void msg_send_formatted_message(int prio, const char *msg) { if (G_UNLIKELY(log_stderr || (msg_post_func == NULL && (prio & 0x7) <= EVT_PRI_WARNING))) { msg_send_formatted_message_to_stderr(msg); } else if (msg_post_func) { LogMessage *m; MsgContext *context = msg_get_context(); if (context->recurse_state == RECURSE_STATE_OK) { context->recurse_warning = FALSE; g_strlcpy(context->recurse_trigger, msg, sizeof(context->recurse_trigger)); } m = log_msg_new_internal(prio, msg); m->recursed = context->recurse_state >= RECURSE_STATE_WATCH; msg_post_message(m); } } void msg_send_message_printf(int prio, const gchar *fmt, ...) { gchar buf[1024]; va_list va; va_start(va, fmt); vsnprintf(buf, sizeof(buf), fmt, va); va_end(va); msg_send_formatted_message(prio, buf); } static void msg_event_send_with_suppression(EVTREC *e, gboolean (*suppress)(const gchar *msg)) { gchar *msg; msg = evt_format(e); if (!suppress || suppress(msg)) msg_send_formatted_message(evt_rec_get_syslog_pri(e) | EVT_FAC_SYSLOG, msg); free(msg); msg_event_free(e); } void msg_event_send(EVTREC *e) { msg_event_send_with_suppression(e, NULL); } void msg_event_suppress_recursions_and_send(EVTREC *e) { msg_event_send_with_suppression(e, msg_limit_internal_message); } void msg_event_print_event_to_stderr(EVTREC *e) { gchar *msg; msg = evt_format(e); msg_send_formatted_message_to_stderr(msg); free(msg); msg_event_free(e); } EVTREC * msg_event_create(gint prio, const gchar *desc, EVTTAG *tag1, ...) { EVTREC *e; va_list va; g_mutex_lock(&evtlog_lock); e = evt_rec_init(evt_context, prio, desc); if (tag1) { evt_rec_add_tag(e, tag1); va_start(va, tag1); evt_rec_add_tagsv(e, va); va_end(va); } g_mutex_unlock(&evtlog_lock); return e; } EVTREC * msg_event_create_from_desc(gint prio, const char *desc) { return msg_event_create(prio, desc, NULL); } void msg_event_free(EVTREC *e) { g_mutex_lock(&evtlog_lock); evt_rec_free(e); g_mutex_unlock(&evtlog_lock); } void msg_log_func(const gchar *log_domain, GLogLevelFlags log_flags, const gchar *msg, gpointer user_data) { int pri = EVT_PRI_INFO; if (log_flags & G_LOG_LEVEL_DEBUG) pri = EVT_PRI_DEBUG; else if (log_flags & G_LOG_LEVEL_WARNING) pri = EVT_PRI_WARNING; else if (log_flags & G_LOG_LEVEL_ERROR) pri = EVT_PRI_ERR; pri |= EVT_FAC_SYSLOG; msg_send_formatted_message(pri, msg); } void msg_set_post_func(MsgPostFunc func) { msg_post_func = func; } void msg_post_message(LogMessage *msg) { if (msg_post_func) msg_post_func(msg); else log_msg_unref(msg); } gint msg_map_string_to_log_level(const gchar *log_level) { if (strcasecmp(log_level, "default") == 0) return 0; else if (strcasecmp(log_level, "verbose") == 0 || strcmp(log_level, "v") == 0) return 1; else if (strcasecmp(log_level, "debug") == 0 || strcmp(log_level, "d") == 0) return 2; else if (strcasecmp(log_level, "trace") == 0 || strcmp(log_level, "t") == 0) return 3; return -1; } void msg_set_log_level(gint new_log_level) { if (new_log_level < 0) return; verbose_flag = FALSE; debug_flag = FALSE; trace_flag = FALSE; if (new_log_level >= 1) verbose_flag = TRUE; if (new_log_level >= 2) debug_flag = TRUE; if (new_log_level >= 3) trace_flag = TRUE; active_log_level = new_log_level; } gint msg_get_log_level(void) { if (active_log_level < 0) return 0; return active_log_level; } void msg_apply_cmdline_log_level(gint new_log_level) { msg_set_log_level(new_log_level); cmdline_log_level = new_log_level; } void msg_apply_config_log_level(gint new_log_level) { if (cmdline_log_level < 0) msg_set_log_level(new_log_level); } static guint g_log_handler_id; static guint glib_handler_id; void msg_init(gboolean interactive) { if (evt_context) return; if (!interactive) { g_log_handler_id = g_log_set_handler(G_LOG_DOMAIN, 0xff, msg_log_func, NULL); glib_handler_id = g_log_set_handler("GLib", 0xff, msg_log_func, NULL); } else { log_stderr = TRUE; skip_timestamp_on_stderr = TRUE; } evt_context = evt_ctx_init("syslog-ng", EVT_FAC_SYSLOG); } void msg_deinit(void) { evt_ctx_free(evt_context); evt_context = NULL; log_stderr = TRUE; if (g_log_handler_id) { g_log_remove_handler(G_LOG_DOMAIN, g_log_handler_id); g_log_handler_id = 0; } if (glib_handler_id) { g_log_remove_handler("GLib", glib_handler_id); glib_handler_id = 0; } } static gboolean _process_compat_log_level_option(const gchar *option_name, const gchar *value, gpointer data, GError **error) { while (*option_name == '-') option_name++; gint ll = msg_map_string_to_log_level(option_name); if (ll < 0) return FALSE; if (ll > cmdline_log_level) msg_apply_cmdline_log_level(ll); return TRUE; } static gboolean _process_log_level_value(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gint ll = msg_map_string_to_log_level(value); if (ll < 0) return FALSE; if (ll > cmdline_log_level) msg_apply_cmdline_log_level(ll); return TRUE; } static GOptionEntry msg_option_entries[] = { { "startup-debug", 'r', 0, G_OPTION_ARG_NONE, &startup_debug_flag, "Enable debug logging during startup", NULL}, { "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, _process_compat_log_level_option, "Be a bit more verbose", NULL }, { "debug", 'd', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, _process_compat_log_level_option, "Enable debug messages", NULL}, { "trace", 't', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, _process_compat_log_level_option, "Enable trace messages", NULL }, { "log-level", 'L', 0, G_OPTION_ARG_CALLBACK, _process_log_level_value, "Set log level to verbose|debug|trace", NULL }, { "stderr", 'e', 0, G_OPTION_ARG_NONE, &log_stderr, "Log messages to stderr", NULL}, { NULL } }; void msg_add_option_group(GOptionContext *ctx) { GOptionGroup *group; group = g_option_group_new("log", "Log options", "Log options", NULL, NULL); g_option_group_add_entries(group, msg_option_entries); g_option_context_add_group(ctx, group); } syslog-ng-syslog-ng-4.4.0/lib/messages.h000066400000000000000000000135101450431004300201010ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MESSAGES_H_INCLUDED #define MESSAGES_H_INCLUDED #include "syslog-ng.h" #include #include extern int startup_debug_flag; extern int debug_flag; extern int verbose_flag; extern int trace_flag; extern int log_stderr; typedef void (*MsgPostFunc)(LogMessage *msg); void msg_set_context(LogMessage *msg); EVTREC *msg_event_create(gint prio, const char *desc, EVTTAG *tag1, ...) __attribute__((nonnull(2))); EVTREC *msg_event_create_from_desc(gint prio, const char *desc); void msg_event_free(EVTREC *e); void msg_event_send(EVTREC *e); void msg_event_suppress_recursions_and_send(EVTREC *e); void msg_event_print_event_to_stderr(EVTREC *e); void msg_set_post_func(MsgPostFunc func); gint msg_map_string_to_log_level(const gchar *log_level); void msg_set_log_level(gint new_log_level); gint msg_get_log_level(void); void msg_apply_cmdline_log_level(gint new_log_level); void msg_apply_config_log_level(gint new_log_level); void msg_init(gboolean interactive); void msg_deinit(void); void msg_add_option_group(GOptionContext *ctx); #define evt_tag_error(tag) evt_tag_errno(tag, __local_copy_of_errno) #define CAPTURE_ERRNO(lambda) do {\ int __local_copy_of_errno G_GNUC_UNUSED = errno; \ lambda; \ } while(0) /* fatal->warning goes out to the console during startup, notice and below * comes goes to the log even during startup */ #define msg_fatal(desc, tags...) CAPTURE_ERRNO(\ msg_event_suppress_recursions_and_send(msg_event_create(EVT_PRI_CRIT, desc, ##tags, NULL ))) #define msg_error(desc, tags...) CAPTURE_ERRNO(\ msg_event_suppress_recursions_and_send(msg_event_create(EVT_PRI_ERR, desc, ##tags, NULL ))) #define msg_warning(desc, tags...) CAPTURE_ERRNO(\ msg_event_suppress_recursions_and_send(msg_event_create(EVT_PRI_WARNING, desc, ##tags, NULL ))) #define msg_notice(desc, tags...) CAPTURE_ERRNO(\ msg_event_suppress_recursions_and_send(msg_event_create(EVT_PRI_NOTICE, desc, ##tags, NULL ))) #define msg_info(desc, tags...) CAPTURE_ERRNO(\ msg_event_suppress_recursions_and_send(msg_event_create(EVT_PRI_INFO, desc, ##tags, NULL ))) /* just like msg_info, but prepends the message with a timestamp -- useful in interactive * tools with long running time to provide some feedback */ #define msg_progress(desc, tags...) \ do { \ time_t t; \ char *timestamp, *newdesc; \ \ t = time(0); \ timestamp = ctime(&t); \ timestamp[strlen(timestamp) - 1] = 0; \ newdesc = g_strdup_printf("[%s] %s", timestamp, desc); \ msg_event_send(msg_event_create(EVT_PRI_INFO, newdesc, ##tags, NULL )); \ g_free(newdesc); \ } while (0) #define msg_verbose(desc, tags...) \ do { \ if (G_UNLIKELY(verbose_flag)) \ msg_info(desc, ##tags ); \ } while (0) #define msg_debug(desc, tags...) \ do { \ if (G_UNLIKELY(debug_flag)) \ msg_event_suppress_recursions_and_send( \ msg_event_create(EVT_PRI_DEBUG, desc, ##tags, NULL )); \ } while (0) #define msg_trace(desc, tags...) \ do { \ if (G_UNLIKELY(trace_flag)) \ msg_event_suppress_recursions_and_send( \ msg_event_create(EVT_PRI_DEBUG, desc, ##tags, NULL )); \ } while (0) #define msg_trace_printf(fmt, values...) \ do { \ if (G_UNLIKELY(trace_flag)) \ msg_send_message_printf(EVT_PRI_DEBUG, fmt, ##values); \ } while (0) #define msg_diagnostics(desc, tags...) \ do { \ if (G_UNLIKELY(trace_flag)) \ msg_event_print_event_to_stderr( \ msg_event_create(EVT_PRI_DEBUG, desc, ##tags, NULL )); \ } while (0) #define __once() \ ({ \ static gboolean __guard = TRUE; \ gboolean __current_guard = __guard; \ __guard = FALSE; \ __current_guard; \ }) #define msg_warning_once(desc, tags...) \ do { \ if (__once()) \ msg_warning(desc, ##tags ); \ } while (0) void msg_post_message(LogMessage *msg); void msg_send_formatted_message(int prio, const char *msg); void msg_send_message_printf(int prio, const gchar *fmt, ...) G_GNUC_PRINTF(2, 3); #endif syslog-ng-syslog-ng-4.4.0/lib/metrics-pipe.c000066400000000000000000000066201450431004300206720ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "metrics-pipe.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" static void _init_stats_keys(MetricsPipe *self, StatsClusterKey *ingress_sc_key, StatsClusterKey *egress_sc_key) { enum { labels_len = 1 }; static StatsClusterLabel labels[labels_len]; labels[0] = stats_cluster_label("id", self->log_path_name); stats_cluster_single_key_set(ingress_sc_key, "route_ingress_total", labels, labels_len); stats_cluster_single_key_set(egress_sc_key, "route_egress_total", labels, labels_len); } static void _queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { MetricsPipe *self = (MetricsPipe *) s; stats_counter_inc(self->ingress_counter); gboolean matched = TRUE; LogPathOptions local_options = *path_options; local_options.matched = &matched; log_pipe_forward_msg(s, msg, &local_options); if (*local_options.matched) stats_counter_inc(self->egress_counter); if (path_options->matched) *path_options->matched = *local_options.matched; } static gboolean _init(LogPipe *s) { MetricsPipe *self = (MetricsPipe *) s; StatsClusterKey ingress_sc_key; StatsClusterKey egress_sc_key; _init_stats_keys(self, &ingress_sc_key, &egress_sc_key); stats_lock(); { stats_register_counter(STATS_LEVEL1, &ingress_sc_key, SC_TYPE_SINGLE_VALUE, &self->ingress_counter); stats_register_counter(STATS_LEVEL1, &egress_sc_key, SC_TYPE_SINGLE_VALUE, &self->egress_counter); } stats_unlock(); return TRUE; } static gboolean _deinit(LogPipe *s) { MetricsPipe *self = (MetricsPipe *) s; StatsClusterKey ingress_sc_key; StatsClusterKey egress_sc_key; _init_stats_keys(self, &ingress_sc_key, &egress_sc_key); stats_lock(); { stats_unregister_counter(&ingress_sc_key, SC_TYPE_SINGLE_VALUE, &self->ingress_counter); stats_unregister_counter(&egress_sc_key, SC_TYPE_SINGLE_VALUE, &self->egress_counter); } stats_unlock(); return TRUE; } static void _free(LogPipe *s) { MetricsPipe *self = (MetricsPipe *) s; g_free(self->log_path_name); log_pipe_free_method(s); } MetricsPipe * metrics_pipe_new(GlobalConfig *cfg, const gchar *log_path_name) { MetricsPipe *self = g_new0(MetricsPipe, 1); log_pipe_init_instance(&self->super, cfg); self->super.queue = _queue; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; self->log_path_name = g_strdup(log_path_name); log_pipe_add_info(&self->super, self->log_path_name); return self; } syslog-ng-syslog-ng-4.4.0/lib/metrics-pipe.h000066400000000000000000000023631450431004300206770ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #include "logpipe.h" typedef struct _MetricsPipe MetricsPipe; struct _MetricsPipe { LogPipe super; gchar *log_path_name; StatsCounterItem *ingress_counter; StatsCounterItem *egress_counter; }; MetricsPipe *metrics_pipe_new(GlobalConfig *cfg, const gchar *log_path_name); syslog-ng-syslog-ng-4.4.0/lib/misc.h000066400000000000000000000022051450431004300172240ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MISC_H_INCLUDED #define MISC_H_INCLUDED #include "syslog-ng.h" #include "gsockaddr.h" #include #include #endif syslog-ng-syslog-ng-4.4.0/lib/ml-batched-timer.c000066400000000000000000000124301450431004300214030ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ml-batched-timer.h" #include "mainloop-call.h" /* callback to be invoked when the timeout triggers */ static void ml_batched_timer_handle(MlBatchedTimer *self) { self->handler(self->cookie); } /* function called using main_loop_call() in case the suppress timer needs * to be updated. It is running in the main thread, thus is able to * reregister our ivykis timer */ static void ml_batched_timer_perform_update(MlBatchedTimer *self) { main_loop_assert_main_thread(); if (iv_timer_registered(&self->timer)) iv_timer_unregister(&self->timer); self->timer.expires = self->expires; if (self->timer.expires.tv_sec > 0) iv_timer_register(&self->timer); self->unref_cookie(self->cookie); } static inline gboolean ml_batched_timer_expiration_changed(MlBatchedTimer *self, struct timespec *next_expires) { return ((next_expires->tv_sec != self->expires.tv_sec) || (next_expires->tv_nsec != self->expires.tv_nsec)); } /* * Update the timer in a deferred manner, possibly batching the results of * multiple updates to the underlying ivykis timer. This is necessary as * suppress timer updates must run in the main thread, and updating it every * time a new message comes in would cause enormous latency in the fast * path. By collecting multiple updates the overhead is drastically * reduced. */ static void ml_batched_timer_update(MlBatchedTimer *self, struct timespec *next_expires) { /* NOTE: this check is racy as self->expires might be updated in a * different thread without holding a lock. * * When we lose the race, that means that another thread has already * updated the expires field, but we see the old value. In this case two * things may happen: * * 1) we skip an update because of the race * * We're going to skip the update if the other set the "expires" field to * the same value we intended to set it. This is not an issue, it doesn't * matter whether we or the other thread updates the timer. * * 2) we perform an update because of the race * * In this case, the other thread has updated the field, but we still * see the old value, thus we decide another update is due. We go * into the locked path, which will sort things out. * * In both cases we are fine. */ if (ml_batched_timer_expiration_changed(self, next_expires)) { g_mutex_lock(&self->lock); /* check if we've lost the race */ if (ml_batched_timer_expiration_changed(self, next_expires)) { /* we need to update the timer */ self->expires = *next_expires; self->ref_cookie(self->cookie); g_mutex_unlock(&self->lock); main_loop_call((MainLoopTaskFunc) ml_batched_timer_perform_update, self, FALSE); } else g_mutex_unlock(&self->lock); } } /* Update the expire time of this timer to the current time plus @sec. Can * be invoked from any threads. */ void ml_batched_timer_postpone(MlBatchedTimer *self, glong sec) { struct timespec next_expires; iv_validate_now(); /* we deliberately use nsec == 0 in order to increase the likelihood that * we target the same second, in case only a fraction of a second has * passed between two updates. */ next_expires.tv_nsec = 0; next_expires.tv_sec = iv_now.tv_sec + sec; ml_batched_timer_update(self, &next_expires); } /* cancel the timer for the time being. Can be invoked from any threads. */ void ml_batched_timer_cancel(MlBatchedTimer *self) { struct timespec next_expires; next_expires.tv_sec = 0; next_expires.tv_nsec = 0; ml_batched_timer_update(self, &next_expires); } /* unregister the underlying ivykis timer, can only be called from the main thread. */ void ml_batched_timer_unregister(MlBatchedTimer *self) { main_loop_assert_main_thread(); if (iv_timer_registered(&self->timer)) iv_timer_unregister(&self->timer); self->expires.tv_sec = 0; self->expires.tv_nsec = 0; } /* one-time initialization of the MlBatchedTimer structure */ void ml_batched_timer_init(MlBatchedTimer *self) { g_mutex_init(&self->lock); IV_TIMER_INIT(&self->timer); self->timer.cookie = self; self->timer.handler = (void (*)(void *)) ml_batched_timer_handle; } /* Free MlBatchedTimer state. */ void ml_batched_timer_free(MlBatchedTimer *self) { g_mutex_clear(&self->lock); } syslog-ng-syslog-ng-4.4.0/lib/ml-batched-timer.h000066400000000000000000000032151450431004300214110ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ML_BATCHED_TIMER_INCLUDED #define ML_BATCHED_TIMER_INCLUDED #include "mainloop.h" #include /* timer which only updates */ typedef struct _MlBatchedTimer { GMutex lock; struct iv_timer timer; struct timespec expires; gpointer cookie; void *(*ref_cookie)(gpointer self); void (*unref_cookie)(gpointer self); void (*handler)(gpointer self); } MlBatchedTimer; void ml_batched_timer_postpone(MlBatchedTimer *self, glong sec); void ml_batched_timer_cancel(MlBatchedTimer *self); void ml_batched_timer_unregister(MlBatchedTimer *self); void ml_batched_timer_init(MlBatchedTimer *self); void ml_batched_timer_free(MlBatchedTimer *self); #endif syslog-ng-syslog-ng-4.4.0/lib/module-config.c000066400000000000000000000025741450431004300210250ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "module-config.h" gboolean module_config_init(ModuleConfig *s, GlobalConfig *cfg) { if (s->init) return s->init(s, cfg); return TRUE; } void module_config_deinit(ModuleConfig *s, GlobalConfig *cfg) { if (s->deinit) s->deinit(s, cfg); } void module_config_free_method(ModuleConfig *s) { } void module_config_free(ModuleConfig *s) { if (s->free_fn) s->free_fn(s); g_free(s); } syslog-ng-syslog-ng-4.4.0/lib/module-config.h000066400000000000000000000035101450431004300210210ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULE_CONFIG_H_INCLUDED #define MODULE_CONFIG_H_INCLUDED 1 #include "syslog-ng.h" typedef struct _ModuleConfig ModuleConfig; /* This class encapsulates global (e.g. GlobalConfig) level settings for * modules. It can be used to store state that is not related to a specific * LogPipe instance. Such an example is the python block embedded in the * configuration used by the Python module. */ struct _ModuleConfig { /* init/deinit is hooked into configuration init/deinit */ gboolean (*init)(ModuleConfig *s, GlobalConfig *cfg); void (*deinit)(ModuleConfig *s, GlobalConfig *cfg); void (*free_fn)(ModuleConfig *s); }; gboolean module_config_init(ModuleConfig *s, GlobalConfig *cfg); void module_config_deinit(ModuleConfig *s, GlobalConfig *cfg); void module_config_free_method(ModuleConfig *s); void module_config_free(ModuleConfig *s); #endif syslog-ng-syslog-ng-4.4.0/lib/msg-format.c000066400000000000000000000237601450431004300203510ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "msg-format.h" #include "cfg.h" #include "plugin.h" #include "plugin-types.h" #include "find-crlf.h" #include "scratch-buffers.h" static gsize _rstripped_message_length(const guchar *data, gsize length) { while (length > 0 && (data[length - 1] == '\n' || data[length - 1] == '\0')) length--; return length; } static void msg_format_inject_parse_error(LogMessage *msg, const guchar *data, gsize length, gint problem_position) { GString *buf = scratch_buffers_alloc(); log_msg_clear(msg); msg->timestamps[LM_TS_STAMP] = msg->timestamps[LM_TS_RECVD]; log_msg_set_value(msg, LM_V_HOST, "", 0); if (problem_position > 0) g_string_printf(buf, "Error processing log message: %.*s>@<%.*s", (gint) problem_position-1, data, (gint) (length-problem_position+1), data+problem_position-1); else g_string_printf(buf, "Error processing log message: %.*s", (gint) length, data); log_msg_set_value(msg, LM_V_MESSAGE, buf->str, buf->len); log_msg_set_value(msg, LM_V_PROGRAM, "syslog-ng", 9); g_string_printf(buf, "%d", (int) getpid()); log_msg_set_value(msg, LM_V_PID, buf->str, buf->len); msg->flags |= LF_LOCAL; msg->pri = LOG_SYSLOG | LOG_ERR; } static void msg_format_preprocess_message(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length) { if (options->flags & LP_STORE_RAW_MESSAGE) { log_msg_set_value(msg, LOG_MSG_GET_VALUE_HANDLE_STATIC("RAWMSG"), (gchar *) data, _rstripped_message_length(data, length)); } } static void msg_format_postprocess_message(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length) { if (options->flags & LP_NO_PARSE_DATE) { msg->timestamps[LM_TS_STAMP] = msg->timestamps[LM_TS_RECVD]; unix_time_set_timezone(&msg->timestamps[LM_TS_STAMP], time_zone_info_get_offset(options->recv_time_zone_info, msg->timestamps[LM_TS_RECVD].ut_sec)); } if (G_UNLIKELY(options->flags & LP_NO_MULTI_LINE)) { gssize msg_len; gchar *msg_text; gchar *p; p = msg_text = (gchar *) log_msg_get_value(msg, LM_V_MESSAGE, &msg_len); while ((p = find_cr_or_lf_or_nul(p, msg_text + msg_len - p))) { *p = ' '; p++; } } if (options->flags & LP_LOCAL) msg->flags |= LF_LOCAL; if (options->flags & LP_ASSUME_UTF8) msg->flags |= LF_UTF8; } static gboolean msg_format_process_message(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length, gsize *problem_position) { if ((options->flags & LP_NOPARSE) == 0) { return options->format_handler->parse(options, msg, data, length, problem_position); } else { log_msg_set_value(msg, LM_V_MESSAGE, (gchar *) data, _rstripped_message_length(data, length)); msg->pri = options->default_pri; return TRUE; } } gboolean msg_format_try_parse_into(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length, gsize *problem_position) { if (G_UNLIKELY(!options->format_handler)) { gchar buf[256]; g_snprintf(buf, sizeof(buf), "Error parsing message, format module %s is not loaded", options->format); log_msg_set_value(msg, LM_V_MESSAGE, buf, -1); return FALSE; } msg_format_preprocess_message(options, msg, data, length); if (!msg_format_process_message(options, msg, data, length, problem_position)) return FALSE; msg_format_postprocess_message(options, msg, data, length); return TRUE; } void msg_format_parse_into(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length) { gsize problem_position = 0; if (!msg_format_try_parse_into(options, msg, data, length, &problem_position)) { msg_format_inject_parse_error(msg, data, _rstripped_message_length(data, length), problem_position); /* the injected error message needs to be postprocessed too */ msg_format_postprocess_message(options, msg, data, length); } } static gsize _determine_payload_size(MsgFormatOptions *parse_options, const guchar *data, gsize length) { gsize payload_size; if ((parse_options->flags & LP_STORE_RAW_MESSAGE)) payload_size = length * 4; else payload_size = length * 2; return MAX(payload_size, 256); } LogMessage * msg_format_construct_message(MsgFormatOptions *options, const guchar *data, gsize length) { LogMessage *msg = log_msg_sized_new(_determine_payload_size(options, data, length)); return msg; } LogMessage * msg_format_parse(MsgFormatOptions *options, const guchar *data, gsize length) { LogMessage *msg = msg_format_construct_message(options, data, length); msg_trace("Initial message parsing follows"); msg_format_parse_into(options, msg, data, length); return msg; } gboolean msg_format_options_set_sdata_prefix(MsgFormatOptions *options, const gchar *prefix) { if (prefix && strlen(prefix) > 128) return FALSE; g_free(options->sdata_prefix); options->sdata_prefix = g_strdup(prefix); return TRUE; } void msg_format_options_defaults(MsgFormatOptions *options) { options->flags = LP_EXPECT_HOSTNAME | LP_STORE_LEGACY_MSGHDR; options->recv_time_zone = NULL; options->recv_time_zone_info = NULL; options->bad_hostname = NULL; options->default_pri = 0xFFFF; options->sdata_param_value_max = 65535; options->sdata_prefix = NULL; options->sdata_prefix_len = 0; } /* NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy */ void msg_format_options_init(MsgFormatOptions *options, GlobalConfig *cfg) { Plugin *p; if (options->initialized) return; if (cfg->bad_hostname_compiled) options->bad_hostname = &cfg->bad_hostname; if (options->recv_time_zone == NULL) options->recv_time_zone = g_strdup(cfg->recv_time_zone); if (options->recv_time_zone_info == NULL) options->recv_time_zone_info = time_zone_info_new(options->recv_time_zone); if (!options->format) options->format = g_strdup("syslog"); p = cfg_find_plugin(cfg, LL_CONTEXT_FORMAT, options->format); if (p) options->format_handler = plugin_construct(p); if (!options->sdata_prefix) options->sdata_prefix = g_strdup(logmsg_sd_prefix); options->sdata_prefix_len = strlen(options->sdata_prefix); options->initialized = TRUE; } void msg_format_options_copy(MsgFormatOptions *options, const MsgFormatOptions *source) { g_assert(!options->initialized); options->format = g_strdup(source->format); options->flags = source->flags; options->default_pri = source->default_pri; options->recv_time_zone = g_strdup(source->recv_time_zone); options->sdata_param_value_max = source->sdata_param_value_max; options->sdata_prefix = g_strdup(source->sdata_prefix); } void msg_format_options_destroy(MsgFormatOptions *options) { if (options->format) { g_free(options->format); options->format = NULL; } if (options->recv_time_zone) { g_free(options->recv_time_zone); options->recv_time_zone = NULL; } if (options->recv_time_zone_info) { time_zone_info_free(options->recv_time_zone_info); options->recv_time_zone_info = NULL; } g_free(options->sdata_prefix); options->initialized = FALSE; } CfgFlagHandler msg_format_flag_handlers[] = { { "no-parse", CFH_SET, offsetof(MsgFormatOptions, flags), LP_NOPARSE }, { "check-hostname", CFH_SET, offsetof(MsgFormatOptions, flags), LP_CHECK_HOSTNAME }, { "syslog-protocol", CFH_SET, offsetof(MsgFormatOptions, flags), LP_SYSLOG_PROTOCOL }, { "assume-utf8", CFH_SET, offsetof(MsgFormatOptions, flags), LP_ASSUME_UTF8 }, { "validate-utf8", CFH_SET, offsetof(MsgFormatOptions, flags), LP_VALIDATE_UTF8 }, { "sanitize-utf8", CFH_SET, offsetof(MsgFormatOptions, flags), LP_SANITIZE_UTF8 }, { "no-multi-line", CFH_SET, offsetof(MsgFormatOptions, flags), LP_NO_MULTI_LINE }, { "store-legacy-msghdr", CFH_SET, offsetof(MsgFormatOptions, flags), LP_STORE_LEGACY_MSGHDR }, { "store-raw-message", CFH_SET, offsetof(MsgFormatOptions, flags), LP_STORE_RAW_MESSAGE }, { "dont-store-legacy-msghdr", CFH_CLEAR, offsetof(MsgFormatOptions, flags), LP_STORE_LEGACY_MSGHDR }, { "expect-hostname", CFH_SET, offsetof(MsgFormatOptions, flags), LP_EXPECT_HOSTNAME }, { "no-hostname", CFH_CLEAR, offsetof(MsgFormatOptions, flags), LP_EXPECT_HOSTNAME }, { "guess-timezone", CFH_SET, offsetof(MsgFormatOptions, flags), LP_GUESS_TIMEZONE }, { "no-header", CFH_SET, offsetof(MsgFormatOptions, flags), LP_NO_HEADER }, { "no-rfc3164-fallback", CFH_SET, offsetof(MsgFormatOptions, flags), LP_NO_RFC3164_FALLBACK }, { NULL }, }; gboolean msg_format_options_process_flag(MsgFormatOptions *options, const gchar *flag) { return cfg_process_flag(msg_format_flag_handlers, options, flag); } syslog-ng-syslog-ng-4.4.0/lib/msg-format.h000066400000000000000000000105311450431004300203460ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MSG_FORMAT_H_INCLUDED #define MSG_FORMAT_H_INCLUDED #include "syslog-ng.h" #include "timeutils/zoneinfo.h" #include "logproto/logproto-server.h" #include enum { /* don't parse the message, put everything into $MSG */ LP_NOPARSE = 0x0001, /* check if the hostname contains valid characters and assume it is part of the program field if it isn't */ LP_CHECK_HOSTNAME = 0x0002, /* message is using RFC5424 format */ LP_SYSLOG_PROTOCOL = 0x0004, /* the caller knows the message is valid UTF-8 */ LP_ASSUME_UTF8 = 0x0008, /* validate that all characters are indeed UTF-8 and mark the message as valid when relaying */ LP_VALIDATE_UTF8 = 0x0010, /* sanitize input and force it to be valid UTF-8 by escaping */ LP_SANITIZE_UTF8 = 0x0020, /* the message may not contain NL characters, strip them if it does */ LP_NO_MULTI_LINE = 0x0040, /* don't store MSGHDR in the LEGACY_MSGHDR macro */ LP_STORE_LEGACY_MSGHDR = 0x0080, /* expect a hostname field in the message */ LP_EXPECT_HOSTNAME = 0x0100, /* message is locally generated and should be marked with LF_LOCAL */ LP_LOCAL = 0x0200, /* for the date part of a message, only skip it, don't fully parse - recommended for keep_timestamp(no) */ LP_NO_PARSE_DATE = 0x0400, LP_STORE_RAW_MESSAGE = 0x0800, LP_GUESS_TIMEZONE = 0x1000, LP_NO_HEADER = 0x2000, LP_NO_RFC3164_FALLBACK = 0x4000, }; typedef struct _MsgFormatHandler MsgFormatHandler; typedef struct _MsgFormatOptions { gboolean initialized; gchar *format; MsgFormatHandler *format_handler; guint32 flags; guint16 default_pri; gchar *recv_time_zone; TimeZoneInfo *recv_time_zone_info; regex_t *bad_hostname; gchar *sdata_prefix; gsize sdata_prefix_len; gint sdata_param_value_max; } MsgFormatOptions; struct _MsgFormatHandler { /* this method has a chance to change the LogProto related options to * match the requirements of the "format" in question. This is used by * the "pacct" plugin to set the record length the proper size */ LogProtoServer *(*construct_proto)(const MsgFormatOptions *options, LogTransport *transport, const LogProtoServerOptions *proto_options); gboolean (*parse)(const MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length, gsize *problem_position); }; gboolean msg_format_try_parse_into(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length, gsize *problem_position); void msg_format_parse_into(MsgFormatOptions *options, LogMessage *msg, const guchar *data, gsize length); LogMessage *msg_format_construct_message(MsgFormatOptions *options, const guchar *data, gsize length); LogMessage *msg_format_parse(MsgFormatOptions *options, const guchar *data, gsize length); gboolean msg_format_options_set_sdata_prefix(MsgFormatOptions *options, const gchar *prefix); void msg_format_options_defaults(MsgFormatOptions *options); void msg_format_options_init(MsgFormatOptions *parse_options, GlobalConfig *cfg); void msg_format_options_destroy(MsgFormatOptions *parse_options); void msg_format_options_copy(MsgFormatOptions *options, const MsgFormatOptions *source); gboolean msg_format_options_process_flag(MsgFormatOptions *options, const gchar *flag); #endif syslog-ng-syslog-ng-4.4.0/lib/msg-stats.c000066400000000000000000000132041450431004300202070ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "msg-stats.h" #include "syslog-names.h" #include "logmsg/logmsg.h" #include "apphook.h" /* Static counters for severities and facilities */ /* LOG_DEBUG 0x7 */ #define SEVERITY_MAX (0x7 + 1) /* LOG_LOCAL7 23<<3, one additional slot for "everything-else" counter */ #define FACILITY_MAX (23 + 1 + 1) static StatsCounterItem *severity_counters[SEVERITY_MAX]; static StatsCounterItem *facility_counters[FACILITY_MAX]; static void _process_message_pri(guint16 pri) { int lpri = SYSLOG_FAC(pri); stats_counter_inc(severity_counters[SYSLOG_PRI(pri)]); if (lpri > (FACILITY_MAX - 1)) { /* the large facilities (=facility.other) are collected in the last array item */ lpri = FACILITY_MAX - 1; } stats_counter_inc(facility_counters[lpri]); } void msg_stats_update_counters(const gchar *source_id, const LogMessage *msg) { if (stats_syslog_stats() == CYNA_YES || (stats_syslog_stats() == CYNA_AUTO && stats_check_level(2))) { stats_lock(); StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_HOST | SCS_SOURCE, NULL, log_msg_get_value(msg, LM_V_HOST, NULL) ); stats_register_and_increment_dynamic_counter(0, &sc_key, msg->timestamps[LM_TS_RECVD].ut_sec); if (stats_syslog_stats() == CYNA_YES || (stats_syslog_stats() == CYNA_AUTO && stats_check_level(3))) { stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SENDER | SCS_SOURCE, NULL, log_msg_get_value(msg, LM_V_HOST_FROM, NULL) ); stats_register_and_increment_dynamic_counter(0, &sc_key, msg->timestamps[LM_TS_RECVD].ut_sec); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_PROGRAM | SCS_SOURCE, NULL, log_msg_get_value(msg, LM_V_PROGRAM, NULL) ); stats_register_and_increment_dynamic_counter(0, &sc_key, msg->timestamps[LM_TS_RECVD].ut_sec); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_HOST | SCS_SOURCE, source_id, log_msg_get_value(msg, LM_V_HOST, NULL)); stats_register_and_increment_dynamic_counter(0, &sc_key, msg->timestamps[LM_TS_RECVD].ut_sec); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SENDER | SCS_SOURCE, source_id, log_msg_get_value(msg, LM_V_HOST_FROM, NULL)); stats_register_and_increment_dynamic_counter(0, &sc_key, msg->timestamps[LM_TS_RECVD].ut_sec); } stats_unlock(); } _process_message_pri(msg->pri); } static void stats_syslog_reinit(void) { gchar name[11] = ""; gint i; StatsClusterKey sc_key; stats_lock(); if (stats_syslog_stats() == CYNA_YES || (stats_syslog_stats() == CYNA_AUTO && stats_check_level(3))) { /* we need these counters, register them */ for (i = 0; i < SEVERITY_MAX; i++) { g_snprintf(name, sizeof(name), "%d", i); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SEVERITY | SCS_SOURCE, NULL, name ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &severity_counters[i]); } for (i = 0; i < FACILITY_MAX - 1; i++) { g_snprintf(name, sizeof(name), "%d", i); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_FACILITY | SCS_SOURCE, NULL, name ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &facility_counters[i]); } stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_FACILITY | SCS_SOURCE, NULL, "other" ); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &facility_counters[FACILITY_MAX - 1]); } else { /* no need for facility/severity counters, unregister them */ for (i = 0; i < SEVERITY_MAX; i++) { g_snprintf(name, sizeof(name), "%d", i); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SEVERITY | SCS_SOURCE, NULL, name ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &severity_counters[i]); } for (i = 0; i < FACILITY_MAX - 1; i++) { g_snprintf(name, sizeof(name), "%d", i); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_FACILITY | SCS_SOURCE, NULL, name ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &facility_counters[i]); } stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_FACILITY | SCS_SOURCE, NULL, "other" ); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &facility_counters[FACILITY_MAX - 1]); } stats_unlock(); } void msg_stats_init(void) { register_application_hook(AH_CONFIG_CHANGED, (ApplicationHookFunc) stats_syslog_reinit, NULL, AHM_RUN_REPEAT); } void msg_stats_deinit(void) { } syslog-ng-syslog-ng-4.4.0/lib/msg-stats.h000066400000000000000000000023331450431004300202150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MSG_STATS_H_INCLUDED #define MSG_STATS_H_INCLUDED 1 #include "stats/stats-registry.h" void msg_stats_update_counters(const gchar *stats_id, const LogMessage *msg); void msg_stats_init(void); void msg_stats_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/000077500000000000000000000000001450431004300202005ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/multi-line/CMakeLists.txt000066400000000000000000000011311450431004300227340ustar00rootroot00000000000000set(MULTI_LINE_HEADERS multi-line/indented-multi-line.h multi-line/multi-line-factory.h multi-line/multi-line-logic.h multi-line/multi-line-pattern.h multi-line/smart-multi-line.h multi-line/regexp-multi-line.h PARENT_SCOPE) set(MULTI_LINE_SOURCES multi-line/indented-multi-line.c multi-line/multi-line-factory.c multi-line/multi-line-logic.c multi-line/multi-line-pattern.c multi-line/smart-multi-line.c multi-line/regexp-multi-line.c PARENT_SCOPE) install(FILES smart-multi-line.fsm DESTINATION share/syslog-ng) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/multi-line/Makefile.am000066400000000000000000000013451450431004300222370ustar00rootroot00000000000000multilineincludedir = ${pkgincludedir}/multi-line multilineinclude_HEADERS = \ lib/multi-line/multi-line-logic.h \ lib/multi-line/multi-line-factory.h \ lib/multi-line/indented-multi-line.h \ lib/multi-line/regexp-multi-line.h \ lib/multi-line/multi-line-pattern.h \ lib/multi-line/smart-multi-line.h multiline_sources = \ lib/multi-line/multi-line-logic.c \ lib/multi-line/multi-line-factory.c \ lib/multi-line/indented-multi-line.c \ lib/multi-line/regexp-multi-line.c \ lib/multi-line/multi-line-pattern.c \ lib/multi-line/smart-multi-line.c pkgdata_DATA = lib/multi-line/smart-multi-line.fsm EXTRA_DIST += lib/multi-line/CMakeLists.txt \ lib/multi-line/smart-multi-line.fsm include lib/multi-line/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/multi-line/indented-multi-line.c000066400000000000000000000040461450431004300242170ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Gergely Nagy * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "multi-line-logic.h" static inline gboolean _is_line_a_continuation_line(guchar first_char) { return (first_char == ' ' || first_char == '\t'); } static gint _accumulate_line(MultiLineLogic *s, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { /* let's check if the current line is a continuation line or not */ if (msg_len > 0 && segment_len > 0) { guchar first_character_of_the_current_line = *segment; if (_is_line_a_continuation_line(first_character_of_the_current_line)) { return MLL_CONSUME_SEGMENT | MLL_WAITING; } else { return MLL_REWIND_SEGMENT | MLL_EXTRACTED; } } return MLL_CONSUME_SEGMENT | MLL_WAITING; } MultiLineLogic * indented_multi_line_new(void) { MultiLineLogic *self = g_new0(MultiLineLogic, 1); multi_line_logic_init_instance(self); self->accumulate_line = _accumulate_line; return self; } syslog-ng-syslog-ng-4.4.0/lib/multi-line/indented-multi-line.h000066400000000000000000000023421450431004300242210ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Gergely Nagy * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef MULTI_LINE_INDENTED_MULTI_LINE_INCLUDED #define MULTI_LINE_INDENTED_MULTI_LINE_INCLUDED #include "multi-line-logic.h" MultiLineLogic *indented_multi_line_new(void); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-factory.c000066400000000000000000000112231450431004300240670ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "multi-line/multi-line-factory.h" #include "multi-line/regexp-multi-line.h" #include "multi-line/indented-multi-line.h" #include "multi-line/smart-multi-line.h" #include "messages.h" #include #include MultiLineLogic * multi_line_factory_construct(const MultiLineOptions *options) { switch (options->mode) { case MLM_INDENTED: return indented_multi_line_new(); case MLM_REGEXP_PREFIX_GARBAGE: return regexp_multi_line_new(RML_PREFIX_GARBAGE, options->regexp.prefix, options->regexp.garbage); case MLM_REGEXP_PREFIX_SUFFIX: return regexp_multi_line_new(RML_PREFIX_SUFFIX, options->regexp.prefix, options->regexp.garbage); case MLM_SMART: return smart_multi_line_new(); case MLM_NONE: return NULL; default: g_assert_not_reached(); break; } g_assert_not_reached(); } gboolean multi_line_options_set_mode(MultiLineOptions *options, const gchar *mode) { if (strcasecmp(mode, "indented") == 0) options->mode = MLM_INDENTED; else if (strcasecmp(mode, "regexp") == 0) options->mode = MLM_REGEXP_PREFIX_GARBAGE; else if (strcasecmp(mode, "prefix-garbage") == 0) options->mode = MLM_REGEXP_PREFIX_GARBAGE; else if (strcasecmp(mode, "prefix-suffix") == 0) options->mode = MLM_REGEXP_PREFIX_SUFFIX; else if (strcasecmp(mode, "smart") == 0) options->mode = MLM_SMART; else if (strcasecmp(mode, "none") == 0) options->mode = MLM_NONE; else return FALSE; return TRUE; } gboolean multi_line_options_set_prefix(MultiLineOptions *options, const gchar *prefix_regexp, GError **error) { multi_line_pattern_unref(options->regexp.prefix); options->regexp.prefix = multi_line_pattern_compile(prefix_regexp, error); return options->regexp.prefix != NULL; } gboolean multi_line_options_set_garbage(MultiLineOptions *options, const gchar *garbage_regexp, GError **error) { multi_line_pattern_unref(options->regexp.garbage); options->regexp.garbage = multi_line_pattern_compile(garbage_regexp, error); return options->regexp.garbage != NULL; } gboolean multi_line_options_validate(MultiLineOptions *options) { gboolean is_garbage_mode = options->mode == MLM_REGEXP_PREFIX_GARBAGE; gboolean is_suffix_mode = options->mode == MLM_REGEXP_PREFIX_SUFFIX; if ((!is_garbage_mode && !is_suffix_mode) && (options->regexp.prefix || options->regexp.garbage)) { msg_error("multi-line-prefix() and/or multi-line-garbage() specified but multi-line-mode() is not regexp based " "(prefix-garbage or prefix-suffix), please set multi-line-mode() properly"); return FALSE; } return TRUE; } void multi_line_options_defaults(MultiLineOptions *options) { memset(options, 0, sizeof(*options)); options->mode = MLM_NONE; } void multi_line_options_copy(MultiLineOptions *dest, MultiLineOptions *source) { dest->mode = source->mode; if (dest->mode == MLM_REGEXP_PREFIX_GARBAGE || dest->mode == MLM_REGEXP_PREFIX_SUFFIX) { dest->regexp.prefix = multi_line_pattern_ref(source->regexp.prefix); dest->regexp.garbage = multi_line_pattern_ref(source->regexp.garbage); } } gboolean multi_line_options_init(MultiLineOptions *options) { if (!multi_line_options_validate(options)) return FALSE; return TRUE; } void multi_line_options_destroy(MultiLineOptions *options) { multi_line_pattern_unref(options->regexp.prefix); multi_line_pattern_unref(options->regexp.garbage); } void multi_line_global_init(void) { smart_multi_line_global_init(); } void multi_line_global_deinit(void) { smart_multi_line_global_deinit(); } syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-factory.h000066400000000000000000000045161450431004300241030ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTI_LINE_MULTI_LINE_FACTORY_H_INCLUDED #define MULTI_LINE_MULTI_LINE_FACTORY_H_INCLUDED #include "multi-line/regexp-multi-line.h" enum { MLM_NONE, MLM_INDENTED, MLM_REGEXP_PREFIX_GARBAGE, MLM_REGEXP_PREFIX_SUFFIX, MLM_SMART, }; typedef struct _MultiLineOptions { gint mode; union { struct { MultiLinePattern *prefix; MultiLinePattern *garbage; } regexp; }; } MultiLineOptions; MultiLineLogic *multi_line_factory_construct(const MultiLineOptions *options); gboolean multi_line_options_set_mode(MultiLineOptions *options, const gchar *mode); gboolean multi_line_options_set_prefix(MultiLineOptions *options, const gchar *prefix_regexp, GError **error); gboolean multi_line_options_set_garbage(MultiLineOptions *options, const gchar *garbage_regexp, GError **error); gboolean multi_line_options_validate(MultiLineOptions *options); void multi_line_options_copy(MultiLineOptions *dest, MultiLineOptions *source); void multi_line_options_defaults(MultiLineOptions *options); gboolean multi_line_options_init(MultiLineOptions *options); void multi_line_options_destroy(MultiLineOptions *options); void multi_line_global_init(void); void multi_line_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-logic.c000066400000000000000000000024171450431004300235220ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "multi-line/multi-line-logic.h" void multi_line_logic_free_method(MultiLineLogic *s) { g_free(s); } void multi_line_logic_init_instance(MultiLineLogic *self) { self->free_fn = multi_line_logic_free_method; } syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-logic.h000066400000000000000000000072371450431004300235340ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTI_LINE_LOGIC_H_INCLUDED #define MULTI_LINE_LOGIC_H_INCLUDED #include "syslog-ng.h" enum { MLL_EXTRACTED = 0x0001, MLL_WAITING = 0x0002, MLL_CONSUME_SEGMENT = 0x0010, MLL_REWIND_SEGMENT = 0x0020, }; #define MLL_CONSUME_PARTIAL_AMOUNT_SHIFT 8 #define MLL_CONSUME_PARTIAL_AMOUNT_MASK ~0xFF #define MLL_CONSUME_PARTIALLY(drop_length) (MLL_CONSUME_SEGMENT | ((drop_length) << MLL_CONSUME_PARTIAL_AMOUNT_SHIFT)) typedef struct _MultiLineLogic MultiLineLogic; struct _MultiLineLogic { gint (*accumulate_line)(MultiLineLogic *self, const guchar *consumed, gsize consumed_len, const guchar *segment, gsize segment_len); void (*free_fn)(MultiLineLogic *s); }; void multi_line_logic_init_instance(MultiLineLogic *self); void multi_line_logic_free_method(MultiLineLogic *s); /* * multi_line_logic_accumulate_line(): * * Accumulate a multi-line message into an internal buffer. * consumed * points to the buffer containing our consumed data so far * * consumed_len * The number of bytes in @consumed * * segment * new data to be considered part of consumed * * segment_len * The number of bytes in @segment * * The accumulator should return a set of bitfields that indicate what to do * with the data presented: * * What we want to do with the new data * MLL_CONSUME_SEGMENT -- add the new segment to data consumed * MLL_CONSUME_PARTIALLY(n) -- add the new segment to the data consumed, * but dropping (n) characters from the end * MLL_REWIND_SEGMENT -- the new data is NOT part of the consumed * data so far, and should be considered * part of the next line. * * What we want to perform once the accumulation is finished: * MLL_EXTRACTED -- the accumulation is finished, return the * consumed data as a complete line for higher * layers. * MLL_WAITING -- we still need more data * */ static inline gint multi_line_logic_accumulate_line(MultiLineLogic *self, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { return self->accumulate_line(self, msg, msg_len, segment, segment_len); } static inline void multi_line_logic_free(MultiLineLogic *self) { self->free_fn(self); } #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-pattern.c000066400000000000000000000100451450431004300240760ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "multi-line/multi-line-pattern.h" #include "messages.h" MultiLinePattern * multi_line_pattern_compile(const gchar *regexp, GError **error) { MultiLinePattern *self = g_new0(MultiLinePattern, 1); gint rc; PCRE2_SIZE erroffset; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); self->ref_cnt = 1; /* compile the regexp */ self->pattern = pcre2_compile((PCRE2_SPTR) regexp, PCRE2_ZERO_TERMINATED, 0, &rc, &erroffset, NULL); if (!self->pattern) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); g_set_error(error, 0, 0, "Error while compiling multi-line regexp as a PCRE expression, error=%s, error_at=%" G_GSIZE_FORMAT, (gchar *) error_message, erroffset); goto error; } /* optimize regexp */ rc = pcre2_jit_compile(self->pattern, PCRE2_JIT_COMPLETE); if (rc < 0) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); msg_warning("multi-line-pattern: Error while JIT compiling regular expression", evt_tag_str("regexp", regexp), evt_tag_str("error", (gchar *) error_message)); } return self; error: if (self->pattern) pcre2_code_free(self->pattern); g_free(self); return NULL; } gint multi_line_pattern_eval(MultiLinePattern *re, const guchar *str, gsize len, pcre2_match_data *match_data) { return pcre2_match(re->pattern, (PCRE2_SPTR) str, (PCRE2_SIZE) len, 0, 0, match_data, NULL); } gboolean multi_line_pattern_find(MultiLinePattern *re, const guchar *str, gsize len, gint *start, gint *end) { if (!re) return FALSE; gboolean result = FALSE; pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re->pattern, NULL); if (multi_line_pattern_eval(re, str, len, match_data) < 0) goto exit; guint32 num_matches = pcre2_get_ovector_count(match_data); PCRE2_SIZE *matches = pcre2_get_ovector_pointer(match_data); if (num_matches == 0) goto exit; *start = matches[0]; *end = matches[1]; result = TRUE; exit: pcre2_match_data_free(match_data); return result; } gboolean multi_line_pattern_match(MultiLinePattern *re, const guchar *str, gsize len) { if (!re) return FALSE; gboolean result = FALSE; pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re->pattern, NULL); if (multi_line_pattern_eval(re, str, len, match_data) < 0) goto exit; guint32 num_matches = pcre2_get_ovector_count(match_data); PCRE2_SIZE *matches = pcre2_get_ovector_pointer(match_data); result = num_matches > 0 && matches[0] >= 0; exit: pcre2_match_data_free(match_data); return result; } MultiLinePattern * multi_line_pattern_ref(MultiLinePattern *self) { if (self) self->ref_cnt++; return self; } void multi_line_pattern_unref(MultiLinePattern *self) { if (self && (--self->ref_cnt == 0)) { if (self->pattern) pcre2_code_free(self->pattern); g_free(self); } } syslog-ng-syslog-ng-4.4.0/lib/multi-line/multi-line-pattern.h000066400000000000000000000033261450431004300241070ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTI_LINE_MULTI_LINE_PATTERN_H_INCLUDED #define MULTI_LINE_MULTI_LINE_PATTERN_H_INCLUDED #include "syslog-ng.h" #include "compat/pcre.h" typedef struct _MultiLinePattern MultiLinePattern; struct _MultiLinePattern { gint ref_cnt; pcre2_code *pattern; }; gboolean multi_line_pattern_find(MultiLinePattern *re, const guchar *str, gsize len, gint *start, gint *end); gboolean multi_line_pattern_match(MultiLinePattern *re, const guchar *str, gsize len); MultiLinePattern *multi_line_pattern_compile(const gchar *regexp, GError **error); MultiLinePattern *multi_line_pattern_ref(MultiLinePattern *self); void multi_line_pattern_unref(MultiLinePattern *self); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/regexp-multi-line.c000066400000000000000000000076561450431004300237310ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "regexp-multi-line.h" static gint _prefix_garbage_get_offset_of_garbage(RegexpMultiLine *self, const guchar *line, gsize line_len) { gint start, end; if (!multi_line_pattern_find(self->garbage, line, line_len, &start, &end)) return -1; return start; } static gint _prefix_suffix_get_offset_of_garbage(RegexpMultiLine *self, const guchar *line, gsize line_len) { gint start, end; if (!multi_line_pattern_find(self->garbage, line, line_len, &start, &end)) return -1; return end; } static gint _get_offset_of_garbage(RegexpMultiLine *self, const guchar *line, gsize line_len) { if (self->mode == RML_PREFIX_GARBAGE) return _prefix_garbage_get_offset_of_garbage(self, line, line_len); else return _prefix_suffix_get_offset_of_garbage(self, line, line_len); } static gint _accumulate_initial_line(RegexpMultiLine *self, const guchar *line, gsize line_len) { gint offset_of_garbage = _get_offset_of_garbage(self, line, line_len); if (offset_of_garbage >= 0) return MLL_CONSUME_PARTIALLY(line_len - offset_of_garbage) | MLL_EXTRACTED; else return MLL_CONSUME_SEGMENT | MLL_WAITING; } static gint _accumulate_continuation_line(RegexpMultiLine *self, const guchar *line, gsize line_len) { gint offset_of_garbage = _get_offset_of_garbage(self, line, line_len); if (offset_of_garbage >= 0) return MLL_CONSUME_PARTIALLY(line_len - offset_of_garbage) | MLL_EXTRACTED; else if (multi_line_pattern_match(self->prefix, line, line_len)) return MLL_REWIND_SEGMENT | MLL_EXTRACTED; else return MLL_CONSUME_SEGMENT | MLL_WAITING; } static gint regexp_multi_line_accumulate_line(MultiLineLogic *s, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { RegexpMultiLine *self = (RegexpMultiLine *) s; if (msg_len == 0) { return _accumulate_initial_line(self, segment, segment_len); } else { return _accumulate_continuation_line(self, segment, segment_len); } } static void regexp_multi_line_free(MultiLineLogic *s) { RegexpMultiLine *self = (RegexpMultiLine *) s; multi_line_pattern_unref(self->prefix); multi_line_pattern_unref(self->garbage); multi_line_logic_free_method(s); } MultiLineLogic * regexp_multi_line_new(gint mode, MultiLinePattern *prefix, MultiLinePattern *garbage_or_suffix) { RegexpMultiLine *self = g_new0(RegexpMultiLine, 1); multi_line_logic_init_instance(&self->super); self->super.accumulate_line = regexp_multi_line_accumulate_line; self->super.free_fn = regexp_multi_line_free; self->mode = mode; self->prefix = multi_line_pattern_ref(prefix); self->garbage = multi_line_pattern_ref(garbage_or_suffix); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/multi-line/regexp-multi-line.h000066400000000000000000000030521450431004300237200ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balazs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTI_LINE_REGEXP_MULTI_LINE_H_INCLUDED #define MULTI_LINE_REGEXP_MULTI_LINE_H_INCLUDED #include "multi-line/multi-line-logic.h" #include "multi-line/multi-line-pattern.h" typedef struct _RegexpMultiLine { MultiLineLogic super; enum { RML_PREFIX_GARBAGE, RML_PREFIX_SUFFIX, } mode; MultiLinePattern *prefix; MultiLinePattern *garbage; } RegexpMultiLine; MultiLineLogic *regexp_multi_line_new(gint mode, MultiLinePattern *prefix, MultiLinePattern *garbage_or_suffix); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/smart-multi-line.c000066400000000000000000000325561450431004300235620ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "smart-multi-line.h" #include "regexp-multi-line.h" #include "reloc.h" #include "messages.h" #include #include #include enum { SMLS_NONE, SMLS_START_STATE, }; typedef struct _SmartMultiLineRule SmartMultiLineRule; struct _SmartMultiLineRule { gint from_states[4]; gchar *regexp; gint to_state; MultiLinePattern *compiled_regexp; }; typedef struct _SmartMultiLine { MultiLineLogic super; GMutex lock; gint current_state; gboolean last_segment_rewound; gboolean rewound_segment_is_trace; gboolean consumed_message_is_trace; } SmartMultiLine; GHashTable *state_map; gint last_state_id = SMLS_START_STATE; GArray *rules; GPtrArray *rules_by_from_state[64]; static void _reshuffle_rules_by_from_state(void) { for (gint rule_ndx = 0; rule_ndx < rules->len; rule_ndx++) { SmartMultiLineRule *rule = &g_array_index(rules, SmartMultiLineRule, rule_ndx); rule->compiled_regexp = multi_line_pattern_compile(rule->regexp, NULL); g_assert(rule->compiled_regexp != NULL); for (gint i = 0; rule->from_states[i]; i++) { g_assert(i < G_N_ELEMENTS(rule->from_states)); gint from_state = rule->from_states[i]; if (rules_by_from_state[from_state] == NULL) rules_by_from_state[from_state] = g_ptr_array_new(); g_ptr_array_add(rules_by_from_state[from_state], rule); } } } static gint _map_state(const gchar *state) { if (!state_map) { state_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_insert(state_map, g_strdup("start_state"), GINT_TO_POINTER(SMLS_START_STATE)); } gpointer value = g_hash_table_lookup(state_map, state); if (value) return GPOINTER_TO_INT(value); if (last_state_id >= G_N_ELEMENTS(rules_by_from_state)) { msg_error("smart-multi-line: too many states used in smart-multi-line.fsm, running with a partial a rule-set", evt_tag_int("fsm-max-state", G_N_ELEMENTS(rules_by_from_state)), evt_tag_str("state", state)); return 0; } last_state_id++; g_hash_table_insert(state_map, g_strdup(state), GINT_TO_POINTER(last_state_id)); return last_state_id; } static gchar * _extract_regexp(const gchar *regexp) { gint len = strlen(regexp); if (regexp[0] == regexp[len - 1]) return g_strndup(®exp[1], len - 2); return g_strdup(regexp); } static void _parse_rule(const gchar *from_states, const gchar *regexp, const gchar *to_state) { SmartMultiLineRule new_rule = {0}; gchar **from_state_list = g_strsplit(from_states, ",", -1); /* leave one slot for a terminating element */ for (gint i = 0; from_state_list[i] && i < G_N_ELEMENTS(new_rule.from_states) - 1; i++) new_rule.from_states[i] = _map_state(from_state_list[i]); new_rule.regexp = _extract_regexp(regexp); new_rule.to_state = _map_state(to_state); g_strfreev(from_state_list); g_array_append_val(rules, new_rule); } static void _read_rules(const gchar *filename, FILE *sml_file) { gchar line[1024]; gint lineno = 0; while (fgets(line, sizeof(line), sml_file)) { lineno++; gint len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = 0; len--; } if (len == 0 || line[0] == '#') continue; gchar **parts = g_strsplit(line, "\t", 3); if (g_strv_length(parts) != 3) { msg_error("smart-multi-line: error parsing line in pattern file, lines need to be in the form \t\t", evt_tag_str("filename", filename), evt_tag_int("lineno", lineno)); continue; } gchar *from_states = parts[0]; gchar *regexp = parts[1]; gchar *to_state = parts[2]; msg_trace("smart-multi-line: processing pattern", evt_tag_str("from_states", from_states), evt_tag_str("regexp", regexp), evt_tag_str("to_state", to_state)); _parse_rule(from_states, regexp, to_state); g_strfreev(parts); } } static void _load_tsv_file(const gchar *sml_file_name) { FILE *sml_file = fopen(sml_file_name, "r"); if (!sml_file) { msg_error("smart-multi-line: error opening smart-multi-line.fsm file", evt_tag_str("filename", sml_file_name), evt_tag_error("error")); return; } _read_rules(sml_file_name, sml_file); fclose(sml_file); } static void _load_rules(const gchar *sml_file_name) { if (rules) return; rules = g_array_new(FALSE, TRUE, sizeof(SmartMultiLineRule)); _load_tsv_file(sml_file_name); _reshuffle_rules_by_from_state(); if (state_map) { g_hash_table_unref(state_map); state_map = NULL; } if (rules_by_from_state[SMLS_START_STATE] == NULL) { msg_warning("smart-multi-line: your smart-multi-line.fsm seems to be empty or non-existent, " "automatic multi-line log extraction will probably not work", evt_tag_str("filename", sml_file_name)); } } static void _free_rules(void) { for (gint state_ndx = 0; state_ndx < G_N_ELEMENTS(rules_by_from_state); state_ndx++) { if (rules_by_from_state[state_ndx]) { g_ptr_array_free(rules_by_from_state[state_ndx], TRUE); rules_by_from_state[state_ndx] = NULL; } } for (gint rule_ndx = 0; rule_ndx < rules->len; rule_ndx++) { SmartMultiLineRule *rule = &g_array_index(rules, SmartMultiLineRule, rule_ndx); multi_line_pattern_unref(rule->compiled_regexp); g_free(rule->regexp); } g_array_free(rules, TRUE); rules = NULL; } gboolean _fsm_transition(SmartMultiLine *self, const gchar *segment, gsize segment_len) { GPtrArray *applicable_rules = rules_by_from_state[self->current_state]; for (gint i = 0; applicable_rules && i < applicable_rules->len; i++) { SmartMultiLineRule *rule = g_ptr_array_index(applicable_rules, i); gboolean match = multi_line_pattern_match(rule->compiled_regexp, (const guchar *) segment, segment_len); msg_trace_printf("smart-multi-line: Matching against pattern: %s in state %d, matched %d", rule->regexp, self->current_state, match); if (match) { self->current_state = rule->to_state; /* the current segment is part of a sequence */ return TRUE; } } self->current_state = SMLS_START_STATE; return FALSE; } void _process_segment(SmartMultiLine *self, const gchar *segment, gsize segment_len, gboolean *segment_is_part_of_trace, gboolean *segment_starts_a_new_trace, gboolean *segment_ends_trace) { *segment_is_part_of_trace = FALSE; *segment_starts_a_new_trace = FALSE; *segment_ends_trace = FALSE; gboolean last_segment_ended_the_trace = self->current_state == SMLS_START_STATE; gboolean segment_is_trace = _fsm_transition(self, segment, segment_len); msg_trace_printf("smart-multi-line: [STEP1] >>%.*s<<, result=%d, state=%d", (int) segment_len, segment, segment_is_trace, self->current_state); *segment_is_part_of_trace = segment_is_trace; if (!(*segment_is_part_of_trace)) { /* try again from the start state, the current segment is may be part of a new trace */ segment_is_trace = _fsm_transition(self, segment, segment_len); msg_trace_printf("smart-multi-line: [STEP2]: >>%.*s<<, result=%d, state=%d", (int) segment_len, segment, segment_is_trace, self->current_state); *segment_is_part_of_trace = segment_is_trace; if (*segment_is_part_of_trace) *segment_starts_a_new_trace = TRUE; } else { if (last_segment_ended_the_trace) *segment_starts_a_new_trace = TRUE; *segment_ends_trace = (self->current_state == SMLS_START_STATE); } } static gint _accumulate_line_unlocked(MultiLineLogic *s, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { SmartMultiLine *self = (SmartMultiLine *) s; if (self->last_segment_rewound) { /* we rewound the last segment, processing it again. The previous * message was extracted we are starting with a fresh start, but we * don't run the current segment through the FSM, we simply reuse the * result the last time we've run it. */ g_assert(msg_len == 0); self->last_segment_rewound = FALSE; if (self->rewound_segment_is_trace) { self->consumed_message_is_trace = TRUE; return MLL_CONSUME_SEGMENT | MLL_WAITING; } else { self->consumed_message_is_trace = FALSE; return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } } else { gboolean segment_is_part_of_trace, segment_starts_a_new_trace, segment_ends_trace; _process_segment(self, (const gchar *) segment, segment_len, &segment_is_part_of_trace, &segment_starts_a_new_trace, &segment_ends_trace); if (msg_len == 0) { /* just starting up, first segment is to be consumed */ if (!segment_is_part_of_trace) { /* not recognized as part of a trace, just return it */ self->consumed_message_is_trace = FALSE; return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } /* first line of the trace, remember that we are within a trace * and let's wait for more */ self->consumed_message_is_trace = TRUE; return MLL_CONSUME_SEGMENT | MLL_WAITING; } else { /* we already have data in @msg, so processing subsequent lines */ if (self->consumed_message_is_trace && segment_is_part_of_trace) { /* ok, @msg is a trace and the new segment as well. */ if (segment_starts_a_new_trace) { /* the new segment is not actually part of the consumed * @msg, it starts a new trace */ self->last_segment_rewound = TRUE; self->rewound_segment_is_trace = TRUE; return MLL_REWIND_SEGMENT | MLL_EXTRACTED; } else if (segment_ends_trace) { /* the new segment is trace, and is the last part of @msg */ return MLL_CONSUME_SEGMENT | MLL_EXTRACTED; } else { /* the new segment is a trace and is part of the partially * consumed @msg */ return MLL_CONSUME_SEGMENT | MLL_WAITING; } } else if (self->consumed_message_is_trace && !segment_is_part_of_trace) { /* ok, we have a consumed trace message in @msg and the new * segment is not part of that. */ self->last_segment_rewound = TRUE; self->rewound_segment_is_trace = FALSE; self->consumed_message_is_trace = FALSE; return MLL_REWIND_SEGMENT | MLL_EXTRACTED; } else { /* we can only be here with consumed_message_is_trace == TRUE */ g_assert_not_reached(); } } } g_assert_not_reached(); } static gint _accumulate_line(MultiLineLogic *s, const guchar *msg, gsize msg_len, const guchar *segment, gsize segment_len) { SmartMultiLine *self = (SmartMultiLine *) s; g_mutex_lock(&self->lock); gint result = _accumulate_line_unlocked(s, msg, msg_len, segment, segment_len); g_mutex_unlock(&self->lock); return result; } static void _free(MultiLineLogic *s) { SmartMultiLine *self = (SmartMultiLine *) s; g_mutex_clear(&self->lock); multi_line_logic_free_method(s); } MultiLineLogic * smart_multi_line_new(void) { SmartMultiLine *self = g_new0(SmartMultiLine, 1); multi_line_logic_init_instance(&self->super); self->super.free_fn = _free; self->super.accumulate_line = _accumulate_line; self->last_segment_rewound = FALSE; self->current_state = SMLS_START_STATE; g_mutex_init(&self->lock); return &self->super; } void smart_multi_line_global_init(void) { const gchar *sml_file_name = get_installation_path_for("${pkgdatadir}/smart-multi-line.fsm"); _load_rules(sml_file_name); } void smart_multi_line_global_deinit(void) { _free_rules(); } syslog-ng-syslog-ng-4.4.0/lib/multi-line/smart-multi-line.fsm000066400000000000000000000071461450431004300241220ustar00rootroot00000000000000# # Copyright 2023 Balazs Scheidler # Copyright 2016 Google Inc. All rights reserved. # # 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. # # The regular expressions were extracted from # https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions # and converted into a TSV format by Balazs Scheidler. # # List of tab separated fields # # comma-separated-states /regexp/ new_state # # java start_state,java_start_exception /(?:Exception|Error|Throwable|V8 errors stack trace)[:\r\n]/ java_after_exception java_after_exception /^[\t ]*nested exception is:[\t ]*/ java_start_exception java_after_exception /^[\r\n]*$/ java_after_exception java_after_exception,java /^[\t ]+(?:eval )?at / java java_after_exception,java /^[\t ]+--- End of inner exception stack trace ---$/ java java_after_exception,java /^--- End of stack trace from previous location where exception was thrown ---$/ java java_after_exception,java /^[\t ]*(?:Caused by|Suppressed):/ java_after_exception java_after_exception,java /^[\t ]*... \d+ (?:more|common frames omitted)/ java # python start_state /^Traceback \(most recent call last\):$/ python python /^[\t ]*File / python_code python_code /[^\t ]/ python python /^(?:[^\s.():]+\.)*[^\s.():]+:/ start_state # PHP start_state /(?:PHP\ (?:Notice|Parse\ error|Fatal\ error|Warning):)|(?:exception\ '[^']+'\ with\ message\ ')/ php_stack_begin php_stack_begin /^Stack trace:/ php_stack_frames php_stack_frames /^#\d/ php_stack_frames php_stack_frames /^\s+thrown in / start_state # Go start_state /\bpanic: / go_after_panic start_state /http: panic serving/ go_goroutine go_after_panic,go_after_signal,go_frame_1 /^$/ go_goroutine go_after_panic /^\[signal / go_after_signal go_goroutine /^goroutine \d+ \[[^\]]+\]:$/ go_frame_1 go_frame_1 /^(?:[^\s.:]+\.)*[^\s.():]+\(|^created by / go_frame_2 go_frame_2 /^\s/ go_frame_1 # Ruby start_state /Error \(.*\):$/ ruby_before_rails_trace ruby_before_rails_trace /^ $/ ruby ruby_before_rails_trace /^[\t ]+.*?\.rb:\d+:in `/ ruby ruby /^[\t ]+.*?\.rb:\d+:in `/ ruby # Dart start_state /^Unhandled exception:$/ dart_exc dart_exc /^(Instance of)|(Exception)|(Bad state)|(IntegerDivisionByZeroException)|(Invalid argument)|(RangeError)|(Assertion failed)|(Cannot instantiate)|(Reading static variable)|(UnimplementedError)|(Unsupported operation)|(Concurrent modification)|(Out of Memory)|(Stack Overflow)/ dart_stack dart_exc /^'.+?':.+?$/ dart_type_err_1 dart_type_err_1 /^#\d+\s+.+?\(.+?\)$/ dart_stack dart_type_err_1 /^.+?$/ dart_type_err_2 dart_type_err_2 /^.*?\^.*?$/ dart_type_err_3 dart_type_err_3 /^$/ dart_type_err_4 dart_type_err_4 /^$/ dart_stack dart_exc /^FormatException/ dart_format_err_1 dart_format_err_1 /^#\d+\s+.+?\(.+?\)$/ dart_stack dart_format_err_1 /^./ dart_format_err_2 dart_format_err_2 /^.*?\^/ dart_format_err_3 dart_format_err_3 /^$/ dart_stack dart_exc /^NoSuchMethodError:/ dart_method_err_1 dart_method_err_1 /^Receiver:/ dart_method_err_2 dart_method_err_2 /^Tried calling:/ dart_method_err_3 dart_method_err_3 /^Found:/ dart_stack dart_method_err_3 /^#\d+\s+.+?\(.+?\)$/ dart_stack dart_stack /^#\d+\s+.+?\(.+?\)$/ dart_stack dart_stack /^$/ dart_stack syslog-ng-syslog-ng-4.4.0/lib/multi-line/smart-multi-line.h000066400000000000000000000023521450431004300235560ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTI_LINE_SMART_MULTI_LINE_H_INCLUDED #define MULTI_LINE_SMART_MULTI_LINE_H_INCLUDED #include "multi-line/multi-line-logic.h" MultiLineLogic *smart_multi_line_new(void); void smart_multi_line_global_init(void); void smart_multi_line_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/multi-line/tests/000077500000000000000000000000001450431004300213425ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/multi-line/tests/CMakeLists.txt000066400000000000000000000000761450431004300241050ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_smart_multi_line) syslog-ng-syslog-ng-4.4.0/lib/multi-line/tests/Makefile.am000066400000000000000000000004661450431004300234040ustar00rootroot00000000000000lib_multi_line_tests_TESTS = \ lib/multi-line/tests/test_smart_multi_line EXTRA_DIST += lib/multi-line/tests/CMakeLists.txt check_PROGRAMS += ${lib_multi_line_tests_TESTS} lib_multi_line_tests_test_smart_multi_line_CFLAGS = $(TEST_CFLAGS) lib_multi_line_tests_test_smart_multi_line_LDADD = $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/multi-line/tests/test_smart_multi_line.c000066400000000000000000001065161450431004300261250ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include #include "multi-line/smart-multi-line.h" #include "scratch-buffers.h" #include "apphook.h" #include "cfg.h" #include "reloc.h" Test(smart_multi_line, three_unrelated_lines_that_are_not_backtraces) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *first_line = "this is an initial line that is consumed"; const gchar *second_line = "another line that is not part of a traceback"; const gchar *third_line = "yet another line that is not part of a traceback"; const gchar *fourth_line = "yet-yet another line that is not part of a traceback"; gint verdict = multi_line_logic_accumulate_line(mll, NULL, 0, (const guchar *) first_line, strlen(first_line)); cr_assert(verdict & MLL_CONSUME_SEGMENT); cr_assert(verdict & MLL_EXTRACTED); verdict = multi_line_logic_accumulate_line(mll, NULL, 0, (const guchar *) second_line, strlen(second_line)); cr_assert(verdict & MLL_CONSUME_SEGMENT); cr_assert(verdict & MLL_EXTRACTED); verdict = multi_line_logic_accumulate_line(mll, NULL, 0, (const guchar *) second_line, strlen(second_line)); cr_assert(verdict & MLL_CONSUME_SEGMENT); cr_assert(verdict & MLL_EXTRACTED); verdict = multi_line_logic_accumulate_line(mll, NULL, 0, (const guchar *) third_line, strlen(third_line)); cr_assert(verdict & MLL_CONSUME_SEGMENT); cr_assert(verdict & MLL_EXTRACTED); verdict = multi_line_logic_accumulate_line(mll, NULL, 0, (const guchar *) fourth_line, strlen(fourth_line)); cr_assert(verdict & MLL_CONSUME_SEGMENT); cr_assert(verdict & MLL_EXTRACTED); multi_line_logic_free(mll); } GString *buffer; GPtrArray *output_messages; static void _feed_line(MultiLineLogic *mll, const gchar *input, gssize input_len) { gboolean repeat; if (input_len < 0) input_len = strlen(input); do { gint verdict = multi_line_logic_accumulate_line(mll, (const guchar *) buffer->str, buffer->len, (const guchar *) input, input_len); repeat = FALSE; if (verdict & MLL_CONSUME_SEGMENT) { gint drop_length = (verdict & MLL_CONSUME_PARTIAL_AMOUNT_MASK) >> MLL_CONSUME_PARTIAL_AMOUNT_SHIFT; cr_assert(drop_length == 0); if (buffer->len > 0) g_string_append_c(buffer, '\n'); g_string_append_len(buffer, input, input_len); if (verdict & MLL_EXTRACTED) { g_ptr_array_add(output_messages, g_strdup(buffer->str)); g_string_truncate(buffer, 0); } else if (verdict & MLL_WAITING) ; else g_assert_not_reached(); } else if (verdict & MLL_REWIND_SEGMENT) { if (verdict & MLL_EXTRACTED) { g_ptr_array_add(output_messages, g_strdup(buffer->str)); g_string_truncate(buffer, 0); repeat = TRUE; } else if (verdict & MLL_WAITING) { repeat = TRUE; } } } while (repeat); } static void _feed_lines(MultiLineLogic *mll, const gchar *messages[]) { for (gint i = 0; messages[i]; i++) { _feed_line(mll, messages[i], strlen(messages[i])); } _feed_line(mll, "ENDOFTEST", -1); } static const gchar * _output_value(gint ndx) { if (output_messages->len <= ndx) return ""; const gchar *str = g_ptr_array_index(output_messages, ndx); return str; } static gboolean _output_equals(gint ndx, const gchar *expected_value) { if (output_messages->len <= ndx) return FALSE; const gchar *str = g_ptr_array_index(output_messages, ndx); return strcmp(str, expected_value) == 0; } Test(smart_multi_line, feed_smart_multi_line_with_single_and_multi_line_messages) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "this is something unrelated", "again something unrelated", "yet again something unrelated, but 3 tracebacks are COMING", "Traceback (most recent call last):", "File \"./lib/merge-grammar.py\", line 62, in ", " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):", "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__", " line = self._readline()", "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline", " return self._readline()", "Traceback (most recent call last):", "File \"./lib/merge-grammar2.py\", line 62, in ", " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):", "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__", " line = self._readline()", "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline", " return self._readline()", "Traceback (most recent call last):", "File \"./lib/merge-grammar3.py\", line 62, in ", " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):", "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__", " line = self._readline()", "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline", " return self._readline()", "unrelated line here", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "this is something unrelated")); cr_assert(_output_equals(1, "again something unrelated")); cr_assert(_output_equals(2, "yet again something unrelated, but 3 tracebacks are COMING")); cr_assert(_output_equals(3, "Traceback (most recent call last):\n" "File \"./lib/merge-grammar.py\", line 62, in \n" " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):\n" "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__\n" " line = self._readline()\n" "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline\n" " return self._readline()"), "unexpected_value %s", _output_value(3)); cr_assert(_output_equals(4, "Traceback (most recent call last):\n" "File \"./lib/merge-grammar2.py\", line 62, in \n" " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):\n" "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__\n" " line = self._readline()\n" "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline\n" " return self._readline()"), "unexpected_value %s", _output_value(4)); cr_assert(_output_equals(5, "Traceback (most recent call last):\n" "File \"./lib/merge-grammar3.py\", line 62, in \n" " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):\n" "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__\n" " line = self._readline()\n" "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline\n" " return self._readline()"), "unexpected_value %s", _output_value(5)); cr_assert(_output_equals(6, "unrelated line here")); multi_line_logic_free(mll); } Test(smart_multi_line, test_python_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "Traceback (most recent call last):", "File \"./lib/merge-grammar.py\", line 62, in ", " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):", "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__", " line = self._readline()", "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline", " return self._readline()", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "Traceback (most recent call last):\n" "File \"./lib/merge-grammar.py\", line 62, in \n" " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):\n" "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__\n" " line = self._readline()\n" "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline\n" " return self._readline()"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } Test(smart_multi_line, test_python_backtrace_with_tailing_exception_text) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "Traceback (most recent call last):", "File \"./lib/merge-grammar.py\", line 62, in ", " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):", "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__", " line = self._readline()", "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline", " return self._readline()", "ValueError: whatever exception that happened", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "Traceback (most recent call last):\n" "File \"./lib/merge-grammar.py\", line 62, in \n" " for line in fileinput.input(openhook=fileinput.hook_encoded(\"utf-8\")):\n" "File \"/usr/lib/python3.8/fileinput.py\", line 248, in __next__\n" " line = self._readline()\n" "File \"/usr/lib/python3.8/fileinput.py\", line 368, in _readline\n" " return self._readline()\n" "ValueError: whatever exception that happened"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } Test(smart_multi_line, test_java_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "java.lang.RuntimeException: javax.mail.SendFailedException: Invalid Addresses;", " nested exception is:", "com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendWithSmtp(AutomaticEmailFacade.java:236)", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:285)", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.lambda$sendSingleEmail$3(AutomaticEmailFacade.java:254)", " at java.util.Optional.ifPresent(Optional.java:159)", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:253)", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:249)", " at com.nethunt.crm.api.email.EmailSender.lambda$notifyPerson$0(EmailSender.java:80)", " at com.nethunt.crm.api.util.ManagedExecutor.lambda$execute$0(ManagedExecutor.java:36)", " at com.nethunt.crm.api.util.RequestContextActivator.lambda$withRequestContext$0(RequestContextActivator.java:36)", " at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)", " at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)", " at java.base/java.lang.Thread.run(Thread.java:748)", "Caused by: javax.mail.SendFailedException: Invalid Addresses;", " nested exception is:", "com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied", " at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:2064)", " at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1286)", " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendWithSmtp(AutomaticEmailFacade.java:229)", " ... 12 more", "Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied", NULL }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "java.lang.RuntimeException: javax.mail.SendFailedException: Invalid Addresses;\n" " nested exception is:\n" "com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendWithSmtp(AutomaticEmailFacade.java:236)\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:285)\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.lambda$sendSingleEmail$3(AutomaticEmailFacade.java:254)\n" " at java.util.Optional.ifPresent(Optional.java:159)\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:253)\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendSingleEmail(AutomaticEmailFacade.java:249)\n" " at com.nethunt.crm.api.email.EmailSender.lambda$notifyPerson$0(EmailSender.java:80)\n" " at com.nethunt.crm.api.util.ManagedExecutor.lambda$execute$0(ManagedExecutor.java:36)\n" " at com.nethunt.crm.api.util.RequestContextActivator.lambda$withRequestContext$0(RequestContextActivator.java:36)\n" " at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n" " at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n" " at java.base/java.lang.Thread.run(Thread.java:748)\n" "Caused by: javax.mail.SendFailedException: Invalid Addresses;\n" " nested exception is:\n" "com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied\n" " at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:2064)\n" " at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1286)\n" " at com.nethunt.crm.api.server.adminsync.AutomaticEmailFacade.sendWithSmtp(AutomaticEmailFacade.java:229)\n" " ... 12 more\n" "Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 550 5.7.1 <[REDACTED_EMAIL_ADDRESS]>... Relaying denied"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } Test(smart_multi_line, test_php_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "exception 'Exception' with message 'Custom exception' in /home/joe/work/test-php/test.php:5", "Stack trace:", "#0 /home/joe/work/test-php/test.php(9): func1()", "#1 /home/joe/work/test-php/test.php(13): func2()", "#2 {main}", "PHP Fatal error: Uncaught exception 'Exception' with message 'message' in /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php:60", "Stack trace:", "#0 [internal function]: ErrorEntryGenerator::{closure}()", "#1 /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php(20): call_user_func_array(Object(Closure), Array)", "#2 /base/data/home/apps/s~crash-example-php/1.388306779641080894/index.php(36): ErrorEntry->__call('raise', Array)", "#3 /base/data/home/apps/s~crash-example-php/1.388306779641080894/index.php(36): ErrorEntry->raise()", "#4 {main}", " thrown in /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php on line 60", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "exception 'Exception' with message 'Custom exception' in /home/joe/work/test-php/test.php:5\n" "Stack trace:\n" "#0 /home/joe/work/test-php/test.php(9): func1()\n" "#1 /home/joe/work/test-php/test.php(13): func2()\n" "#2 {main}"), "unexpected_value %s", _output_value(0)); cr_assert(_output_equals(1, "PHP Fatal error: Uncaught exception 'Exception' with message 'message' in /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php:60\n" "Stack trace:\n" "#0 [internal function]: ErrorEntryGenerator::{closure}()\n" "#1 /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php(20): call_user_func_array(Object(Closure), Array)\n" "#2 /base/data/home/apps/s~crash-example-php/1.388306779641080894/index.php(36): ErrorEntry->__call('raise', Array)\n" "#3 /base/data/home/apps/s~crash-example-php/1.388306779641080894/index.php(36): ErrorEntry->raise()\n" "#4 {main}\n" " thrown in /base/data/home/apps/s~crash-example-php/1.388306779641080894/errors.php on line 60"), "unexpected_value %s", _output_value(1)); multi_line_logic_free(mll); } Test(smart_multi_line, test_js_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "ReferenceError: myArray is not defined", " at next (/app/node_modules/express/lib/router/index.js:256:14)", " at /app/node_modules/express/lib/router/index.js:615:15", " at next (/app/node_modules/express/lib/router/index.js:271:10)", " at Function.process_params (/app/node_modules/express/lib/router/index.js:330:12)", " at /app/node_modules/express/lib/router/index.js:277:22", " at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)", " at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)", " at next (/app/node_modules/express/lib/router/route.js:131:13)", " at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)", " at /app/app.js:52:3", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "ReferenceError: myArray is not defined\n" " at next (/app/node_modules/express/lib/router/index.js:256:14)\n" " at /app/node_modules/express/lib/router/index.js:615:15\n" " at next (/app/node_modules/express/lib/router/index.js:271:10)\n" " at Function.process_params (/app/node_modules/express/lib/router/index.js:330:12)\n" " at /app/node_modules/express/lib/router/index.js:277:22\n" " at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)\n" " at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)\n" " at next (/app/node_modules/express/lib/router/route.js:131:13)\n" " at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)\n" " at /app/app.js:52:3"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } Test(smart_multi_line, test_go_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "panic: my panic", "", "goroutine 4 [running]:", "panic(0x45cb40, 0x47ad70)", " /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c", "main.main.func1(0xc420024120)", " foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339", "runtime.goexit()", " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1", "created by main.main", " foo.go:5 +0x58", "", "goroutine 1 [chan receive]:", "runtime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)", " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c", "runtime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)", " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e", "runtime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)", " /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4", "runtime.chanrecv1(0xc420024120, 0x0)", " /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b", "main.main()", " foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef", "runtime.main()", " /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad", "runtime.goexit()", " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1", "", "goroutine 2 [force gc (idle)]:", "runtime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)", " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c", "runtime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)", " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e", "runtime.forcegchelper()", " /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c", "runtime.goexit()", " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1", "created by runtime.init.4", " /usr/local/go/src/runtime/proc.go:227 +0x35", "", "goroutine 3 [GC sweep wait]:", "runtime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)", " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c", "runtime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)", " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e", "runtime.bgsweep(0xc42001e150)", " /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973", "runtime.goexit()", " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1", "created by runtime.gcenable", " /usr/local/go/src/runtime/mgc.go:216 +0x58", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "panic: my panic\n" "\n" "goroutine 4 [running]:\n" "panic(0x45cb40, 0x47ad70)\n" " /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c\n" "main.main.func1(0xc420024120)\n" " foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339\n" "runtime.goexit()\n" " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1\n" "created by main.main\n" " foo.go:5 +0x58\n" "\n" "goroutine 1 [chan receive]:\n" "runtime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)\n" " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c\n" "runtime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)\n" " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e\n" "runtime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)\n" " /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4\n" "runtime.chanrecv1(0xc420024120, 0x0)\n" " /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b\n" "main.main()\n" " foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef\n" "runtime.main()\n" " /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad\n" "runtime.goexit()\n" " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1\n" "\n" "goroutine 2 [force gc (idle)]:\n" "runtime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)\n" " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c\n" "runtime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)\n" " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e\n" "runtime.forcegchelper()\n" " /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c\n" "runtime.goexit()\n" " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1\n" "created by runtime.init.4\n" " /usr/local/go/src/runtime/proc.go:227 +0x35\n" "\n" "goroutine 3 [GC sweep wait]:\n" "runtime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)\n" " /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c\n" "runtime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)\n" " /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e\n" "runtime.bgsweep(0xc42001e150)\n" " /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973\n" "runtime.goexit()\n" " /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1\n" "created by runtime.gcenable\n" " /usr/local/go/src/runtime/mgc.go:216 +0x58"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } Test(smart_multi_line, test_ruby_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { " NoMethodError (undefined method `resursivewordload' for #):", " app/controllers/books_controller.rb:69:in `recursivewordload'", " app/controllers/books_controller.rb:75:in `loadword'", " app/controllers/books_controller.rb:79:in `loadline'", " app/controllers/books_controller.rb:83:in `loadparagraph'", " app/controllers/books_controller.rb:87:in `loadpage'", " app/controllers/books_controller.rb:91:in `onload'", " app/controllers/books_controller.rb:95:in `loadrecursive'", " app/controllers/books_controller.rb:99:in `requestload'", " app/controllers/books_controller.rb:118:in `generror'", " config/error_reporting_logger.rb:62:in `tagged'", " ActionController::RoutingError (No route matches [GET] \"/settings\"):", " ", " actionpack (5.1.4) lib/action_dispatch/middleware/debug_exceptions.rb:63:in `call'", " actionpack (5.1.4) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'", " railties (5.1.4) lib/rails/rack/logger.rb:36:in `call_app'", " railties (5.1.4) lib/rails/rack/logger.rb:24:in `block in call'", " activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `block in tagged'", " activesupport (5.1.4) lib/active_support/tagged_logging.rb:26:in `tagged'", " activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `tagged'", " railties (5.1.4) lib/rails/rack/logger.rb:24:in `call'", " actionpack (5.1.4) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'", " actionpack (5.1.4) lib/action_dispatch/middleware/request_id.rb:25:in `call'", " rack (2.0.3) lib/rack/method_override.rb:22:in `call'", " rack (2.0.3) lib/rack/runtime.rb:22:in `call'", " activesupport (5.1.4) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'", " actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'", " rack (2.0.3) lib/rack/sendfile.rb:111:in `call'", " railties (5.1.4) lib/rails/engine.rb:522:in `call'", " puma (3.10.0) lib/puma/configuration.rb:225:in `call'", " puma (3.10.0) lib/puma/server.rb:605:in `handle_request'", " puma (3.10.0) lib/puma/server.rb:437:in `process_client'", " puma (3.10.0) lib/puma/server.rb:301:in `block in run'", " puma (3.10.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, " NoMethodError (undefined method `resursivewordload' for #):\n" " app/controllers/books_controller.rb:69:in `recursivewordload'\n" " app/controllers/books_controller.rb:75:in `loadword'\n" " app/controllers/books_controller.rb:79:in `loadline'\n" " app/controllers/books_controller.rb:83:in `loadparagraph'\n" " app/controllers/books_controller.rb:87:in `loadpage'\n" " app/controllers/books_controller.rb:91:in `onload'\n" " app/controllers/books_controller.rb:95:in `loadrecursive'\n" " app/controllers/books_controller.rb:99:in `requestload'\n" " app/controllers/books_controller.rb:118:in `generror'\n" " config/error_reporting_logger.rb:62:in `tagged'"), "unexpected_value %s", _output_value(0)); cr_assert(_output_equals(1, " ActionController::RoutingError (No route matches [GET] \"/settings\"):\n" " \n" " actionpack (5.1.4) lib/action_dispatch/middleware/debug_exceptions.rb:63:in `call'\n" " actionpack (5.1.4) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'\n" " railties (5.1.4) lib/rails/rack/logger.rb:36:in `call_app'\n" " railties (5.1.4) lib/rails/rack/logger.rb:24:in `block in call'\n" " activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `block in tagged'\n" " activesupport (5.1.4) lib/active_support/tagged_logging.rb:26:in `tagged'\n" " activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `tagged'\n" " railties (5.1.4) lib/rails/rack/logger.rb:24:in `call'\n" " actionpack (5.1.4) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'\n" " actionpack (5.1.4) lib/action_dispatch/middleware/request_id.rb:25:in `call'\n" " rack (2.0.3) lib/rack/method_override.rb:22:in `call'\n" " rack (2.0.3) lib/rack/runtime.rb:22:in `call'\n" " activesupport (5.1.4) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'\n" " actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'\n" " rack (2.0.3) lib/rack/sendfile.rb:111:in `call'\n" " railties (5.1.4) lib/rails/engine.rb:522:in `call'\n" " puma (3.10.0) lib/puma/configuration.rb:225:in `call'\n" " puma (3.10.0) lib/puma/server.rb:605:in `handle_request'\n" " puma (3.10.0) lib/puma/server.rb:437:in `process_client'\n" " puma (3.10.0) lib/puma/server.rb:301:in `block in run'\n" " puma (3.10.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'"), "unexpected_value %s", _output_value(1)); multi_line_logic_free(mll); } Test(smart_multi_line, test_dart_backtrace) { MultiLineLogic *mll = smart_multi_line_new(); const gchar *messages[] = { "Unhandled exception:", "RangeError (index): Invalid value: Valid value range is empty: 1", "#0 List.[] (dart:core-patch/growable_array.dart:151)", "#1 main. (file:///path/to/code/dartFile.dart:31:23)", "#2 printError (file:///path/to/code/dartFile.dart:42:13)", "#3 main (file:///path/to/code/dartFile.dart:29:3)", "#4 _startIsolate. (dart:isolate-patch/isolate_patch.dart:265)", "#5 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:151)", NULL, }; _feed_lines(mll, messages); cr_assert(_output_equals(0, "Unhandled exception:\n" "RangeError (index): Invalid value: Valid value range is empty: 1\n" "#0 List.[] (dart:core-patch/growable_array.dart:151)\n" "#1 main. (file:///path/to/code/dartFile.dart:31:23)\n" "#2 printError (file:///path/to/code/dartFile.dart:42:13)\n" "#3 main (file:///path/to/code/dartFile.dart:29:3)\n" "#4 _startIsolate. (dart:isolate-patch/isolate_patch.dart:265)\n" "#5 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:151)"), "unexpected_value %s", _output_value(0)); multi_line_logic_free(mll); } void setup(void) { override_installation_path_for("${pkgdatadir}/smart-multi-line.fsm", TOP_SRCDIR "/lib/multi-line/smart-multi-line.fsm"); app_startup(); configuration = cfg_new_snippet(); buffer = g_string_sized_new(256); output_messages = g_ptr_array_new(); } void teardown(void) { g_string_free(buffer, TRUE); g_ptr_array_foreach(output_messages, (GFunc) g_free, NULL); g_ptr_array_free(output_messages, TRUE); scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(smart_multi_line, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/parse-number.c000066400000000000000000000130431450431004300206660ustar00rootroot00000000000000/* * Copyright (c) 2013-2014 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "parse-number.h" #include #include #include #include static const gint DECIMAL_BASE = 10; static const gint DETECT_BASE = 0; static gboolean _valid_unit(const gchar unit_char) { return (unit_char == 'B' || unit_char == 'b'); } static gboolean _valid_exponent(const gchar exponent_char) { gchar e = exponent_char; return e == 'k' || e == 'K' || e == 'm' || e == 'M' || e == 'g' || e == 'G'; } static gboolean _parse_suffix(const gchar *suffix, gchar *exponent_char, gchar *base_char, gchar *unit_char) { gint suffix_len; suffix_len = strlen(suffix); if (suffix_len > 3) return FALSE; if (suffix_len == 0) return TRUE; if (suffix_len == 3) { *exponent_char = suffix[0]; *base_char = suffix[1]; *unit_char = suffix[2]; } else if (suffix_len == 2) { *exponent_char = suffix[0]; if (_valid_unit(suffix[1])) *unit_char = suffix[1]; else *base_char = suffix[1]; } else if (suffix_len == 1) { if (_valid_exponent(suffix[0])) *exponent_char = suffix[0]; else if (_valid_unit(suffix[0])) *unit_char = suffix[0]; else return FALSE; } return TRUE; } static gboolean _determine_multiplier(gchar base_char, gint *multiplier) { if (base_char == 0) *multiplier = 1000; else if (base_char == 'I' || base_char == 'i') *multiplier = 1024; else return FALSE; return TRUE; } static gboolean _validate_unit(gchar unit_char) { if (unit_char && !_valid_unit(unit_char)) return FALSE; return TRUE; } static gboolean _process_exponent(gchar exponent_char, gint64 *d, gint multiplier) { switch (exponent_char) { case 'G': case 'g': (*d) *= multiplier; case 'm': case 'M': (*d) *= multiplier; case 'K': case 'k': (*d) *= multiplier; case 0: return TRUE; default: return FALSE; } } static gboolean _process_suffix(const gchar *suffix, gint64 *d) { gchar exponent_char = 0, base_char = 0, unit_char = 0; gint multiplier = 0; if (!_parse_suffix(suffix, &exponent_char, &base_char, &unit_char)) return FALSE; if (!_determine_multiplier(base_char, &multiplier)) return FALSE; if (!_validate_unit(unit_char)) return FALSE; if (!_process_exponent(exponent_char, d, multiplier)) return FALSE; return TRUE; } static gboolean _int64_from_string(const gchar *s, gchar **endptr, gint base, gint64 *d) { gint64 val; errno = 0; val = strtoll(s, endptr, base); if (errno == ERANGE || errno == EINVAL) return FALSE; if (*endptr == s) return FALSE; *d = val; return TRUE; } static gboolean _parse_double(const gchar *s, gchar **endptr, gdouble *d) { gdouble val; errno = 0; val = strtod(s, endptr); if (errno == ERANGE) return FALSE; if (*endptr == s) return FALSE; *d = val; return TRUE; } gboolean parse_int64_base16(const gchar *s, gint64 *d) { gchar *endptr; if (!_int64_from_string(s, &endptr, 16, d)) return FALSE; if (*endptr) return FALSE; return TRUE; } gboolean parse_int64_base8(const gchar *s, gint64 *d) { gchar *endptr; if (!_int64_from_string(s, &endptr, 8, d)) return FALSE; if (*endptr) return FALSE; return TRUE; } gboolean parse_int64_base_any(const gchar *s, gint64 *d) { gchar *endptr; if (!_int64_from_string(s, &endptr, DETECT_BASE, d)) return FALSE; if (*endptr) return FALSE; return TRUE; } gboolean parse_int64(const gchar *s, gint64 *d) { gchar *endptr; if (!_int64_from_string(s, &endptr, DECIMAL_BASE, d)) return FALSE; if (*endptr) return FALSE; return TRUE; } gboolean parse_int64_with_suffix(const gchar *s, gint64 *d) { gchar *endptr; if (!_int64_from_string(s, &endptr, DECIMAL_BASE, d)) return FALSE; return _process_suffix(endptr, d); } gboolean parse_double(const gchar *s, gdouble *d) { gchar *endptr; if (!_parse_double(s, &endptr, d)) return FALSE; if (*endptr) return FALSE; return TRUE; } gboolean parse_nan(const gchar *s) { while (isspace(*s)) s++; if (strcasecmp(s, "NaN") == 0) return TRUE; return FALSE; } gboolean parse_generic_number(const char *str, GenericNumber *number) { gint64 int_value; if (parse_int64(str, &int_value)) { gn_set_int64(number, int_value); return TRUE; } double float_value; if (parse_double(str, &float_value)) { gn_set_double(number, float_value, -1); return TRUE; } if (parse_nan(str)) gn_set_nan(number); return FALSE; } syslog-ng-syslog-ng-4.4.0/lib/parse-number.h000066400000000000000000000030331450431004300206710ustar00rootroot00000000000000/* * Copyright (c) 2013-2014 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PARSE_NUMBER_H_INCLUDED #define PARSE_NUMBER_H_INCLUDED #include "generic-number.h" gboolean parse_int64(const gchar *str, gint64 *result); gboolean parse_int64_base16(const gchar *str, gint64 *result); gboolean parse_int64_base8(const gchar *str, gint64 *result); gboolean parse_int64_base_any(const gchar *str, gint64 *result); gboolean parse_int64_with_suffix(const gchar *str, gint64 *result); gboolean parse_double(const gchar *str, gdouble *result); gboolean parse_generic_number(const char *str, GenericNumber *number); #endif syslog-ng-syslog-ng-4.4.0/lib/parser/000077500000000000000000000000001450431004300174155ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/parser/CMakeLists.txt000066400000000000000000000003071450431004300221550ustar00rootroot00000000000000set(PARSER_HEADERS parser/parser-expr.h parser/parser-expr-parser.h PARENT_SCOPE ) set(PARSER_SOURCES parser/parser-expr.c parser/parser-expr-parser.c PARENT_SCOPE ) syslog-ng-syslog-ng-4.4.0/lib/parser/Makefile.am000066400000000000000000000007371450431004300214600ustar00rootroot00000000000000parserincludedir = ${pkgincludedir}/parser EXTRA_DIST += lib/parser/CMakeLists.txt parserinclude_HEADERS = \ lib/parser/parser-expr.h \ lib/parser/parser-expr-parser.h parser_sources = \ lib/parser/parser-expr.c \ lib/parser/parser-expr-parser.c \ lib/parser/parser-expr-grammar.y BUILT_SOURCES += \ lib/parser/parser-expr-grammar.y \ lib/parser/parser-expr-grammar.c \ lib/parser/parser-expr-grammar.h EXTRA_DIST += lib/parser/parser-expr-grammar.ym syslog-ng-syslog-ng-4.4.0/lib/parser/parser-expr-grammar.ym000066400000000000000000000046411450431004300236650ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "parser/parser-expr-parser.h" #include "cfg-tree.h" } %code { #include "syslog-names.h" #include "plugin.h" #include "cfg-grammar-internal.h" } %define api.prefix {parser_expr_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogExprNode **result} %parse-param {gpointer arg} %type parser_expr %type parser_expr_list /* INCLUDE_DECLS */ %% start : parser_expr_list { *result = $1; if (yychar != PARSER_EXPR_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } YYACCEPT; } ; parser_expr_list : parser_expr semicolons parser_expr_list { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_fork semicolons parser_expr_list { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; parser_expr : LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_PARSER; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_parser = (LogParser *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_parser) { YYERROR; } $$ = last_parser; } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/parser/parser-expr-parser.c000066400000000000000000000031561450431004300233300ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "parser/parser-expr-parser.h" #include "parser/parser-expr.h" #include "parser/parser-expr-grammar.h" extern int parser_expr_debug; int parser_expr_parse(CfgLexer *lexer, LogExprNode **node, gpointer arg); static CfgLexerKeyword parser_expr_keywords[] = { { NULL } }; CfgParser parser_expr_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &parser_expr_debug, #endif .name = "parser expression", .context = LL_CONTEXT_PARSER, .keywords = parser_expr_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) parser_expr_parse, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(parser_expr_, PARSER_EXPR_, LogExprNode **) syslog-ng-syslog-ng-4.4.0/lib/parser/parser-expr-parser.h000066400000000000000000000023561450431004300233360ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PARSER_EXPR_PARSER_H_INCLUDED #define PARSER_EXPR_PARSER_H_INCLUDED #include "cfg-parser.h" #include "parser/parser-expr.h" extern CfgParser parser_expr_parser; CFG_PARSER_DECLARE_LEXER_BINDING(parser_expr_, PARSER_EXPR_, LogExprNode **) #endif syslog-ng-syslog-ng-4.4.0/lib/parser/parser-expr.c000066400000000000000000000136041450431004300220350ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "parser/parser-expr.h" #include "template/templates.h" #include "logmatcher.h" #include /* NOTE: consumes template */ void log_parser_set_template(LogParser *self, LogTemplate *template_obj) { log_template_unref(self->template_obj); self->template_obj = template_obj; } void log_parser_clone_settings(LogParser *self, LogParser *cloned) { log_pipe_clone_method(&cloned->super, &self->super); log_parser_set_template(cloned, log_template_ref(self->template_obj)); } gboolean log_parser_process_message(LogParser *self, LogMessage **pmsg, const LogPathOptions *path_options) { LogMessage *msg = *pmsg; gboolean success; if (G_LIKELY(!self->template_obj)) { NVTable *payload = nv_table_ref(msg->payload); const gchar *value; gssize value_len; /* NOTE: the process function may set values in the LogMessage * instance, which in turn can trigger nv_table_realloc() to be * called. However in case nv_table_realloc() finds a refcounter > 1, * it'll always _move_ the structure and leave the old one intact, * until its refcounter drops to zero. If that wouldn't be the case, * nv_table_realloc() could make our payload pointer and the * LM_V_MESSAGE pointer we pass to process() go stale. */ value = log_msg_get_value(msg, LM_V_MESSAGE, &value_len); success = self->process(self, pmsg, path_options, value, value_len); nv_table_unref(payload); } else { GString *input = g_string_sized_new(256); log_template_format(self->template_obj, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, input); success = self->process(self, pmsg, path_options, input->str, input->len); g_string_free(input, TRUE); } if (!success) stats_counter_inc(self->super.discarded_messages); else stats_counter_inc(self->processed_messages); return success; } void log_parser_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogParser *self = (LogParser *) s; gboolean success; gchar *parser_result; msg_trace(">>>>>> parser rule evaluation begin", evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); success = log_parser_process_message(self, &msg, path_options); if (success) { parser_result = "Forwarding message to the next LogPipe"; log_pipe_forward_msg(s, msg, path_options); } else { parser_result = "Dropping message from LogPipe"; if (path_options->matched) (*path_options->matched) = FALSE; log_msg_drop(msg, path_options, AT_PROCESSED); } msg_trace("<<<<<< parser rule evaluation result", evt_tag_str("result", parser_result), evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); } static void _register_counters(LogParser *self) { gint level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : STATS_LEVEL1; stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->name) }; stats_cluster_logpipe_key_set(&sc_key, "parsed_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_PARSER, self->name, NULL ); stats_register_counter(level, &sc_key, SC_TYPE_DISCARDED, &self->super.discarded_messages); stats_register_counter(level, &sc_key, SC_TYPE_PROCESSED, &self->processed_messages); stats_unlock(); } gboolean log_parser_init_method(LogPipe *s) { LogParser *self = (LogParser *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!self->name && s->expr_node) self->name = cfg_tree_get_rule_name(&cfg->tree, ENC_PARSER, s->expr_node); _register_counters(self); return TRUE; } static void _unregister_stats(LogParser *self) { stats_lock(); StatsClusterKey sc_key; StatsClusterLabel labels[] = { stats_cluster_label("id", self->name) }; stats_cluster_logpipe_key_set(&sc_key, "parsed_events_total", labels, G_N_ELEMENTS(labels)); stats_cluster_logpipe_key_add_legacy_alias(&sc_key, SCS_PARSER, self->name, NULL ); stats_unregister_counter(&sc_key, SC_TYPE_DISCARDED, &self->super.discarded_messages); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &self->processed_messages); stats_unlock(); } gboolean log_parser_deinit_method(LogPipe *s) { LogParser *self = (LogParser *) s; _unregister_stats(self); return TRUE; } void log_parser_free_method(LogPipe *s) { LogParser *self = (LogParser *) s; g_free(self->name); log_template_unref(self->template_obj); log_pipe_free_method(s); } void log_parser_init_instance(LogParser *self, GlobalConfig *cfg) { log_pipe_init_instance(&self->super, cfg); self->super.flags |= PIF_CONFIG_RELATED; self->super.init = log_parser_init_method; self->super.deinit = log_parser_deinit_method; self->super.free_fn = log_parser_free_method; self->super.queue = log_parser_queue_method; } syslog-ng-syslog-ng-4.4.0/lib/parser/parser-expr.h000066400000000000000000000045251450431004300220440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGPARSER_H_INCLUDED #define LOGPARSER_H_INCLUDED #include "logmsg/logmsg.h" #include "messages.h" #include "logpipe.h" #include "template/templates.h" #include "stats/stats-registry.h" #include typedef struct _LogParser LogParser; struct _LogParser { LogPipe super; LogTemplate *template_obj; StatsCounterItem *processed_messages; gboolean (*process)(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const gchar *input, gsize input_len); gchar *name; }; gboolean log_parser_deinit_method(LogPipe *s); void log_parser_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options); gboolean log_parser_init_method(LogPipe *s); void log_parser_set_template(LogParser *self, LogTemplate *template_obj); void log_parser_clone_settings(LogParser *self, LogParser *cloned); void log_parser_init_instance(LogParser *self, GlobalConfig *cfg); void log_parser_free_method(LogPipe *self); static inline gboolean log_parser_process(LogParser *self, LogMessage **pmsg, const LogPathOptions *path_options, const gchar *input, gssize input_len) { if (input_len < 0) input_len = strlen(input); return self->process(self, pmsg, path_options, input, input_len); } gboolean log_parser_process_message(LogParser *self, LogMessage **pmsg, const LogPathOptions *path_options); #endif syslog-ng-syslog-ng-4.4.0/lib/pathutils.c000066400000000000000000000046021450431004300203040ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pathutils.h" #include #include gboolean is_file_directory(const char *filename) { return g_file_test(filename, G_FILE_TEST_EXISTS) && g_file_test(filename, G_FILE_TEST_IS_DIR); }; gboolean is_file_regular(const char *filename) { return g_file_test(filename, G_FILE_TEST_EXISTS) && g_file_test(filename, G_FILE_TEST_IS_REGULAR); }; gboolean is_file_device(const gchar *name) { struct stat st; if (stat(name, &st) >= 0) return S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode); else return FALSE; } gchar * find_file_in_path(const gchar *path, const gchar *filename, GFileTest test) { gchar **dirs; gchar *fullname = NULL; gint i; if (filename[0] == '/' || !path) { if (g_file_test(filename, test)) return g_strdup(filename); return NULL; } dirs = g_strsplit(path, G_SEARCHPATH_SEPARATOR_S, 0); i = 0; while (dirs && dirs[i]) { fullname = g_build_filename(dirs[i], filename, NULL); if (g_file_test(fullname, test)) break; g_free(fullname); fullname = NULL; i++; } g_strfreev(dirs); return fullname; } const gchar * get_filename_extension(const gchar *filename) { if (!filename) return NULL; const gchar *start_ext = strrchr(filename, '.'); if (!start_ext || start_ext[1] == '\0' || start_ext == filename) return NULL; return start_ext + 1; } syslog-ng-syslog-ng-4.4.0/lib/pathutils.h000066400000000000000000000025571450431004300203200ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _PATHUTILS_H #define _PATHUTILS_H #include "syslog-ng.h" gboolean is_file_regular(const char *filename); gboolean is_file_directory(const char *filename); gboolean is_file_device(const gchar *name); gchar *find_file_in_path(const gchar *path, const gchar *filename, GFileTest test); const gchar *get_filename_extension(const gchar *filename); #endif syslog-ng-syslog-ng-4.4.0/lib/pe-versioning.h000066400000000000000000000017361450431004300210660ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ syslog-ng-syslog-ng-4.4.0/lib/persist-state.c000066400000000000000000000767171450431004300211160ustar00rootroot00000000000000/* * Copyright (c) 2023 One Identity LLC. * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "persist-state.h" #include "serialize.h" #include "messages.h" #include "fdhelpers.h" #include #include #include #include #include #include #include #define PERSIST_FILE_INITIAL_SIZE 16384 #define PERSIST_STATE_KEY_BLOCK_SIZE 4096 #define PERSIST_FILE_MAX_ENTRY_SIZE 8448 /* * The syslog-ng persistent state is a set of name-value pairs, * updated atomically during syslog-ng runtime. When syslog-ng * initializes its configuration it allocates chunks of memory to * represent its own state which gets mmapped from a file. * * Whenever syslog-ng writes to the state memory, it gets atomically * written to the persistent file. * * Allocated blocks have a name in order to make it possible to fetch * the same state even between syslog-ng restarts. * * Thus PersistState has two memory areas to represent the information * - the key store containing names and the associated offset * information basically in a sequential file * - the state area containing the values * * When a new NV pair is registered, syslog-ng allocates the requested * area in the state, and writes a new record to the key store * file containing the name of the state entry and its length * information. If the same name is reused, it is appended to the * key store, never updated in-line. * * If syslog-ng crashes then both the state and the keystore should be * left where it was. The information processed the following way: * - the key store file is read into memory and a new key store file is * produced (to ensure that unused state entries are dropped) * - a new state file is produced, again unused data is dropped * * Old persist files can be converted the same way. * * We're using a trick to represent both areas in the same file: some * space is allocated initially for the key store and once that fills * up, syslog-ng allocates another key store area and chains these * areas up using a next pointer. * * Value blocks are prefixed with an 8 byte header, containing the * following information: * - block size (4 bytes) * - format version (1 byte) * - whether the block is in use (1 byte) * * Cleaning up: * ------------ * * It can be seen that no explicit deallocation is performed on the * persistent file, in effect it could grow indefinitely. There's a * simple cleanup procedure though: * * - on every startup, the persist file is rewritten, entries with an * in_use bit set are copied to the new one, with the in_use bit cleared * - whenever syslog-ng looks up (e.g. uses) an entry, its in_use bit is set again * * This way unused entries in the persist file are reaped when * syslog-ng restarts. * * Trusts: * ------- * * We don't trust the on-disk file when following a reference * (e.g. offset, or object size) however we do trust the internal hash * table built after validating the disk contents. This means that if * you look up a key in the hashtable you can use the returned offset * blindly without checking. However when reading the same value from * the file you need to check it whether it is inside the mapped file. * */ /* everything is big-endian */ typedef struct _PersistValueHeader { guint32 size; guint8 in_use; guint8 version; guint16 __padding; } PersistValueHeader; /* lowest layer, "store" functions manage the file on disk */ static void _wait_until_map_release(PersistState *self) { g_mutex_lock(&self->mapped_lock); while (self->mapped_counter) g_cond_wait(&self->mapped_release_cond, &self->mapped_lock); } static gboolean _increase_file_size(PersistState *self, guint32 new_size) { gboolean result = TRUE; ssize_t length = new_size - self->current_size; gchar *pad_buffer = g_new0(gchar, length); ssize_t rc = pwrite(self->fd, pad_buffer, length, self->current_size); if (rc != length) { msg_error("Can't grow the persist file", evt_tag_int("old_size", self->current_size), evt_tag_int("new_size", new_size), evt_tag_str("error", rc < 0 ? g_strerror(errno) : "short write")); result = FALSE; } g_free(pad_buffer); return result; } static gboolean _grow_store(PersistState *self, guint32 new_size) { int pgsize = getpagesize(); gboolean result = FALSE; _wait_until_map_release(self); if ((new_size & (pgsize-1)) != 0) { new_size = ((new_size / pgsize) + 1) * pgsize; } if (new_size > self->current_size) { if (!_increase_file_size(self, new_size)) goto exit; if (self->current_map) munmap(self->current_map, self->current_size); self->current_size = new_size; self->current_map = mmap(NULL, self->current_size, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, 0); if (self->current_map == MAP_FAILED) { self->current_map = NULL; goto exit; } self->header = (PersistFileHeader *) self->current_map; memcpy(&self->header->magic, "SLP4", 4); } result = TRUE; exit: g_mutex_unlock(&self->mapped_lock); return result; } static gboolean _create_store(PersistState *self) { self->fd = open(self->temp_filename, O_RDWR | O_CREAT | O_TRUNC, 0600); if (self->fd < 0) { msg_error("Error creating persistent state file", evt_tag_str("filename", self->temp_filename), evt_tag_error("error")); return FALSE; } g_fd_set_cloexec(self->fd, TRUE); self->current_key_block = offsetof(PersistFileHeader, initial_key_store); self->current_key_ofs = 0; self->current_key_size = sizeof((((PersistFileHeader *) NULL))->initial_key_store); return _grow_store(self, PERSIST_FILE_INITIAL_SIZE); } static gboolean _commit_store(PersistState *self) { /* NOTE: we don't need to remap the file in case it is renamed */ return rename(self->temp_filename, self->committed_filename) >= 0; } static gboolean _check_watermark(PersistState *self) { return (self->current_ofs + PERSIST_FILE_MAX_ENTRY_SIZE < self->current_size); } static inline gboolean _check_free_space(PersistState *self, guint32 size) { return (size + sizeof(PersistValueHeader) + self->current_ofs) <= self->current_size; } static void persist_state_run_error_handler(PersistState *self) { if (self->error_handler.handler) self->error_handler.handler(self->error_handler.cookie); } /* "value" layer that handles memory block allocation in the file, without working with keys */ static inline void _check_max_entry_size(guint32 size) { g_assert(size + sizeof(PersistValueHeader) <= PERSIST_FILE_MAX_ENTRY_SIZE); } static PersistEntryHandle _alloc_value(PersistState *self, guint32 orig_size, gboolean in_use, guint8 version) { PersistEntryHandle result; PersistValueHeader *header; guint32 size = orig_size; /* round up size to 8 bytes boundary */ if ((size & 0x7)) size = ((size >> 3) + 1) << 3; _check_max_entry_size(size); if (!_check_free_space(self, size)) { msg_error("No more free space exhausted in persist file"); return 0; } result = self->current_ofs + sizeof(PersistValueHeader); /* fill value header */ header = (PersistValueHeader *) persist_state_map_entry(self, self->current_ofs); header->size = GUINT32_TO_BE(orig_size); header->in_use = in_use; header->version = version; persist_state_unmap_entry(self, self->current_ofs); self->current_ofs += size + sizeof(PersistValueHeader); if (!_check_watermark(self) && !_grow_store(self, self->current_size + PERSIST_FILE_INITIAL_SIZE)) { msg_error("Can't preallocate space for persist file", evt_tag_int("current", self->current_size), evt_tag_int("new_size", self->current_size + PERSIST_FILE_INITIAL_SIZE)); persist_state_run_error_handler(self); } return result; } static PersistValueHeader * _map_header_of_entry_from_handle(PersistState *self, PersistEntryHandle handle) { PersistValueHeader *header; if (handle > self->current_size) { msg_error("Corrupted handle in persist_state_lookup_entry, handle value too large", evt_tag_printf("handle", "%08x", handle)); return NULL; } header = (PersistValueHeader *) persist_state_map_entry(self, handle - sizeof(PersistValueHeader)); if (GUINT32_FROM_BE(header->size) + handle > self->current_size) { msg_error("Corrupted entry header found in persist_state_lookup_entry, size too large", evt_tag_printf("handle", "%08x", handle), evt_tag_int("size", GUINT32_FROM_BE(header->size)), evt_tag_int("file_size", self->current_size)); return NULL; } return header; } static void _free_value(PersistState *self, PersistEntryHandle handle) { if (handle) { PersistValueHeader *header; header = _map_header_of_entry_from_handle(self, handle); if (header) header->in_use = 0; persist_state_unmap_entry(self, handle); } } /* key management */ static gboolean _persist_state_lookup_key(PersistState *self, const gchar *key, PersistEntryHandle *handle) { PersistEntry *entry; entry = g_hash_table_lookup(self->keys, key); if (entry) { *handle = entry->ofs; return TRUE; } return FALSE; } gboolean persist_state_rename_entry(PersistState *self, const gchar *old_key, const gchar *new_key) { PersistEntry *entry; gpointer old_orig_key; if (g_hash_table_lookup_extended(self->keys, old_key, &old_orig_key, (gpointer *)&entry)) { if (g_hash_table_steal(self->keys, old_key)) { g_free(old_orig_key); g_hash_table_insert(self->keys, g_strdup(new_key), entry); return TRUE; } } return FALSE; } static void _persist_state_copy_entry(PersistState *self, const PersistEntryHandle from, PersistEntryHandle to, gsize size) { gpointer entry_from = persist_state_map_entry(self, from); gpointer entry_to = persist_state_map_entry(self, to); memcpy(entry_to, entry_from, size); persist_state_unmap_entry(self, from); persist_state_unmap_entry(self, to); } gboolean persist_state_move_entry(PersistState *self, const gchar *old_key, const gchar *new_key) { gsize size; guint8 version; PersistEntryHandle old_handle = persist_state_lookup_entry(self, old_key, &size, &version); if (!old_handle) return FALSE; PersistEntryHandle new_handle = persist_state_alloc_entry(self, new_key, size); if (!new_handle) return FALSE; _persist_state_copy_entry(self, old_handle, new_handle, size); _free_value(self, old_handle); msg_debug("Persistent entry moved", evt_tag_str("from", old_key), evt_tag_str("to", new_key)); return TRUE; } /* * NOTE: can only be called from the main thread (e.g. log_pipe_init/deinit). */ static gboolean _add_key(PersistState *self, const gchar *key, PersistEntryHandle handle) { PersistEntry *entry; gboolean new_block_created = FALSE; SerializeArchive *sa; g_assert(key[0] != 0); entry = g_new(PersistEntry, 1); entry->ofs = handle; g_hash_table_insert(self->keys, g_strdup(key), entry); /* we try to insert the key into the current block first, then if it doesn't fit, we create a new block */ while (1) { /* the size of the key block chain part, 4 byte for the empty string length, guint32 for the link to the next block */ guint32 chain_size = sizeof(guint32) + sizeof(guint32); gboolean success; gchar *key_area = persist_state_map_entry(self, self->current_key_block); /* we reserve space for the next area pointer */ sa = serialize_buffer_archive_new(key_area + self->current_key_ofs, self->current_key_size - self->current_key_ofs - chain_size); sa->silent = TRUE; success = serialize_write_cstring(sa, key, -1) && serialize_write_uint32(sa, handle); if (!success) { serialize_archive_free(sa); if (!new_block_created) { PersistEntryHandle new_block; /* we unmap the key_area as otherwise we can't grow because of the pending maps */ persist_state_unmap_entry(self, self->current_key_block); /* ah, we couldn't fit into the current block, create a new one and link it off the old one */ new_block = _alloc_value(self, PERSIST_STATE_KEY_BLOCK_SIZE, TRUE, 0); if (!new_block) { msg_error("Unable to allocate space in the persistent file for key store"); return FALSE; } key_area = persist_state_map_entry(self, self->current_key_block); sa = serialize_buffer_archive_new(key_area + self->current_key_ofs, self->current_key_size - self->current_key_ofs); if (!serialize_write_cstring(sa, "", 0) || !serialize_write_uint32(sa, new_block)) { /* hmmm. now this is bad, we couldn't write the tail of the block even though we always reserved space for it, this is a programming error somewhere in this function. */ g_assert_not_reached(); } serialize_archive_free(sa); persist_state_unmap_entry(self, self->current_key_block); self->current_key_block = new_block; self->current_key_size = PERSIST_STATE_KEY_BLOCK_SIZE; self->current_key_ofs = 0; new_block_created = TRUE; } else { /* if this happens, that means that the current key * entry won't fit even into a freshly initialized key * block, this means that the key is too large. */ msg_error("Persistent key too large, it cannot be larger than somewhat less than 4k", evt_tag_str("key", key)); persist_state_unmap_entry(self, self->current_key_block); return FALSE; } } else { const guint32 key_count = GUINT32_FROM_BE(self->header->key_count); self->header->key_count = GUINT32_TO_BE(key_count + 1); self->current_key_ofs += serialize_buffer_archive_get_pos(sa); serialize_archive_free(sa); persist_state_unmap_entry(self, self->current_key_block); return TRUE; } } g_assert_not_reached(); } /* process an on-disk persist file into the current one */ /* function to load v2 and v3 format persistent files */ static gboolean _load_v23(PersistState *self, gint version, SerializeArchive *sa) { gchar *key, *value; while (serialize_read_cstring(sa, &key, NULL)) { gsize len; guint32 str_len; if (key[0] && serialize_read_cstring(sa, &value, &len)) { PersistEntryHandle new_handle; /* add length of the string */ new_handle = _alloc_value(self, len + sizeof(str_len), FALSE, version); gchar *new_block = persist_state_map_entry(self, new_handle); /* NOTE: we add an extra length field to the old value, as our * persist_state_lookup_string() needs that. * persist_state_lookup_string is used to fetch disk queue file * names. It could have been solved somewhat better, but now it * doesn't justify a persist-state file format change. */ str_len = GUINT32_TO_BE(len); memcpy(new_block, &str_len, sizeof(str_len)); memcpy(new_block + sizeof(str_len), value, len); persist_state_unmap_entry(self, new_handle); /* add key to the current file */ _add_key(self, key, new_handle); g_free(value); g_free(key); } else { g_free(key); break; } } return TRUE; } static gboolean _load_v4(PersistState *self, gboolean load_all_entries) { gint fd; gint64 file_size; gpointer map; gpointer key_block; guint32 key_size; PersistFileHeader *header; gint key_count, i; fd = open(self->committed_filename, O_RDONLY); if (fd < 0) { /* no previous data found */ return TRUE; } file_size = lseek(fd, 0, SEEK_END); if (file_size > ((1LL << 31) - 1)) { msg_error("Persistent file too large", evt_tag_str("filename", self->committed_filename), evt_tag_printf("size", "%" G_GINT64_FORMAT, file_size)); close(fd); return FALSE; } map = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (map == MAP_FAILED) { msg_error("Error mapping persistent file into memory", evt_tag_str("filename", self->committed_filename), evt_tag_error("error")); return FALSE; } header = (PersistFileHeader *) map; key_block = ((gchar *) map) + offsetof(PersistFileHeader, initial_key_store); key_size = sizeof((((PersistFileHeader *) NULL))->initial_key_store); key_count = GUINT32_FROM_BE(header->key_count); i = 0; while (i < key_count) { gchar *name; guint32 entry_ofs, chain_ofs; SerializeArchive *sa; sa = serialize_buffer_archive_new(key_block, key_size); while (i < key_count) { if (!serialize_read_cstring(sa, &name, NULL)) { serialize_archive_free(sa); msg_error("Persistent file format error, unable to fetch key name"); goto free_and_exit; } if (name[0]) { if (serialize_read_uint32(sa, &entry_ofs)) { PersistValueHeader *value_header; i++; if (entry_ofs < sizeof(PersistFileHeader) || entry_ofs > file_size) { serialize_archive_free(sa); g_free(name); msg_error("Persistent file format error, entry offset is out of bounds"); goto free_and_exit; } value_header = (PersistValueHeader *) ((gchar *) map + entry_ofs - sizeof(PersistValueHeader)); if ((value_header->in_use) || load_all_entries) { gpointer new_block; PersistEntryHandle new_handle; new_handle = _alloc_value(self, GUINT32_FROM_BE(value_header->size), FALSE, value_header->version); new_block = persist_state_map_entry(self, new_handle); memcpy(new_block, value_header + 1, GUINT32_FROM_BE(value_header->size)); persist_state_unmap_entry(self, new_handle); /* add key to the current file */ _add_key(self, name, new_handle); } g_free(name); } else { /* bad format */ serialize_archive_free(sa); g_free(name); msg_error("Persistent file format error, unable to fetch key name"); goto free_and_exit; } } else { g_free(name); if (serialize_read_uint32(sa, &chain_ofs)) { /* end of block, chain to the next one */ if (chain_ofs == 0 || chain_ofs > file_size) { msg_error("Persistent file format error, key block chain offset is too large or zero", evt_tag_printf("key_block", "%08lx", (gulong) ((gchar *) key_block - (gchar *) map)), evt_tag_printf("key_size", "%d", key_size), evt_tag_int("ofs", chain_ofs)); serialize_archive_free(sa); goto free_and_exit; } key_block = ((gchar *) map) + chain_ofs; key_size = GUINT32_FROM_BE(*(guint32 *) (((gchar *) key_block) - sizeof(PersistValueHeader))); if (chain_ofs + key_size > file_size) { msg_error("Persistent file format error, key block size is too large", evt_tag_int("key_size", key_size)); serialize_archive_free(sa); goto free_and_exit; } break; } else { serialize_archive_free(sa); msg_error("Persistent file format error, unable to fetch chained key block offset"); goto free_and_exit; } } } serialize_archive_free(sa); } free_and_exit: munmap(map, file_size); return TRUE; } static gboolean _load(PersistState *self, gboolean all_errors_are_fatal, gboolean load_all_entries) { FILE *persist_file; gboolean success = FALSE; persist_file = fopen(self->committed_filename, "r"); if (persist_file) { SerializeArchive *sa; gchar magic[4]; gint version; sa = serialize_file_archive_new(persist_file); serialize_read_blob(sa, magic, 4); if (memcmp(magic, "SLP", 3) != 0) { msg_error("Persistent configuration file is in invalid format, ignoring"); success = all_errors_are_fatal ? FALSE : TRUE; goto close_and_exit; } version = magic[3] - '0'; if (version >= 2 && version <= 3) { success = _load_v23(self, version, sa); } else if (version == 4) { success = _load_v4(self, load_all_entries); } else { msg_error("Persistent configuration file has an unsupported major version, ignoring", evt_tag_int("version", version)); success = TRUE; } close_and_exit: fclose(persist_file); serialize_archive_free(sa); } else { if (all_errors_are_fatal) { msg_error("Failed to open persist file!", evt_tag_str("filename", self->committed_filename), evt_tag_str("error", strerror(errno))); success = FALSE; } else success = TRUE; } return success; } /** * All persistent data accesses must be guarded by a _map and _unmap * call in order to get a dereferencable pointer. It is not safe to * save this pointer for longer terms as the underlying mapping may * change when the file grows. * * Threading NOTE: this can be called from any kind of threads. * * NOTE: it is not safe to keep an entry mapped while synchronizing with the * main thread (e.g. mutexes, condvars, main_loop_call()), because * map_entry() may block the main thread in _grow_store(). **/ gpointer persist_state_map_entry(PersistState *self, PersistEntryHandle handle) { /* we count the number of mapped entries in order to know if we're * safe to remap the file region */ g_assert(handle); g_mutex_lock(&self->mapped_lock); self->mapped_counter++; g_mutex_unlock(&self->mapped_lock); return (gpointer) (((gchar *) self->current_map) + (guint32) handle); } /* * Threading NOTE: this can be called from any kind of threads. */ void persist_state_unmap_entry(PersistState *self, PersistEntryHandle handle) { g_mutex_lock(&self->mapped_lock); g_assert(self->mapped_counter >= 1); self->mapped_counter--; if (self->mapped_counter == 0) { g_cond_signal(&self->mapped_release_cond); } g_mutex_unlock(&self->mapped_lock); } static PersistValueHeader * _map_header_of_entry(PersistState *self, const gchar *persist_name, PersistEntryHandle *handle) { if (!_persist_state_lookup_key(self, persist_name, handle)) return NULL; return _map_header_of_entry_from_handle(self, *handle); } PersistEntryHandle persist_state_alloc_entry(PersistState *self, const gchar *persist_name, gsize alloc_size) { PersistEntryHandle handle; persist_state_remove_entry(self, persist_name); handle = _alloc_value(self, alloc_size, TRUE, self->version); if (!handle) return 0; if (!_add_key(self, persist_name, handle)) { _free_value(self, handle); return 0; } return handle; } PersistEntryHandle persist_state_lookup_entry(PersistState *self, const gchar *key, gsize *size, guint8 *version) { PersistEntryHandle handle; PersistValueHeader *header; header = _map_header_of_entry(self, key, &handle); if (header) { header->in_use = TRUE; *size = GUINT32_FROM_BE(header->size); *version = header->version; persist_state_unmap_entry(self, handle); return handle; } else return 0; } gboolean persist_state_entry_exists(PersistState *self, const gchar *persist_name) { PersistEntryHandle handle; return _persist_state_lookup_key(self, persist_name, &handle); } gboolean persist_state_remove_entry(PersistState *self, const gchar *key) { PersistEntryHandle handle; if (!_persist_state_lookup_key(self, key, &handle)) return FALSE; _free_value(self, handle); return TRUE; } typedef struct _PersistStateKeysForeachData { PersistStateForeachFunc func; gpointer userdata; PersistState *storage; } PersistStateKeysForeachData; static void _foreach_entry_func(gpointer key, gpointer value, gpointer userdata) { PersistStateKeysForeachData *data = (PersistStateKeysForeachData *) userdata; PersistEntry *entry = (PersistEntry *) value; gchar *name = (gchar *) key; PersistValueHeader *header = persist_state_map_entry(data->storage, entry->ofs - sizeof(PersistValueHeader)); gint size = GUINT32_FROM_BE(header->size); persist_state_unmap_entry(data->storage, entry->ofs - sizeof(PersistValueHeader)); PersistEntryHandle original_handler = entry->ofs; gpointer state = persist_state_map_entry(data->storage, entry->ofs); data->func(name, size, state, data->userdata); persist_state_unmap_entry(data->storage, original_handler); } void persist_state_foreach_entry(PersistState *self, PersistStateForeachFunc func, gpointer userdata) { PersistStateKeysForeachData data; data.func = func; data.userdata = userdata; data.storage = self; g_hash_table_foreach(self->keys, _foreach_entry_func, &data); } /* easier to use string based interface */ gchar * persist_state_lookup_string(PersistState *self, const gchar *key, gsize *length, guint8 *version) { PersistEntryHandle handle; gpointer block; SerializeArchive *sa; gchar *result; gsize result_len, size; guint8 result_version; gboolean success; if (!(handle = persist_state_lookup_entry(self, key, &size, &result_version))) return NULL; block = persist_state_map_entry(self, handle); sa = serialize_buffer_archive_new(block, size); success = serialize_read_cstring(sa, &result, &result_len); serialize_archive_free(sa); persist_state_unmap_entry(self, handle); if (!success) return NULL; if (length) *length = result_len; if (version) *version = result_version; return result; } void persist_state_alloc_string(PersistState *self, const gchar *persist_name, const gchar *value, gssize len) { PersistEntryHandle handle; SerializeArchive *serializer; GString *buf; gboolean success; gpointer block; gsize lookup_size; guint8 lookup_result_version; if (len < 0) len = strlen(value); buf = g_string_sized_new(len + 5); serializer = serialize_string_archive_new(buf); success = serialize_write_cstring(serializer, value, len); g_assert(success == TRUE); serialize_archive_free(serializer); handle = persist_state_lookup_entry(self, persist_name, &lookup_size, &lookup_result_version); if (!handle || lookup_size < buf->len) { handle = persist_state_alloc_entry(self, persist_name, buf->len); } block = persist_state_map_entry(self, handle); memcpy(block, buf->str, buf->len); persist_state_unmap_entry(self, handle); g_string_free(buf, TRUE); } const gchar * persist_state_get_filename(PersistState *self) { return self->committed_filename; } gboolean persist_state_start_dump(PersistState *self) { if (!_create_store(self)) return FALSE; if (!_load(self, TRUE, TRUE)) return FALSE; return TRUE; } gboolean persist_state_start_edit(PersistState *self) { if (!_create_store(self)) return FALSE; if (!_load(self, FALSE, TRUE)) return FALSE; return TRUE; } gboolean persist_state_start(PersistState *self) { if (!_create_store(self)) return FALSE; if (!_load(self, FALSE, FALSE)) return FALSE; return TRUE; } /* * This function commits the current store as the "persistent" file by * renaming the temp file we created to build the loaded * information. Once this function returns, then the current * persistent file will be visible to the next relaunch of syslog-ng, * even if we crashed. */ gboolean persist_state_commit(PersistState *self) { if (!_commit_store(self)) return FALSE; return TRUE; } static void _destroy(PersistState *self) { g_mutex_lock(&self->mapped_lock); g_assert(self->mapped_counter == 0); g_mutex_unlock(&self->mapped_lock); if (self->fd >= 0) close(self->fd); if (self->current_map) munmap(self->current_map, self->current_size); unlink(self->temp_filename); g_mutex_clear(&self->mapped_lock); g_cond_clear(&self->mapped_release_cond); g_free(self->temp_filename); g_free(self->committed_filename); g_hash_table_destroy(self->keys); } static void _init(PersistState *self, gchar *committed_filename, gchar *temp_filename) { self->keys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); self->current_ofs = sizeof(PersistFileHeader); g_mutex_init(&self->mapped_lock); g_cond_init(&self->mapped_release_cond); self->version = 4; self->fd = -1; self->committed_filename = committed_filename; self->temp_filename = temp_filename; } /* * This routine should revert to the persist_state_new() state, * e.g. just like the PersistState object wasn't started yet. */ void persist_state_cancel(PersistState *self) { gchar *committed_filename, *temp_filename; committed_filename = g_strdup(self->committed_filename); temp_filename = g_strdup(self->temp_filename); _destroy(self); memset(self, 0, sizeof(*self)); _init(self, committed_filename, temp_filename); } PersistState * persist_state_new(const gchar *filename) { PersistState *self = g_new0(PersistState, 1); _init(self, g_strdup(filename), g_strdup_printf("%s-", filename)); return self; } void persist_state_free(PersistState *self) { _destroy(self); g_free(self); } void persist_state_set_global_error_handler(PersistState *self, void (*handler)(gpointer user_data), gpointer user_data) { self->error_handler.handler = handler; self->error_handler.cookie = user_data; } syslog-ng-syslog-ng-4.4.0/lib/persist-state.h000066400000000000000000000104571450431004300211100ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PERSIST_STATE_H_INCLUDED #define PERSIST_STATE_H_INCLUDED #include "syslog-ng.h" typedef struct _PersistFileHeader { union { struct { /* should contain SLP4, everything is Big-Endian */ /* 64 bytes for file header */ gchar magic[4]; /* should be zero, any non-zero value is not supported and causes the state to be dropped */ guint32 flags; /* number of name-value keys in the file */ guint32 key_count; /* space reserved for additional information in the header */ gchar __reserved1[52]; /* initial key store where the first couple of NV keys are stored, sized to align the header to 4k boundary */ gchar initial_key_store[4032]; }; gchar __padding[4096]; }; } PersistFileHeader; typedef guint32 PersistEntryHandle; typedef struct { void (*handler)(gpointer user_data); gpointer cookie; } PersistStateErrorHandler; typedef struct _PersistEntry { PersistEntryHandle ofs; } PersistEntry; struct _PersistState { gint version; gchar *committed_filename; gchar *temp_filename; gint fd; gint mapped_counter; GMutex mapped_lock; GCond mapped_release_cond; guint32 current_size; guint32 current_ofs; gpointer current_map; PersistFileHeader *header; PersistStateErrorHandler error_handler; /* keys being used */ GHashTable *keys; PersistEntryHandle current_key_block; gint current_key_ofs; gint current_key_size; }; typedef struct _PersistState PersistState; gpointer persist_state_map_entry(PersistState *self, PersistEntryHandle handle); void persist_state_unmap_entry(PersistState *self, PersistEntryHandle handle); PersistEntryHandle persist_state_alloc_entry(PersistState *self, const gchar *persist_name, gsize alloc_size); PersistEntryHandle persist_state_lookup_entry(PersistState *self, const gchar *persist_name, gsize *size, guint8 *version); gboolean persist_state_entry_exists(PersistState *self, const gchar *persist_name); gboolean persist_state_remove_entry(PersistState *self, const gchar *persist_name); gchar *persist_state_lookup_string(PersistState *self, const gchar *key, gsize *length, guint8 *version); gboolean persist_state_rename_entry(PersistState *self, const gchar *old_key, const gchar *new_key); gboolean persist_state_move_entry(PersistState *self, const gchar *old_key, const gchar *new_key); void persist_state_alloc_string(PersistState *self, const gchar *persist_name, const gchar *value, gssize len); void persist_state_free_entry(PersistEntryHandle handle); typedef void (*PersistStateForeachFunc)(gchar *name, gint entry_size, gpointer entry, gpointer userdata); void persist_state_foreach_entry(PersistState *self, PersistStateForeachFunc func, gpointer userdata); gboolean persist_state_start(PersistState *self); gboolean persist_state_start_edit(PersistState *self); gboolean persist_state_start_dump(PersistState *self); const gchar *persist_state_get_filename(PersistState *self); gboolean persist_state_commit(PersistState *self); void persist_state_cancel(PersistState *self); PersistState *persist_state_new(const gchar *filename); void persist_state_free(PersistState *self); void persist_state_set_global_error_handler(PersistState *self, void (*handler)(gpointer user_data), gpointer user_data); #endif syslog-ng-syslog-ng-4.4.0/lib/persistable-state-header.h000066400000000000000000000031031450431004300231500ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2012-2013 Viktor Juhasz * Copyright (c) 2012-2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _PERSISTABLE_STATE_HEADER_H #define _PERSISTABLE_STATE_HEADER_H typedef struct _PersistableStateHeader { guint8 version; /* this indicates that the members in the struct are stored in * big-endian byte order. if the byte ordering of the struct doesn't * match the current CPU byte ordering, then the members are * byte-swapped when the state is loaded. * * Every State structure must have it's own byte-order swapping function */ guint8 big_endian:1; } PersistableStateHeader; #endif syslog-ng-syslog-ng-4.4.0/lib/persistable-state-presenter.c000066400000000000000000000034551450431004300237340ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "persistable-state-presenter.h" #include "logmsg/logmsg.h" #include "str-format.h" static GHashTable *persist_state_storage = NULL; PersistableStatePresenterConstructFunc persistable_state_presenter_get_constructor_by_prefix(const gchar *prefix) { PersistableStatePresenterConstructFunc result = NULL; if (persist_state_storage) { result = g_hash_table_lookup(persist_state_storage, prefix); } return result; } void persistable_state_presenter_register_constructor(const gchar *prefix, PersistableStatePresenterConstructFunc handler) { if (!persist_state_storage) { persist_state_storage = g_hash_table_new(g_str_hash, g_str_equal); } g_hash_table_insert(persist_state_storage, (gpointer) prefix, handler); } syslog-ng-syslog-ng-4.4.0/lib/persistable-state-presenter.h000066400000000000000000000053451450431004300237410ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PERSISTABLE_STATE_PRESENTER_H_INCLUDED #define PERSISTABLE_STATE_PRESENTER_H_INCLUDED #include "syslog-ng.h" #include "persist-state.h" #include "presented-persistable-state.h" #include "persistable-state-header.h" struct _PersistableStatePresenter { gboolean (*dump)(PersistableStateHeader *state, PresentedPersistableState *representation); gboolean (*load)(PersistableStateHeader *state, PresentedPersistableState *representation); PersistEntryHandle (*alloc)(PersistState *state, const gchar *name); }; typedef struct _PersistableStatePresenter PersistableStatePresenter; static inline gboolean persistable_state_presenter_load(PersistableStatePresenter *self, PersistableStateHeader *state, PresentedPersistableState *representation) { g_assert(self->load != NULL); return self->load(state, representation); } static inline gboolean persistable_state_presenter_dump(PersistableStatePresenter *self, PersistableStateHeader *state, PresentedPersistableState *representation) { g_assert(self->dump != NULL); return self->dump(state, representation); } static inline PersistEntryHandle persistable_state_presenter_alloc(PersistableStatePresenter *self, PersistState *state, const gchar *name) { g_assert(self->alloc != NULL); return self->alloc(state, name); } typedef PersistableStatePresenter *(*PersistableStatePresenterConstructFunc)(const gchar *name); PersistableStatePresenterConstructFunc persistable_state_presenter_get_constructor_by_prefix(const gchar *prefix); void persistable_state_presenter_register_constructor(const gchar *prefix, PersistableStatePresenterConstructFunc handler); #endif syslog-ng-syslog-ng-4.4.0/lib/plugin-types.h000066400000000000000000000040001450431004300207240ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PLUGIN_TYPES_H_INCLUDED #define PLUGIN_TYPES_H_INCLUDED /* * Plugin types are defined by the configuration grammar (LL_CONTEXT_*) * tokens, but in order to avoid having to directly include cfg-grammar.h * (and for the ensuing WTF comments) define this headers to make it a bit * more visible that the reason for including that is the definition of * those tokens. * * In the future we might as well generate this header file, but for now we * simply poison the namespace with all bison generated macros, as no * practical issue has come up until now. */ #include "cfg-grammar.h" /* bitmask to cover non-context flags in the "plugin_type", e.g. * LL_CONTEXT_FLAG_* */ #define LL_CONTEXT_FLAGS 0xF00 /* indicates that a plugin is actually a generator, e.g. it is registered * as LL_CONTEXT_SOURCE but instead of running through the normal plugin * instantiation via Plugin->parse, let it generate a configuration snippet * that will be parsed normally. */ #define LL_CONTEXT_FLAG_GENERATOR 0x0100 #endif syslog-ng-syslog-ng-4.4.0/lib/plugin.c000066400000000000000000000467151450431004300176000ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "plugin.h" #include "plugin-types.h" #include "messages.h" #include "pathutils.h" #include "resolved-configurable-paths.h" #include #include #ifdef _AIX #undef G_MODULE_SUFFIX #define G_MODULE_SUFFIX "a" #endif #ifdef __APPLE__ #undef G_MODULE_SUFFIX #define G_MODULE_SUFFIX "dylib" #endif static void plugin_candidate_set_module_name(PluginCandidate *self, const gchar *module_name) { g_free(self->module_name); self->module_name = g_strdup(module_name); } PluginCandidate * plugin_candidate_new(gint plugin_type, const gchar *name, const gchar *module_name) { PluginCandidate *self = g_new0(PluginCandidate, 1); self->super.type = plugin_type; self->super.name = g_strdup(name); self->module_name = g_strdup(module_name); self->super.failure_info.aux_data = NULL; return self; } void plugin_candidate_free(PluginCandidate *self) { g_free(self->super.name); g_free(self->module_name); g_free(self); } /* construct a plugin without having a configuration file to parse */ gpointer plugin_construct(Plugin *self) { if (self->construct) { return self->construct(self); } return NULL; } static void plugin_free(Plugin *plugin) { if (plugin->free_fn) plugin->free_fn(plugin); } static gboolean _is_log_pipe(Plugin *self) { switch (self->type) { case LL_CONTEXT_SOURCE: case LL_CONTEXT_DESTINATION: case LL_CONTEXT_PARSER: case LL_CONTEXT_REWRITE: return TRUE; default: return FALSE; } } gpointer plugin_construct_from_config(Plugin *self, CfgLexer *lexer, gpointer arg) { gpointer instance = NULL; g_assert(self->construct == NULL); if (!cfg_parser_parse(self->parser, lexer, &instance, arg)) { cfg_parser_cleanup(self->parser, instance); return NULL; } if (_is_log_pipe(self)) { LogPipe *p = (LogPipe *)instance; p->plugin_name = g_strdup(self->name); if (self->failure_info.aux_data != NULL) p->init = self->failure_info.aux_data; } return instance; } /***************************************************************************** * Implementation of PluginContext *****************************************************************************/ static Plugin * _find_plugin_in_list(GList *head, gint plugin_type, const gchar *plugin_name) { GList *p; Plugin *plugin; gint i; /* this function can only use the first two fields in plugin (type & * name), because it may be supplied a list of PluginCandidate * instances too */ for (p = head; p; p = g_list_next(p)) { plugin = p->data; if (plugin->type == plugin_type) { for (i = 0; plugin->name[i] && plugin_name[i]; i++) { if (plugin->name[i] != plugin_name[i] && !((plugin->name[i] == '-' || plugin->name[i] == '_') && (plugin_name[i] == '-' || plugin_name[i] == '_'))) { break; } } if (plugin_name[i] == 0 && plugin->name[i] == 0) return plugin; } } return NULL; } static ModuleInfo * _get_module_info(GModule *mod) { ModuleInfo *module_info = NULL; if (mod && g_module_symbol(mod, "module_info", (gpointer *) &module_info)) return module_info; return NULL; } static gchar * _format_module_init_name(const gchar *module_name) { gchar *module_init_func; gchar *p; module_init_func = g_strdup_printf("%s_module_init", module_name); for (p = module_init_func; *p; p++) { if ((*p) == '-') *p = '_'; } return module_init_func; } static GModule * _dlopen_module_as_filename(const gchar *module_file_name, const gchar *module_name) { GModule *mod = NULL; msg_trace("Trying to open module", evt_tag_str("module", module_name), evt_tag_str("filename", module_file_name)); mod = g_module_open(module_file_name, G_MODULE_BIND_LAZY); if (!mod) { msg_info("Error opening plugin module", evt_tag_str("module", module_name), evt_tag_str("error", g_module_error())); return NULL; } return mod; } static GModule * _dlopen_module_as_dir_and_filename(const gchar *module_dir_name, const gchar *module_file_name, const gchar *module_name) { gchar *path; GModule *mod; path = g_build_path(G_DIR_SEPARATOR_S, module_dir_name, module_file_name, NULL); mod = _dlopen_module_as_filename(path, module_name); g_free(path); return mod; } static GModule * _dlopen_module_on_path(const gchar *module_name, const gchar *module_path) { gchar *plugin_module_name = NULL; gchar **module_path_dirs, *p, *dot; GModule *mod; gint i; module_path_dirs = g_strsplit(module_path ? : "", G_SEARCHPATH_SEPARATOR_S, 0); i = 0; while (module_path_dirs && module_path_dirs[i]) { plugin_module_name = g_module_build_path(module_path_dirs[i], module_name); if (is_file_regular(plugin_module_name)) break; /* also check if a libtool archive exists (for example in the build directory) */ #ifndef _AIX dot = strrchr(plugin_module_name, '.'); if (dot) { *dot = 0; p = g_strdup_printf("%s.la", plugin_module_name); g_free(plugin_module_name); plugin_module_name = p; } if (is_file_regular(plugin_module_name)) break; /* On AIX the modules in .a files */ #else dot = strrchr(plugin_module_name, '.'); if (dot) { *dot = 0; p = g_strdup_printf("%s.a", plugin_module_name); g_free(plugin_module_name); plugin_module_name = p; } if (is_file_regular(plugin_module_name)) break; #endif #ifdef __APPLE__ /* On Mac the modules are in .dylib files */ dot = strrchr(plugin_module_name, '.'); if (dot) { *dot = 0; p = g_strdup_printf("%s.dylib", plugin_module_name); g_free(plugin_module_name); plugin_module_name = p; } if (is_file_regular(plugin_module_name)) break; #endif g_free(plugin_module_name); plugin_module_name = NULL; i++; } g_strfreev(module_path_dirs); if (!plugin_module_name) { msg_error("Plugin module not found in 'module-path'", evt_tag_str("module-path", module_path), evt_tag_str("module", module_name)); return NULL; } mod = _dlopen_module_as_filename(plugin_module_name, module_name); g_free(plugin_module_name); return mod; } void plugin_register(PluginContext *context, Plugin *p, gint number) { gint i; for (i = 0; i < number; i++) { Plugin *existing_plugin; existing_plugin = _find_plugin_in_list(context->plugins, p[i].type, p[i].name); if (existing_plugin) { msg_debug("Attempted to register the same plugin multiple times, dropping the old one", evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(p[i].type)), evt_tag_str("name", p[i].name)); plugin_free(existing_plugin); context->plugins = g_list_remove(context->plugins, existing_plugin); } context->plugins = g_list_prepend(context->plugins, &p[i]); } } Plugin * plugin_find(PluginContext *context, gint plugin_type, const gchar *plugin_name) { Plugin *p; PluginCandidate *candidate; /* try registered plugins first */ p = _find_plugin_in_list(context->plugins, plugin_type, plugin_name); if (p) { return p; } candidate = (PluginCandidate *) _find_plugin_in_list(context->candidate_plugins, plugin_type, plugin_name); if (!candidate) return NULL; /* try to autoload the module */ plugin_load_module(context, candidate->module_name, NULL); /* by this time it should've registered */ p = _find_plugin_in_list(context->plugins, plugin_type, plugin_name); if (p) { p->failure_info.aux_data = candidate->super.failure_info.aux_data; return p; } else { msg_error("This module claims to support a plugin, which it didn't register after loading", evt_tag_str("module", candidate->module_name), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(plugin_type)), evt_tag_str("name", plugin_name)); } return NULL; } gboolean plugin_load_module(PluginContext *context, const gchar *module_name, CfgArgs *args) { GModule *mod; static GModule *main_module_handle; gboolean (*init_func)(PluginContext *context, CfgArgs *args); gchar *module_init_func; gboolean result; ModuleInfo *module_info; /* lookup in the main executable */ if (!main_module_handle) main_module_handle = g_module_open(NULL, 0); module_init_func = _format_module_init_name(module_name); if (g_module_symbol(main_module_handle, module_init_func, (gpointer *) &init_func)) { /* already linked in, no need to load explicitly */ goto call_init; } /* try to load it from external .so */ mod = _dlopen_module_on_path(module_name, context->module_path); if (!mod) { g_free(module_init_func); return FALSE; } g_module_make_resident(mod); module_info = _get_module_info(mod); if (module_info->canonical_name) { g_free(module_init_func); module_init_func = _format_module_init_name(module_info->canonical_name ? : module_name); } if (!g_module_symbol(mod, module_init_func, (gpointer *) &init_func)) { msg_error("Error finding init function in module", evt_tag_str("module", module_name), evt_tag_str("symbol", module_init_func), evt_tag_str("error", g_module_error())); g_free(module_init_func); return FALSE; } call_init: g_free(module_init_func); result = (*init_func)(context, args); if (result) msg_verbose("Module loaded and initialized successfully", evt_tag_str("module", module_name)); else msg_error("Module initialization failed", evt_tag_str("module", module_name)); return result; } gboolean plugin_is_module_available(PluginContext *context, const gchar *module_name) { for (GList *l = context->candidate_plugins; l; l = l->next) { PluginCandidate *pc = (PluginCandidate *) l->data; if (strcmp(pc->module_name, module_name) == 0) return TRUE; } return FALSE; } gboolean plugin_is_plugin_available(PluginContext *context, gint plugin_type, const gchar *plugin_name) { Plugin *p; PluginCandidate *candidate; p = _find_plugin_in_list(context->plugins, plugin_type, plugin_name); if (p) return TRUE; candidate = (PluginCandidate *) _find_plugin_in_list(context->candidate_plugins, plugin_type, plugin_name); return !!candidate; } /************************************************************ * Candidate modules ************************************************************/ static void _free_candidate_plugins(PluginContext *context) { g_list_foreach(context->candidate_plugins, (GFunc) plugin_candidate_free, NULL); g_list_free(context->candidate_plugins); context->candidate_plugins = NULL; } gboolean plugin_has_discovery_run(PluginContext *context) { return context->candidate_plugins != NULL; } void plugin_discover_candidate_modules(PluginContext *context) { GModule *mod; gchar **mod_paths; gint i, j; _free_candidate_plugins(context); mod_paths = g_strsplit(context->module_path ? : "", G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; mod_paths[i]; i++) { GDir *dir; const gchar *fname; msg_debug("Reading path for candidate modules", evt_tag_str("path", mod_paths[i])); dir = g_dir_open(mod_paths[i], 0, NULL); if (!dir) continue; while ((fname = g_dir_read_name(dir))) { if (g_str_has_suffix(fname, G_MODULE_SUFFIX)) { gchar *module_name; ModuleInfo *module_info; const gchar *so_basename = fname; if (g_str_has_prefix(fname, "lib")) so_basename = fname + 3; module_name = g_strndup(so_basename, (gint) (strlen(so_basename) - strlen(G_MODULE_SUFFIX) - 1)); msg_debug("Reading shared object for a candidate module", evt_tag_str("path", mod_paths[i]), evt_tag_str("fname", fname), evt_tag_str("module", module_name)); mod = _dlopen_module_as_dir_and_filename(mod_paths[i], fname, module_name); module_info = _get_module_info(mod); if (module_info) { for (j = 0; j < module_info->plugins_len; j++) { Plugin *plugin = &module_info->plugins[j]; PluginCandidate *candidate_plugin; candidate_plugin = (PluginCandidate *) _find_plugin_in_list(context->candidate_plugins, plugin->type, plugin->name); msg_debug("Registering candidate plugin", evt_tag_str("module", module_name), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(plugin->type)), evt_tag_str("name", plugin->name)); if (candidate_plugin) { msg_debug("Duplicate plugin candidate, overriding previous registration with the new one", evt_tag_str("old-module", candidate_plugin->module_name), evt_tag_str("new-module", module_name), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(plugin->type)), evt_tag_str("name", plugin->name)); plugin_candidate_set_module_name(candidate_plugin, module_name); } else { context->candidate_plugins = g_list_prepend(context->candidate_plugins, plugin_candidate_new(plugin->type, plugin->name, module_name)); } } } g_free(module_name); if (mod) g_module_close(mod); else mod = NULL; } } g_dir_close(dir); } g_strfreev(mod_paths); } static void _free_plugins(PluginContext *context) { g_list_foreach(context->plugins, (GFunc) plugin_free, NULL); g_list_free(context->plugins); context->plugins = NULL; } void plugin_context_copy_candidates(PluginContext *context, PluginContext *from) { GList *l; for (l = from->candidate_plugins; l; l = l->next) { PluginCandidate *pc = (PluginCandidate *) l->data; context->candidate_plugins = g_list_prepend(context->candidate_plugins, plugin_candidate_new(pc->super.type, pc->super.name, pc->module_name)); } } void plugin_context_set_module_path(PluginContext *context, const gchar *module_path) { g_free(context->module_path); context->module_path = g_strdup(module_path); } void plugin_context_init_instance(PluginContext *context) { memset(context, 0, sizeof(*context)); plugin_context_set_module_path(context, resolved_configurable_paths.initial_module_path); } void plugin_context_deinit_instance(PluginContext *context) { _free_plugins(context); _free_candidate_plugins(context); g_free(context->module_path); } /* global functions */ void plugin_list_modules(FILE *out, gboolean verbose) { GModule *mod; gchar **mod_paths; gint i, j, k; gboolean first = TRUE; mod_paths = g_strsplit(resolved_configurable_paths.initial_module_path, ":", 0); for (i = 0; mod_paths[i]; i++) { GDir *dir; const gchar *fname; dir = g_dir_open(mod_paths[i], 0, NULL); if (!dir) continue; while ((fname = g_dir_read_name(dir))) { if (g_str_has_suffix(fname, G_MODULE_SUFFIX)) { gchar *module_name; ModuleInfo *module_info; const gchar *so_basename = fname; if (g_str_has_prefix(fname, "lib")) so_basename = fname + 3; module_name = g_strndup(so_basename, (gint) (strlen(so_basename) - strlen(G_MODULE_SUFFIX) - 1)); mod = _dlopen_module_as_dir_and_filename(mod_paths[i], fname, module_name); module_info = _get_module_info(mod); if (verbose) { fprintf(out, "Module: %s\n", module_name); if (mod) { if (!module_info) { fprintf(out, "Status: Unable to resolve module_info variable, probably not a syslog-ng module\n"); } else { gchar **lines; fprintf(out, "Status: ok\n" "Version: %s\n" "Core-Revision: %s\n" "Description:\n", module_info->version, module_info->core_revision); lines = g_strsplit(module_info->description, "\n", 0); for (k = 0; lines[k]; k++) fprintf(out, " %s\n", lines[k][0] ? lines[k] : "."); g_strfreev(lines); fprintf(out, "Plugins:\n"); for (j = 0; j < module_info->plugins_len; j++) { Plugin *plugin = &module_info->plugins[j]; fprintf(out, " %-15s %s\n", cfg_lexer_lookup_context_name_by_type(plugin->type), plugin->name); } } } else { fprintf(out, "Status: Unable to dlopen shared object, probably not a syslog-ng module\n"); } fprintf(out, "\n"); } else if (module_info) { fprintf(out, "%s%s", first ? "" : ",", module_name); first = FALSE; } g_free(module_name); if (mod) g_module_close(mod); } } g_dir_close(dir); } g_strfreev(mod_paths); if (!verbose) fprintf(out, "\n"); } syslog-ng-syslog-ng-4.4.0/lib/plugin.h000066400000000000000000000102061450431004300175670ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PLUGIN_H_INCLUDED #define PLUGIN_H_INCLUDED #include "cfg-parser.h" typedef struct _PluginFailureInfo { gconstpointer aux_data; } PluginFailureInfo; typedef struct _PluginBase { /* NOTE: the start of this structure must match the Plugin struct, thus it has to be changed together with Plugin */ gint type; gchar *name; PluginFailureInfo failure_info; } PluginBase; typedef struct _PluginCandidate { PluginBase super; gchar *module_name; } PluginCandidate; /* A plugin actually registered by a module. See PluginCandidate in * the implementation module, which encapsulates a demand-loadable * plugin, not yet loaded. * * A plugin serves as the factory for an extension point (=plugin). In * contrast with the "module" which is the shared object itself which * registers plugins. Each module can register a number of plugins, * not just one. */ typedef struct _Plugin Plugin; struct _Plugin { /* NOTE: the first three fields must match PluginCandidate struct defined in the plugin.c module, please modify them both at the same time! It is not referenced as "super" as it would make the using sites having to use ugly braces when initializing the structure. */ gint type; const gchar *name; PluginFailureInfo failure_info; CfgParser *parser; gpointer (*construct)(Plugin *self); void (*free_fn)(Plugin *s); }; gpointer plugin_construct(Plugin *self); gpointer plugin_construct_from_config(Plugin *self, CfgLexer *lexer, gpointer arg); typedef struct _ModuleInfo ModuleInfo; struct _ModuleInfo { /* name of the module to be loaded as */ const gchar *canonical_name; /* version number if any */ const gchar *version; /* copyright information, homepage and other important information about the module */ const gchar *description; /* git sha that identifies the core revision that this was compiled for */ const gchar *core_revision; Plugin *plugins; gint plugins_len; /* the higher the better */ }; struct _PluginContext { GList *plugins; GList *candidate_plugins; gchar *module_path; }; /* instantiate a new plugin */ Plugin *plugin_find(PluginContext *context, gint plugin_type, const gchar *plugin_name); /* plugin side API */ PluginCandidate *plugin_candidate_new(gint plugin_type, const gchar *name, const gchar *module_name); void plugin_candidate_free(PluginCandidate *self); void plugin_register(PluginContext *context, Plugin *p, gint number); gboolean plugin_load_module(PluginContext *context, const gchar *module_name, CfgArgs *args); gboolean plugin_is_plugin_available(PluginContext *context, gint plugin_type, const gchar *plugin_name); gboolean plugin_is_module_available(PluginContext *context, const gchar *module_name); void plugin_list_modules(FILE *out, gboolean verbose); gboolean plugin_has_discovery_run(PluginContext *context); void plugin_discover_candidate_modules(PluginContext *context); void plugin_context_copy_candidates(PluginContext *context, PluginContext *src_context); void plugin_context_set_module_path(PluginContext *context, const gchar *module_path); void plugin_context_init_instance(PluginContext *context); void plugin_context_deinit_instance(PluginContext *context); #endif syslog-ng-syslog-ng-4.4.0/lib/poll-events.c000066400000000000000000000026341450431004300205420ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "poll-events.h" void poll_events_invoke_callback(PollEvents *self) { self->callback(self->callback_data); } void poll_events_set_callback(PollEvents *self, PollCallback callback, gpointer user_data) { self->callback = callback; self->callback_data = user_data; } void poll_events_init(PollEvents *self) { } void poll_events_free(PollEvents *self) { if (self->free_fn) self->free_fn(self); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/poll-events.h000066400000000000000000000043001450431004300205370ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef POLL_EVENTS_H_INCLUDED #define POLL_EVENTS_H_INCLUDED #include "syslog-ng.h" typedef struct _PollEvents PollEvents; typedef void (*PollCallback)(gpointer user_data); struct _PollEvents { PollCallback callback; gpointer callback_data; void (*start_watches)(PollEvents *self); void (*stop_watches)(PollEvents *self); void (*update_watches)(PollEvents *self, GIOCondition cond); void (*suspend_watches)(PollEvents *self); void (*free_fn)(PollEvents *self); }; static inline void poll_events_start_watches(PollEvents *self) { if (self->start_watches) self->start_watches(self); } static inline void poll_events_stop_watches(PollEvents *self) { self->stop_watches(self); } static inline void poll_events_update_watches(PollEvents *self, GIOCondition cond) { self->update_watches(self, cond); } static inline void poll_events_suspend_watches(PollEvents *self) { if (self->suspend_watches) return self->suspend_watches(self); poll_events_stop_watches(self); } void poll_events_invoke_callback(PollEvents *self); void poll_events_set_callback(PollEvents *self, PollCallback callback, gpointer user_data); void poll_events_init(PollEvents *self); void poll_events_free(PollEvents *self); #endif syslog-ng-syslog-ng-4.4.0/lib/poll-fd-events.c000066400000000000000000000053001450431004300211220ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "poll-fd-events.h" #include typedef struct _PollFdEvents { PollEvents super; struct iv_fd fd_watch; } PollFdEvents; #define IV_FD_CALLBACK(x) ((void (*)(void *)) (x)) static void poll_fd_events_start_watches(PollEvents *s) { PollFdEvents *self = (PollFdEvents *) s; iv_fd_register(&self->fd_watch); } static void poll_fd_events_stop_watches(PollEvents *s) { PollFdEvents *self = (PollFdEvents *) s; if (iv_fd_registered(&self->fd_watch)) iv_fd_unregister(&self->fd_watch); } static void poll_fd_events_suspend_watches(PollEvents *s) { PollFdEvents *self = (PollFdEvents *) s; iv_fd_set_handler_in(&self->fd_watch, NULL); iv_fd_set_handler_out(&self->fd_watch, NULL); iv_fd_set_handler_err(&self->fd_watch, NULL); } static void poll_fd_events_update_watches(PollEvents *s, GIOCondition cond) { PollFdEvents *self = (PollFdEvents *) s; poll_events_suspend_watches(s); if (cond & G_IO_IN) iv_fd_set_handler_in(&self->fd_watch, IV_FD_CALLBACK(poll_events_invoke_callback)); if (cond & G_IO_OUT) iv_fd_set_handler_out(&self->fd_watch, IV_FD_CALLBACK(poll_events_invoke_callback)); if (cond & (G_IO_IN + G_IO_OUT)) iv_fd_set_handler_err(&self->fd_watch, IV_FD_CALLBACK(poll_events_invoke_callback)); } PollEvents * poll_fd_events_new(gint fd) { PollFdEvents *self = g_new0(PollFdEvents, 1); g_assert(fd >= 0); self->super.start_watches = poll_fd_events_start_watches; self->super.stop_watches = poll_fd_events_stop_watches; self->super.update_watches = poll_fd_events_update_watches; self->super.suspend_watches = poll_fd_events_suspend_watches; IV_FD_INIT(&self->fd_watch); self->fd_watch.fd = fd; self->fd_watch.cookie = self; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/poll-fd-events.h000066400000000000000000000021741450431004300211350ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef POLL_FD_EVENTS_H_INCLUDED #define POLL_FD_EVENTS_H_INCLUDED #include "poll-events.h" PollEvents *poll_fd_events_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/pragma-grammar.ym000066400000000000000000000137011450431004300213650ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #pragma GCC diagnostic ignored "-Wswitch-default" #include "pragma-parser.h" #include "plugin.h" #include "cfg.h" #include "messages.h" #include } %define api.prefix {pragma_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {gpointer *result} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_VERSION %token KW_VERSION_CURRENT %token KW_DEFINE %token KW_MODULE %token KW_REQUIRES %token KW_LINE %token KW_CONFIG_ID %code { #include #define PRAGMA_BEGIN() ({ lexer->tokenize_eol++; }) #define PRAGMA_END() ({ lexer->tokenize_eol--; }) #define PRAGMA_ERROR() ({ PRAGMA_END(); YYERROR; }) CfgArgs *last_module_args = NULL; static void _report_define_deprecations(const gchar *name, const gchar *value) { if (strcmp(name, "autoload-compiled-modules") == 0 && atoi(value) == 0) msg_warning("WARNING: disabling plugin discovery via the autoload-compiled-modules " "@define has become unsupported in " VERSION_3_37 ", use the syslog-ng command line option --no-module-discovery instead"); else if (strcmp(name, "module-path") == 0) msg_warning("WARNING: changing the path to runtime loaded modules via the module-path " "@define has become unsupported in " VERSION_3_37 ", use the command line option --module-path instead"); } static void pragma_define_global(GlobalConfig *cfg, const gchar *name, const gchar *value) { msg_debug("Global value changed", evt_tag_str("define", name), evt_tag_str("value", value)); _report_define_deprecations(name, value); cfg_args_set(cfg->globals, name, value); } } %type requires_message %% start : { PRAGMA_BEGIN(); } stmt { if (yychar != PRAGMA_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } PRAGMA_END(); YYACCEPT; } stmt : stmt_without_eol LL_EOL | stmt_with_eol ; stmt_without_eol : version_stmt | define_stmt | module_stmt | config_id_stmt ; /* LL_EOL as a token needs to be consumed by the rules below, as they can * change the lexer buffer by the time they return to the grammar. */ stmt_with_eol : include_stmt | requires_stmt | line_stmt ; version_stmt : KW_VERSION ':' KW_VERSION_CURRENT { if (!cfg_set_current_version(configuration)) PRAGMA_ERROR(); } | KW_VERSION ':' string_or_number { guint parsed_version = process_version_string($3); free($3); if (parsed_version == 0) PRAGMA_ERROR(); if (!cfg_set_version(configuration, parsed_version)) PRAGMA_ERROR(); } define_stmt : KW_DEFINE LL_IDENTIFIER string_or_number { pragma_define_global(configuration, $2, $3); free($2); free($3); } module_stmt : KW_MODULE string { last_module_args = cfg_args_new(); } module_params { gboolean success = cfg_load_module_with_args(configuration, $2, last_module_args); free($2); cfg_args_unref(last_module_args); last_module_args = NULL; if (!success) PRAGMA_ERROR(); } ; module_params : module_param module_params | ; module_param : LL_IDENTIFIER '(' string_or_number ')' { cfg_args_set(last_module_args, $1, $3); free($1); free($3); } ; config_id_stmt : KW_CONFIG_ID ':' string_or_number { cfg_set_user_config_id(configuration, $3); free($3); } include_stmt : KW_INCLUDE string LL_EOL { CHECK_ERROR(cfg_lexer_include_file(lexer, $2), @2, "Error including %s", $2); free($2); } ; requires_stmt : KW_REQUIRES string requires_message LL_EOL { if (!cfg_is_module_available(configuration, $2)) { if (0 == lexer->include_depth || $3) { msg_error("Cannot load required module", evt_tag_str("module", $2), evt_tag_str("details", $3 ? : "none"), cfg_lexer_format_location_tag(lexer,&@1)); free($2); PRAGMA_ERROR(); } else { msg_debug("Included file was skipped because of a missing module", evt_tag_str("module", $2), cfg_lexer_format_location_tag(lexer,&@1)); cfg_lexer_start_next_include(lexer); } } free($2); } ; requires_message : string { $$ = $1; } | { $$ = NULL; } ; line_stmt : KW_LINE string positive_integer positive_integer LL_EOL { cfg_lexer_set_file_location(lexer, $2, $3, $4); free($2); } /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/pragma-parser.c000066400000000000000000000046161450431004300210350ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pragma-parser.h" #include "pragma-grammar.h" #include extern int pragma_debug; int pragma_parse(CfgLexer *lexer, gpointer *result, gpointer arg); guint process_version_string(gchar *value) { gchar *p, *end; gint major, minor; if (strlen(value) > strlen("xxx.yyy")) return 0; if (value[0] == '+' || value[0] == '-') return 0; p = strchr(value, '.'); if (p == value) return 0; if (p) { major = strtol(value, &end, 10); if (major < 0) return 0; if (end == p) { minor = strtol(p+1, &end, 10); if (minor < 0) return 0; if (*end == '\0') { return (major << 8) + minor; } } } return 0; } static CfgLexerKeyword pragma_keywords[] = { { "version", KW_VERSION, }, { "current", KW_VERSION_CURRENT }, { "include", KW_INCLUDE, }, { "module", KW_MODULE, }, { "define", KW_DEFINE, }, { "requires", KW_REQUIRES, }, { "line", KW_LINE }, { "config_id", KW_CONFIG_ID }, { CFG_KEYWORD_STOP }, }; CfgParser pragma_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &pragma_debug, #endif .name = "pragma", .context = LL_CONTEXT_PRAGMA, .keywords = pragma_keywords, .parse = pragma_parse, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(pragma_, PRAGMA_, gpointer *) syslog-ng-syslog-ng-4.4.0/lib/pragma-parser.h000066400000000000000000000023361450431004300210370ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PRAGMA_PARSER_H_INCLUDED #define PRAGMA_PARSER_H_INCLUDED #include "cfg-parser.h" extern CfgParser pragma_parser; guint process_version_string(gchar *value); CFG_PARSER_DECLARE_LEXER_BINDING(pragma_, PRAGMA_, gpointer *) #endif syslog-ng-syslog-ng-4.4.0/lib/presented-persistable-state.h000066400000000000000000000075421450431004300237240ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PRESENTED_PERSISTABLE_STATE_H_INCLUDED #define PRESENTED_PERSISTABLE_STATE_H_INCLUDED #include "syslog-ng.h" typedef struct _PresentedPersistableState PresentedPersistableState; struct _PresentedPersistableState { void (*add_string)(PresentedPersistableState *self, gchar *name, gchar *value); void (*add_boolean)(PresentedPersistableState *self, gchar *name, gboolean value); void (*add_int64)(PresentedPersistableState *self, gchar *name, gint64 value); void (*add_int)(PresentedPersistableState *self, gchar *name, gint value); const gchar *(*get_string)(PresentedPersistableState *self, gchar *name); gboolean (*get_boolean)(PresentedPersistableState *self, gchar *name); gint (*get_int)(PresentedPersistableState *self, gchar *name); gint64 (*get_int64)(PresentedPersistableState *self, gchar *name); void (*foreach)(PresentedPersistableState *self, void (callback)(gchar *name, const gchar *value, gpointer user_data), gpointer user_data); gboolean (*does_name_exist)(PresentedPersistableState *self, gchar *name); void (*free)(PresentedPersistableState *self); }; static inline void presented_persistable_state_add_string(PresentedPersistableState *self, gchar *name, gchar *value) { self->add_string(self, name, value); } static inline void presented_persistable_state_add_boolean(PresentedPersistableState *self, gchar *name, gboolean value) { self->add_boolean(self, name, value); } static inline void presented_persistable_state_add_int(PresentedPersistableState *self, gchar *name, gint value) { self->add_int(self, name, value); } static inline void presented_persistable_state_add_int64(PresentedPersistableState *self, gchar *name, gint64 value) { self->add_int64(self, name, value); } static inline const gchar * presented_persistable_state_get_string(PresentedPersistableState *self, gchar *name) { return self->get_string(self, name); } static inline gboolean presented_persistable_state_get_boolean(PresentedPersistableState *self, gchar *name) { return self->get_boolean(self, name); } static inline gint presented_persistable_state_get_int(PresentedPersistableState *self, gchar *name) { return self->get_int(self, name); } static inline gint64 presented_persistable_state_get_int64(PresentedPersistableState *self, gchar *name) { return self->get_int64(self, name); } static inline void presented_persistable_state_foreach(PresentedPersistableState *self, void (callback)(gchar *name, const gchar *value, gpointer user_data), gpointer user_data) { self->foreach(self, callback, user_data); } static inline gboolean presented_persistable_state_does_name_exist(PresentedPersistableState *self, gchar *name) { return self->does_name_exist(self, name); } static inline void presented_persistable_state_free(PresentedPersistableState *self) { self->free(self); } #endif syslog-ng-syslog-ng-4.4.0/lib/rcptid.c000066400000000000000000000106541450431004300175600ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rcptid.h" #include "messages.h" #include "str-format.h" static struct _RcptidService { PersistState *persist_state; PersistEntryHandle persist_handle; GMutex lock; } rcptid_service; /* NOTE: RcptIdInstance is a singleton, so we don't pass self around as an argument */ #define self (&rcpt_instance) static RcptidState * rcptid_map_state(void) { return (RcptidState *) persist_state_map_entry(rcptid_service.persist_state, rcptid_service.persist_handle); } static void rcptid_unmap_state(void) { persist_state_unmap_entry(rcptid_service.persist_state, rcptid_service.persist_handle); } static gboolean rcptid_is_initialized(void) { return rcptid_service.persist_state != NULL; } static gboolean rcptid_restore_entry(void) { RcptidState *data = rcptid_map_state(); if (data->header.version > 0) { msg_error("Internal error restoring log reader state, stored data is too new", evt_tag_int("version", data->header.version)); rcptid_unmap_state(); return FALSE; } if ((data->header.big_endian && G_BYTE_ORDER == G_LITTLE_ENDIAN) || (!data->header.big_endian && G_BYTE_ORDER == G_BIG_ENDIAN)) { data->header.big_endian = !data->header.big_endian; data->g_rcptid = GUINT64_SWAP_LE_BE(data->g_rcptid); } rcptid_unmap_state(); return TRUE; } static gboolean rcptid_create_new_entry(void) { RcptidState *data; rcptid_service.persist_handle = persist_state_alloc_entry(rcptid_service.persist_state, "next.rcptid", sizeof(RcptidState)); if (!rcptid_service.persist_handle) { msg_error("Error allocating RCPTID structure in persist-state"); return FALSE; } data = rcptid_map_state(); data->header.version = 0; data->header.big_endian = (G_BYTE_ORDER == G_BIG_ENDIAN); data->g_rcptid = 1; rcptid_unmap_state(); return TRUE; } void rcptid_append_formatted_id(GString *result, guint64 rcptid) { if (rcptid) { format_uint64_padded(result, 0, 0, 10, rcptid); } } void rcptid_set_id(guint64 id) { RcptidState *data; if (!rcptid_is_initialized()) return; g_mutex_lock(&rcptid_service.lock); data = rcptid_map_state(); data->g_rcptid = id; rcptid_unmap_state(); g_mutex_unlock(&rcptid_service.lock); } guint64 rcptid_generate_id(void) { RcptidState *data; guint64 new_id; if (!rcptid_is_initialized()) return 0; g_mutex_lock(&rcptid_service.lock); data = rcptid_map_state(); new_id = data->g_rcptid++; if (data->g_rcptid == 0) data->g_rcptid = 1; rcptid_unmap_state(); g_mutex_unlock(&rcptid_service.lock); return new_id; } /*restore RCTPID from persist file, if possible, else create new entry point with "next.rcptid" name*/ gboolean rcptid_init(PersistState *state, gboolean use_rcptid) { gsize size; guint8 version; g_assert(rcptid_service.persist_state == NULL); if (!use_rcptid) return TRUE; rcptid_service.persist_state = state; rcptid_service.persist_handle = persist_state_lookup_entry(state, "next.rcptid", &size, &version); if (rcptid_service.persist_handle && size == sizeof(RcptidState)) { return rcptid_restore_entry(); } else { if (rcptid_service.persist_handle) msg_warning("rcpt-id: persist state: invalid size, allocating a new one"); return rcptid_create_new_entry(); } } void rcptid_deinit(void) { rcptid_service.persist_state = NULL; } syslog-ng-syslog-ng-4.4.0/lib/rcptid.h000066400000000000000000000027151450431004300175640ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _RCPTID_H #define _RCPTID_H #include "syslog-ng.h" #include "persist-state.h" #include "persistable-state-header.h" typedef struct _RcptidState { PersistableStateHeader header; guint64 g_rcptid; } RcptidState; void rcptid_set_id(guint64 id); guint64 rcptid_generate_id(void); void rcptid_append_formatted_id(GString *result, guint64 rcptid); gboolean rcptid_init(PersistState *state, gboolean use_rcptid); void rcptid_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/reloc.c000066400000000000000000000136031450431004300173740ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "reloc.h" #include "cache.h" #include #include #include Cache *path_cache; typedef struct _PathResolver { CacheResolver super; GHashTable *configure_variables; } PathResolver; void path_resolver_add_configure_variable(CacheResolver *s, const gchar *name, const gchar *value) { PathResolver *self = (PathResolver *) s; g_hash_table_insert(self->configure_variables, g_strdup(name), g_strdup(value)); } static void path_resolver_populate_configure_variables(PathResolver *self, const gchar *sysprefix) { path_resolver_add_configure_variable(&self->super, "${prefix}", sysprefix); path_resolver_add_configure_variable(&self->super, "${exec_prefix}", SYSLOG_NG_PATH_EXECPREFIX); path_resolver_add_configure_variable(&self->super, "${libexecdir}", SYSLOG_NG_PATH_LIBEXECDIR); path_resolver_add_configure_variable(&self->super, "${datarootdir}", SYSLOG_NG_PATH_DATAROOTDIR); path_resolver_add_configure_variable(&self->super, "${datadir}", SYSLOG_NG_PATH_DATADIR); path_resolver_add_configure_variable(&self->super, "${pkgdatadir}", SYSLOG_NG_PATH_PKGDATADIR); path_resolver_add_configure_variable(&self->super, "${localstatedir}", SYSLOG_NG_PATH_LOCALSTATEDIR); path_resolver_add_configure_variable(&self->super, "${moduledir}", SYSLOG_NG_PATH_MODULEDIR); } /* NOTE: we really don't have an easy way to handle errors, as installation * paths are resolved quite early while syslog-ng starts up. The best is to * abort, as an error is either a problem in the configure variables OR a * coding mistake. For now, we desperately try to write an error message to * stderr and then abort the process. */ #define handle_fatal_error(fmt, ...) \ do { \ fprintf(stderr, fmt, __VA_ARGS__); \ g_assert_not_reached(); \ } while (0) gpointer path_resolver_resolve(CacheResolver *s, const gchar *orig) { PathResolver *self = (PathResolver *) s; gchar *subst_start = NULL; gchar *subst_end = NULL; gchar *new_value, *prefix, *suffix, *replacement, *value; gchar *confvar; gint prefix_len, confvar_len; /* Find variable enclosed within ${...}, replace with the value in * configure_variables. Repeat until no more substitutions can be made. * */ value = g_strdup(orig); subst_start = strstr(value, "${"); while (subst_start != NULL) { prefix = NULL; prefix_len = 0; suffix = NULL; subst_end = strchr(subst_start, '}'); if (subst_end == NULL) handle_fatal_error("Relocation resolution error: missing '}' in string '%s'. Please re-compile syslog-ng with proper path variables.\n", value); /* extract confvar */ confvar_len = (subst_end + 1) - subst_start; confvar = g_strndup(subst_start, confvar_len); /* lookup replacement */ replacement = g_hash_table_lookup(self->configure_variables, confvar); if (replacement == NULL) handle_fatal_error("Relocation resolution error: Unknown configure variable: '%s' in string '%s'.\nPlease re-compile syslog-ng with proper path variables.\n", confvar, value); g_free(confvar); /* replace confvar with replacement */ suffix = (subst_end + 1); prefix_len = subst_start - value; prefix = g_strndup(value, prefix_len); /* construct the new value */ new_value = g_strconcat(prefix, replacement, suffix, NULL); g_free(prefix); /* commit the new value */ g_free(value); value = new_value; subst_start = strstr(value, "${"); } return value; } static void path_resolver_free(CacheResolver *s) { PathResolver *self = (PathResolver *) s; g_hash_table_unref(self->configure_variables); } CacheResolver * path_resolver_new(const gchar *sysprefix) { PathResolver *self = g_new0(PathResolver, 1); self->super.resolve_elem = path_resolver_resolve; self->super.free_elem = g_free; self->super.free_fn = path_resolver_free; self->configure_variables = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); path_resolver_populate_configure_variables(self, sysprefix); return &self->super; } static const gchar * lookup_sysprefix(void) { gchar *v; v = getenv("SYSLOGNG_PREFIX"); if (v) return v; return SYSLOG_NG_PATH_PREFIX; } const gchar * get_installation_path_for(const gchar *template) { reloc_init(); return cache_lookup(path_cache, template); } gchar * resolve_path_variables_in_text(const gchar *text) { reloc_init(); return cache_resolve(path_cache, text); } /* NOTE: to be used in test programs only to override paths to external files */ void override_installation_path_for(const gchar *template, const gchar *value) { reloc_init(); cache_populate(path_cache, template, value); } void reloc_init(void) { if (!path_cache) path_cache = cache_new(path_resolver_new(lookup_sysprefix())); } void reloc_deinit(void) { if (path_cache) { cache_free(path_cache); path_cache = NULL; } } syslog-ng-syslog-ng-4.4.0/lib/reloc.h000066400000000000000000000027011450431004300173760ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef RELOC_H_INCLUDED #define RELOC_H_INCLUDED #include "syslog-ng.h" #include "cache.h" void path_resolver_add_configure_variable(CacheResolver *self, const gchar *name, const gchar *value); CacheResolver *path_resolver_new(const gchar *sysprefix); gchar *resolve_path_variables_in_text(const gchar *text); const gchar *get_installation_path_for(const gchar *template); void override_installation_path_for(const gchar *template, const gchar *value); void reloc_init(void); void reloc_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/resolved-configurable-paths.c000066400000000000000000000030311450431004300236600ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "resolved-configurable-paths.h" #include "reloc.h" ResolvedConfigurablePaths resolved_configurable_paths; void resolved_configurable_paths_init(ResolvedConfigurablePaths *self) { resolved_configurable_paths.cfgfilename = get_installation_path_for(PATH_SYSLOG_NG_CONF); resolved_configurable_paths.persist_file = get_installation_path_for(PATH_PERSIST_CONFIG); resolved_configurable_paths.ctlfilename = get_installation_path_for(PATH_CONTROL_SOCKET); resolved_configurable_paths.initial_module_path = get_installation_path_for(SYSLOG_NG_MODULE_PATH); } syslog-ng-syslog-ng-4.4.0/lib/resolved-configurable-paths.h000066400000000000000000000026421450431004300236740ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef RESOLVED_CONFIGURABLE_PATHS_H_INCLUDED #define RESOLVED_CONFIGURABLE_PATHS_H_INCLUDED #include typedef struct _ResolvedConfigurablePaths { const gchar *cfgfilename; const gchar *persist_file; const gchar *ctlfilename; const gchar *initial_module_path; } ResolvedConfigurablePaths; extern ResolvedConfigurablePaths resolved_configurable_paths; void resolved_configurable_paths_init(ResolvedConfigurablePaths *self); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/000077500000000000000000000000001450431004300176025ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/rewrite/CMakeLists.txt000066400000000000000000000016331450431004300223450ustar00rootroot00000000000000set(REWRITE_HEADERS rewrite/rewrite-expr.h rewrite/rewrite-set-tag.h rewrite/rewrite-set.h rewrite/rewrite-subst.h rewrite/rewrite-expr-parser.h rewrite/rewrite-groupset.h rewrite/rewrite-unset.h rewrite/rewrite-rename.h rewrite/rewrite-set-matches.h rewrite/rewrite-unset-matches.h rewrite/rewrite-set-pri.h rewrite/rewrite-set-severity.h rewrite/rewrite-set-facility.h PARENT_SCOPE ) set(REWRITE_SOURCES rewrite/rewrite-expr.c rewrite/rewrite-set-tag.c rewrite/rewrite-set.c rewrite/rewrite-subst.c rewrite/rewrite-expr-parser.c rewrite/rewrite-groupset.c rewrite/rewrite-unset.c rewrite/rewrite-rename.c rewrite/rewrite-set-matches.c rewrite/rewrite-unset-matches.c rewrite/rewrite-set-pri.c rewrite/rewrite-set-severity.c rewrite/rewrite-set-facility.c PARENT_SCOPE ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/rewrite/Makefile.am000066400000000000000000000024321450431004300216370ustar00rootroot00000000000000rewriteincludedir = ${pkgincludedir}/rewrite EXTRA_DIST += lib/rewrite/CMakeLists.txt rewriteinclude_HEADERS = \ lib/rewrite/rewrite-expr.h \ lib/rewrite/rewrite-set-tag.h \ lib/rewrite/rewrite-set.h \ lib/rewrite/rewrite-unset.h \ lib/rewrite/rewrite-rename.h \ lib/rewrite/rewrite-subst.h \ lib/rewrite/rewrite-expr-parser.h \ lib/rewrite/rewrite-groupset.h \ lib/rewrite/rewrite-set-matches.h \ lib/rewrite/rewrite-unset-matches.h \ lib/rewrite/rewrite-set-pri.h \ lib/rewrite/rewrite-set-severity.h \ lib/rewrite/rewrite-set-facility.h rewrite_sources = \ lib/rewrite/rewrite-expr.c \ lib/rewrite/rewrite-set-tag.c \ lib/rewrite/rewrite-set.c \ lib/rewrite/rewrite-unset.c \ lib/rewrite/rewrite-rename.c \ lib/rewrite/rewrite-subst.c \ lib/rewrite/rewrite-expr-parser.c \ lib/rewrite/rewrite-expr-grammar.y \ lib/rewrite/rewrite-groupset.c \ lib/rewrite/rewrite-set-matches.c \ lib/rewrite/rewrite-unset-matches.c \ lib/rewrite/rewrite-set-pri.c \ lib/rewrite/rewrite-set-severity.c \ lib/rewrite/rewrite-set-facility.c BUILT_SOURCES += \ lib/rewrite/rewrite-expr-grammar.y \ lib/rewrite/rewrite-expr-grammar.c \ lib/rewrite/rewrite-expr-grammar.h EXTRA_DIST += lib/rewrite/rewrite-expr-grammar.ym include lib/rewrite/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-expr-grammar.ym000066400000000000000000000207621450431004300242410ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "rewrite/rewrite-expr-parser.h" } %code { #include "rewrite/rewrite-set-tag.h" #include "rewrite/rewrite-set.h" #include "rewrite/rewrite-unset.h" #include "rewrite/rewrite-rename.h" #include "rewrite/rewrite-subst.h" #include "rewrite/rewrite-groupset.h" #include "rewrite/rewrite-set-matches.h" #include "rewrite/rewrite-unset-matches.h" #include "rewrite/rewrite-set-pri.h" #include "rewrite/rewrite-set-severity.h" #include "rewrite/rewrite-set-facility.h" #include "filter/filter-expr.h" #include "filter/filter-expr-parser.h" #include "cfg-grammar-internal.h" #include "syslog-names.h" #include "plugin.h" #include } %define api.prefix {rewrite_expr_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogExprNode **result} %parse-param {gpointer arg} %type rewrite_expr %type rewrite_expr_list /* INCLUDE_DECLS */ %token KW_SET_TAG %token KW_CLEAR_TAG %token KW_GROUP_SET %token KW_GROUP_UNSET %token KW_SET %token KW_UNSET %token KW_RENAME %token KW_SUBST %token KW_VALUES %token KW_SET_SEVERITY %token KW_SET_FACILITY %token KW_SET_PRI %token KW_SET_MATCHES %token KW_UNSET_MATCHES %% start : rewrite_expr_list log_last_junction { *result = log_expr_node_append_tail($1, $2); if (yychar != REWRITE_EXPR_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } YYACCEPT; } ; rewrite_expr_list : rewrite_expr semicolons rewrite_expr_list { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_junction semicolons rewrite_expr_list { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; rewrite_expr : KW_SUBST '(' string template_content { last_rewrite = log_rewrite_subst_new($4, configuration); log_template_unref($4); } rewrite_subst_opts ')' { GError *error = NULL; CHECK_ERROR_GERROR(log_rewrite_subst_compile_pattern(last_rewrite, $3, &error), @3, error, "error compiling search pattern"); free($3); $$ = last_rewrite; } | KW_SET '(' template_content { last_rewrite = log_rewrite_set_new($3, configuration); last_template_options = log_rewrite_set_get_template_options(last_rewrite); log_template_unref($3); } rewrite_set_opts ')' { $$ = last_rewrite; } | KW_SET_MATCHES '(' template_content { last_rewrite = log_rewrite_set_matches_new($3, configuration); last_template_options = log_rewrite_set_get_template_options(last_rewrite); log_template_unref($3); } rewrite_set_matches_opts ')' { $$ = last_rewrite; } | KW_UNSET_MATCHES { last_rewrite = log_rewrite_unset_matches_new(configuration); } '(' rewrite_unset_matches_opts ')' { $$ = last_rewrite; } | KW_UNSET { last_rewrite = log_rewrite_unset_new(configuration); } '(' rewrite_set_opts ')' { $$ = last_rewrite; } | KW_RENAME '(' string string { NVHandle from = log_msg_get_value_handle($3); NVHandle to = log_msg_get_value_handle($4); free($3); free($4); last_rewrite = log_rewrite_rename_new(configuration, from, to); } rewrite_rename_opts ')' { $$ = last_rewrite; } | KW_SET_TAG '(' template_content { last_rewrite = log_rewrite_set_tag_new($3, TRUE, configuration); log_template_unref($3); } rewrite_settag_opts ')' { $$ = last_rewrite; } | KW_CLEAR_TAG '(' template_content { last_rewrite = log_rewrite_set_tag_new($3, FALSE, configuration); log_template_unref($3); } rewrite_settag_opts ')' { $$ = last_rewrite; } | KW_GROUP_SET '(' template_content { last_rewrite = log_rewrite_groupset_new($3, configuration); log_template_unref($3); } rewrite_groupset_opts ')' { $$ = last_rewrite; } | KW_GROUP_UNSET '(' { last_rewrite = log_rewrite_groupunset_new(configuration); } rewrite_groupset_opts ')' { $$ = last_rewrite; } | KW_SET_PRI '(' template_content { last_rewrite = log_rewrite_set_pri_new($3, configuration); log_template_unref($3); } rewrite_set_pri_opts ')' { $$ = last_rewrite; }; | KW_SET_SEVERITY '(' template_content { last_rewrite = log_rewrite_set_severity_new($3, configuration); log_template_unref($3); } rewrite_set_severity_opts ')' { $$ = last_rewrite; }; | KW_SET_FACILITY '(' template_content { last_rewrite = log_rewrite_set_facility_new($3, configuration); log_template_unref($3); } rewrite_set_facility_opts ')' { $$ = last_rewrite; }; | LL_PLUGIN { Plugin *p; gint context = LL_CONTEXT_REWRITE; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_rewrite = (LogRewrite *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_rewrite) { YYERROR; } $$ = last_rewrite; } ; rewrite_settag_opts : rewrite_settag_opt rewrite_settag_opts | ; rewrite_settag_opt : rewrite_condition_opt ; rewrite_groupset_opts : rewrite_groupset_opt rewrite_groupset_opts | ; rewrite_groupset_opt : KW_VALUES '(' string_list ')' { log_rewrite_groupset_add_fields(last_rewrite, $3); } | rewrite_condition_opt ; rewrite_subst_opts : rewrite_subst_opt rewrite_subst_opts | ; rewrite_subst_opt : { last_matcher_options = log_rewrite_subst_get_matcher_options(last_rewrite); } matcher_option | rewrite_expr_opt ; rewrite_rename_opts : rewrite_rename_opt rewrite_rename_opts | ; rewrite_rename_opt : rewrite_condition_opt ; rewrite_set_opts : rewrite_set_opt rewrite_set_opts | ; rewrite_set_opt : rewrite_expr_opt | template_option ; rewrite_expr_opts : rewrite_expr_opt rewrite_expr_opts | ; rewrite_set_pri_opts : rewrite_set_pri_opt rewrite_set_pri_opts | ; rewrite_set_pri_opt : rewrite_condition_opt ; rewrite_set_severity_opts : rewrite_set_severity_opt rewrite_set_severity_opts | ; rewrite_set_severity_opt : rewrite_condition_opt ; rewrite_set_facility_opts : rewrite_set_facility_opt rewrite_set_facility_opts | ; rewrite_set_facility_opt : rewrite_condition_opt ; rewrite_set_matches_opts : rewrite_set_matches_opt rewrite_set_matches_opts | ; rewrite_set_matches_opt : rewrite_condition_opt ; rewrite_unset_matches_opts : rewrite_unset_matches_opt rewrite_unset_matches_opts | ; rewrite_unset_matches_opt : rewrite_condition_opt ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-expr-parser.c000066400000000000000000000043041450431004300236760ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite/rewrite-expr-parser.h" #include "rewrite/rewrite-expr.h" #include "rewrite/rewrite-expr-grammar.h" extern int rewrite_expr_debug; int rewrite_expr_parse(CfgLexer *lexer, LogExprNode **node, gpointer arg); static CfgLexerKeyword rewrite_expr_keywords[] = { { "set", KW_SET }, { "unset", KW_UNSET }, { "subst", KW_SUBST }, { "set_tag", KW_SET_TAG }, { "clear_tag", KW_CLEAR_TAG }, { "set_matches", KW_SET_MATCHES }, { "unset_matches", KW_UNSET_MATCHES }, { "set_pri", KW_SET_PRI }, { "set_severity", KW_SET_SEVERITY }, { "set_facility", KW_SET_FACILITY }, { "rename", KW_RENAME }, { "groupset", KW_GROUP_SET }, { "groupunset", KW_GROUP_UNSET }, { "values", KW_VALUES }, { NULL } }; CfgParser rewrite_expr_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &rewrite_expr_debug, #endif .name = "rewrite expression", .context = LL_CONTEXT_REWRITE, .keywords = rewrite_expr_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) rewrite_expr_parse, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(rewrite_expr_, REWRITE_EXPR_, LogExprNode **) syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-expr-parser.h000066400000000000000000000023511450431004300237030ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_EXPR_PARSER_H_INCLUDED #define REWRITE_EXPR_PARSER_H_INCLUDED #include "cfg-parser.h" #include "cfg-tree.h" extern CfgParser rewrite_expr_parser; CFG_PARSER_DECLARE_LEXER_BINDING(rewrite_expr_, REWRITE_EXPR_, LogExprNode **) #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-expr.c000066400000000000000000000063361450431004300224130ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite/rewrite-expr.h" /* rewrite */ void log_rewrite_set_condition(LogRewrite *self, FilterExprNode *condition) { self->condition = condition; } static void log_rewrite_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogRewrite *self = (LogRewrite *) s; msg_trace(">>>>>> rewrite rule evaluation begin", evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); if (self->condition && !filter_expr_eval_root(self->condition, &msg, path_options)) { msg_trace("Rewrite condition unmatched, skipping rewrite", evt_tag_str("value", log_msg_get_value_name(self->value_handle, NULL)), evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); } else { self->process(self, &msg, path_options); } msg_trace("<<<<<< rewrite rule evaluation finished", evt_tag_str("rule", self->name), log_pipe_location_tag(s), evt_tag_msg_reference(msg)); log_pipe_forward_msg(s, msg, path_options); } void log_rewrite_clone_method(LogRewrite *dst, const LogRewrite *src) { log_pipe_clone_method(&dst->super, &src->super); dst->condition = filter_expr_clone(src->condition); dst->value_handle = src->value_handle; } gboolean log_rewrite_init_method(LogPipe *s) { LogRewrite *self = (LogRewrite *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (self->condition) filter_expr_init(self->condition, cfg); if (!self->name) self->name = cfg_tree_get_rule_name(&cfg->tree, ENC_REWRITE, s->expr_node); return TRUE; } void log_rewrite_free_method(LogPipe *s) { LogRewrite *self = (LogRewrite *) s; if (self->condition) filter_expr_unref(self->condition); g_free(self->name); log_pipe_free_method(s); } void log_rewrite_init_instance(LogRewrite *self, GlobalConfig *cfg) { log_pipe_init_instance(&self->super, cfg); /* indicate that the rewrite rule is changing the message */ self->super.flags |= PIF_CONFIG_RELATED; self->super.free_fn = log_rewrite_free_method; self->super.queue = log_rewrite_queue; self->super.init = log_rewrite_init_method; self->value_handle = LM_V_MESSAGE; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-expr.h000066400000000000000000000032451450431004300224140ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_H_INCLUDED #define REWRITE_H_INCLUDED #include "logpipe.h" #include "filter/filter-expr.h" typedef struct _LogRewrite LogRewrite; struct _LogRewrite { LogPipe super; NVHandle value_handle; FilterExprNode *condition; void (*process)(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options); gchar *name; }; /* LogRewrite, abstract class */ gboolean log_rewrite_init_method(LogPipe *s); void log_rewrite_clone_method(LogRewrite *dst, const LogRewrite *src); void log_rewrite_set_condition(LogRewrite *s, FilterExprNode *condition); void log_rewrite_init_instance(LogRewrite *self, GlobalConfig *cfg); void log_rewrite_free_method(LogPipe *self); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-groupset.c000066400000000000000000000114211450431004300232740ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Juhász * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-groupset.h" #include "scratch-buffers.h" #include "string-list.h" typedef struct _LogRewriteGroupSetCallbackData { LogMessage *msg; LogTemplate *template; } LogRewriteGroupSetCallbackData; /* TODO escape '\0' when passing down the value */ static gboolean log_rewrite_groupset_foreach_func(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { LogRewriteGroupSetCallbackData *callback_data = (LogRewriteGroupSetCallbackData *) user_data; LogMessage *msg = callback_data->msg; LogTemplate *template = callback_data->template; GString *result; ScratchBuffersMarker mark; result = scratch_buffers_alloc_and_mark(&mark); LogTemplateEvalOptions options = {NULL, LTZ_LOCAL, 0, value, type}; log_template_format_value_and_type(template, msg, &options, result, &type); log_msg_set_value_by_name_with_type(msg, name, result->str, result->len, type); scratch_buffers_reclaim_marked(mark); return FALSE; } static gboolean log_rewrite_groupunset_foreach_func(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { LogRewriteGroupSetCallbackData *callback_data = (LogRewriteGroupSetCallbackData *) user_data; LogMessage *msg = callback_data->msg; log_msg_unset_value_by_name(msg, name); return FALSE; } static void log_rewrite_groupset_process(LogRewrite *s, LogMessage **msg, const LogPathOptions *path_options) { LogRewriteGroupSet *self = (LogRewriteGroupSet *) s; GlobalConfig *cfg = log_pipe_get_config(&s->super); LogRewriteGroupSetCallbackData userdata; log_msg_make_writable(msg, path_options); userdata.msg = *msg; userdata.template = self->replacement; LogTemplateEvalOptions options = {&cfg->template_options, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; value_pairs_foreach(self->query, self->vp_func, *msg, &options, &userdata); } void log_rewrite_groupset_add_fields(LogRewrite *rewrite, GList *fields) { LogRewriteGroupSet *self = (LogRewriteGroupSet *) rewrite; for (GList *head = fields; head; head = head->next) { value_pairs_add_glob_pattern(self->query, head->data, TRUE); } string_list_free(fields); } static LogPipe * log_rewrite_groupset_clone(LogPipe *s) { LogRewriteGroupSet *self = (LogRewriteGroupSet *) s; LogRewriteGroupSet *cloned = (LogRewriteGroupSet *)log_rewrite_groupset_new(self->replacement, log_pipe_get_config(&self->super.super)); log_rewrite_clone_method(&cloned->super, &self->super); value_pairs_unref(cloned->query); cloned->query = value_pairs_ref(self->query); cloned->vp_func = self->vp_func; return &cloned->super.super; } void log_rewrite_groupset_free(LogPipe *s) { LogRewriteGroupSet *self = (LogRewriteGroupSet *) s; value_pairs_unref(self->query); log_template_unref(self->replacement); log_rewrite_free_method(s); } LogRewrite * log_rewrite_groupset_new(LogTemplate *template, GlobalConfig *cfg) { LogRewriteGroupSet *self = g_new0(LogRewriteGroupSet, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_groupset_free; self->super.process = log_rewrite_groupset_process; self->super.super.clone = log_rewrite_groupset_clone; self->replacement = log_template_ref(template); self->query = value_pairs_new(cfg); self->vp_func = log_rewrite_groupset_foreach_func; return &self->super; } LogRewrite * log_rewrite_groupunset_new(GlobalConfig *cfg) { LogRewriteGroupSet *self = (LogRewriteGroupSet *)log_rewrite_groupset_new(NULL, cfg); self->vp_func = log_rewrite_groupunset_foreach_func; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-groupset.h000066400000000000000000000027771450431004300233170ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_GROUPSET_H_INCLUDED #define REWRITE_GROUPSET_H_INCLUDED #include "rewrite/rewrite-expr.h" #include "value-pairs/value-pairs.h" typedef struct _LogRewriteGroupSet { LogRewrite super; ValuePairs *query; LogTemplate *replacement; VPForeachFunc vp_func; } LogRewriteGroupSet; LogRewrite *log_rewrite_groupset_new(LogTemplate *template, GlobalConfig *cfg); LogRewrite *log_rewrite_groupunset_new(GlobalConfig *cfg); void log_rewrite_groupset_add_fields(LogRewrite *rewrite, GList *fields); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-rename.c000066400000000000000000000051451450431004300227010ustar00rootroot00000000000000/* * Copyright (c) 2021 Balabit * Copyright (c) 2021 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-rename.h" typedef struct _LogRewriteRename LogRewriteRename; struct _LogRewriteRename { LogRewrite super; NVHandle source_handle; NVHandle destination_handle; }; static void log_rewrite_rename_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteRename *self = (LogRewriteRename *) s; if (self->source_handle == self->destination_handle) return; log_msg_make_writable(pmsg, path_options); log_msg_rename_value(*pmsg, self->source_handle, self->destination_handle); } static LogPipe * log_rewrite_rename_clone(LogPipe *s) { LogRewriteRename *self = (LogRewriteRename *) s; LogRewriteRename *cloned; cloned = (LogRewriteRename *) log_rewrite_rename_new(s->cfg, self->source_handle, self->destination_handle); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } static gboolean log_rewrite_rename_init(LogPipe *s) { LogRewriteRename *self = (LogRewriteRename *) s; if (!self->source_handle || !self->destination_handle) { msg_error("rename(from to): requires two non-empty arguments", log_pipe_location_tag(s)); return FALSE; } return TRUE; } LogRewrite * log_rewrite_rename_new(GlobalConfig *cfg, NVHandle source, NVHandle destination) { LogRewriteRename *self = g_new0(LogRewriteRename, 1); self->source_handle = source; self->destination_handle = destination; log_rewrite_init_instance(&self->super, cfg); self->super.super.init = log_rewrite_rename_init; self->super.super.clone = log_rewrite_rename_clone; self->super.process = log_rewrite_rename_process; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-rename.h000066400000000000000000000022741450431004300227060ustar00rootroot00000000000000/* * Copyright (c) 2021 Balabit * Copyright (c) 2021 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_RENAME_H_INCLUDED #define REWRITE_RENAME_H_INCLUDED #include "rewrite/rewrite-expr.h" LogRewrite *log_rewrite_rename_new(GlobalConfig *cfg, NVHandle source, NVHandle destination); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-facility.c000066400000000000000000000100651450431004300240240ustar00rootroot00000000000000/* * Copyright (c) 2020 Balazs Scheidler * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set-facility.h" #include "template/templates.h" #include "syslog-names.h" #include "scratch-buffers.h" #include "parse-number.h" #include typedef struct _LogRewriteSetFacility LogRewriteSetFacility; struct _LogRewriteSetFacility { LogRewrite super; LogTemplate *facility; }; static gint _convert_facility_as_number(const gchar *facility_text) { gint64 facility = 0; if (!parse_int64(facility_text, &facility)) return -1; if (facility > 127) return -1; return SYSLOG_FACILITY_CODE(facility); } static gint _convert_facility_as_text(const gchar *facility_text) { return syslog_name_lookup_facility_by_name(facility_text); } static gint _convert_facility(const gchar *facility_text) { gint facility = _convert_facility_as_number(facility_text); if (facility >= 0) return facility; facility = _convert_facility_as_text(facility_text); if (facility >= 0) return facility; return -1; } static void _set_msg_facility(LogMessage *msg, const guint32 facility) { msg->pri = (msg->pri & ~SYSLOG_FACMASK) | facility; } static void log_rewrite_set_facility_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { ScratchBuffersMarker marker; GString *result = scratch_buffers_alloc_and_mark(&marker); LogRewriteSetFacility *self = (LogRewriteSetFacility *) s; log_msg_make_writable(pmsg, path_options); log_template_format(self->facility, *pmsg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result); const gint facility = _convert_facility(result->str); if (facility < 0) { msg_debug("Warning: invalid value passed to set-facility()", evt_tag_str("facility", result->str), log_pipe_location_tag(&s->super)); goto error; } msg_trace("Setting syslog facility", evt_tag_int("old_facility", (*pmsg)->pri & SYSLOG_FACMASK), evt_tag_int("new_facility", facility), evt_tag_msg_reference(*pmsg)); _set_msg_facility(*pmsg, facility); error: scratch_buffers_reclaim_marked(marker); } static LogPipe * log_rewrite_set_facility_clone(LogPipe *s) { LogRewriteSetFacility *self = (LogRewriteSetFacility *) s; LogRewriteSetFacility *cloned = (LogRewriteSetFacility *)log_rewrite_set_facility_new(log_template_ref(self->facility), s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } void log_rewrite_set_facility_free(LogPipe *s) { LogRewriteSetFacility *self = (LogRewriteSetFacility *) s; log_template_unref(self->facility); log_rewrite_free_method(s); } LogRewrite * log_rewrite_set_facility_new(LogTemplate *facility, GlobalConfig *cfg) { LogRewriteSetFacility *self = g_new0(LogRewriteSetFacility, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_set_facility_free; self->super.super.clone = log_rewrite_set_facility_clone; self->super.process = log_rewrite_set_facility_process; self->facility = log_template_ref(facility); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-facility.h000066400000000000000000000022401450431004300240250ustar00rootroot00000000000000/* * Copyright (c) 2020 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_FACILITY_H_INCLUDED #define REWRITE_SET_FACILITY_H_INCLUDED #include "rewrite-expr.h" LogRewrite *log_rewrite_set_facility_new(LogTemplate *facility, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-matches.c000066400000000000000000000075761450431004300236610ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set-matches.h" #include "scanner/list-scanner/list-scanner.h" #include "scratch-buffers.h" /* LogRewriteSetMatches * * This class implements the "set" expression in a rewrite rule. */ typedef struct _LogRewriteSetMatches LogRewriteSetMatches; struct _LogRewriteSetMatches { LogRewrite super; LogTemplate *value_template; LogTemplateOptions template_options; }; LogTemplateOptions * log_rewrite_set_matches_get_template_options(LogRewrite *s) { LogRewriteSetMatches *self = (LogRewriteSetMatches *) s; return &self->template_options; } static void log_rewrite_set_matches_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteSetMatches *self = (LogRewriteSetMatches *) s; GString *result; LogMessageValueType type; result = scratch_buffers_alloc(); LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, 0, NULL, LM_VT_STRING}; log_template_format_value_and_type(self->value_template, *pmsg, &options, result, &type); log_msg_make_writable(pmsg, path_options); ListScanner scanner; list_scanner_init(&scanner); list_scanner_input_string(&scanner, result->str, result->len); log_msg_clear_matches(*pmsg); for (gint i = 1; list_scanner_scan_next(&scanner) && i < LOGMSG_MAX_MATCHES; i++) { log_msg_set_match(*pmsg, i, list_scanner_get_current_value(&scanner), list_scanner_get_current_value_len(&scanner)); } list_scanner_deinit(&scanner); } static LogPipe * log_rewrite_set_matches_clone(LogPipe *s) { LogRewriteSetMatches *self = (LogRewriteSetMatches *) s; LogRewriteSetMatches *cloned; cloned = (LogRewriteSetMatches *) log_rewrite_set_matches_new(self->value_template, s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } static void log_rewrite_set_matches_free(LogPipe *s) { LogRewriteSetMatches *self = (LogRewriteSetMatches *) s; log_template_options_destroy(&self->template_options); log_template_unref(self->value_template); log_rewrite_free_method(s); } gboolean log_rewrite_set_matches_init_method(LogPipe *s) { LogRewriteSetMatches *self = (LogRewriteSetMatches *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (log_rewrite_init_method(s)) { log_template_options_init(&self->template_options, cfg); return TRUE; } else return FALSE; } LogRewrite * log_rewrite_set_matches_new(LogTemplate *new_value, GlobalConfig *cfg) { LogRewriteSetMatches *self = g_new0(LogRewriteSetMatches, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_set_matches_free; self->super.super.clone = log_rewrite_set_matches_clone; self->super.super.init = log_rewrite_set_matches_init_method; self->super.process = log_rewrite_set_matches_process; self->value_template = log_template_ref(new_value); log_template_options_defaults(&self->template_options); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-matches.h000066400000000000000000000024141450431004300236500ustar00rootroot00000000000000/* * Copyright (c) 2021 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_MATCHES_H_INCLUDED #define REWRITE_SET_MATCHES_H_INCLUDED #include "rewrite/rewrite-expr.h" /* LogRewriteSet */ LogRewrite *log_rewrite_set_matches_new(LogTemplate *new_value, GlobalConfig *cfg); LogTemplateOptions *log_rewrite_set_matches_get_template_options(LogRewrite *s); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-pri.c000066400000000000000000000063311450431004300230130ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set-pri.h" #include "template/templates.h" #include "syslog-names.h" #include "scratch-buffers.h" #include typedef struct _LogRewriteSetPri LogRewriteSetPri; struct _LogRewriteSetPri { LogRewrite super; LogTemplate *pri; }; gint log_rewrite_set_pri_convert_pri(const gchar *pri_text) { char *endptr; long int pri = strtol(pri_text, &endptr, 10); if (!endptr) return -1; if (endptr[0] != '\0' || pri_text == endptr) return -1; /* the maximum facility code is 127 in set-facility() */ if (pri > 127*8 + 7) return -1; return pri; } static void log_rewrite_set_pri_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteSetPri *self = (LogRewriteSetPri *) s; GString *result = scratch_buffers_alloc(); log_msg_make_writable(pmsg, path_options); log_template_format(self->pri, *pmsg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result); const gint pri = log_rewrite_set_pri_convert_pri(result->str); if (pri < 0) { msg_debug("Warning: invalid value passed to set-pri()", evt_tag_str("pri", result->str), log_pipe_location_tag(&s->super)); return; } msg_trace("Setting syslog pri", evt_tag_int("old_pri", (*pmsg)->pri), evt_tag_int("new_pri", pri), evt_tag_msg_reference(*pmsg)); (*pmsg)->pri = pri; } static LogPipe * log_rewrite_set_pri_clone(LogPipe *s) { LogRewriteSetPri *self = (LogRewriteSetPri *) s; LogRewriteSetPri *cloned = (LogRewriteSetPri *) log_rewrite_set_pri_new(log_template_ref(self->pri), s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } void log_rewrite_set_pri_free(LogPipe *s) { LogRewriteSetPri *self = (LogRewriteSetPri *) s; log_template_unref(self->pri); log_rewrite_free_method(s); } LogRewrite * log_rewrite_set_pri_new(LogTemplate *pri, GlobalConfig *cfg) { LogRewriteSetPri *self = g_new0(LogRewriteSetPri, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_set_pri_free; self->super.super.clone = log_rewrite_set_pri_clone; self->super.process = log_rewrite_set_pri_process; self->pri = log_template_ref(pri); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-pri.h000066400000000000000000000023161450431004300230170ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_PRI_H_INCLUDED #define REWRITE_SET_PRI_H_INCLUDED #include "rewrite-expr.h" LogRewrite *log_rewrite_set_pri_new(LogTemplate *severity, GlobalConfig *cfg); gint log_rewrite_set_pri_convert_pri(const gchar *pri_text); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-severity.c000066400000000000000000000100341450431004300240660ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set-severity.h" #include "template/templates.h" #include "syslog-names.h" #include "scratch-buffers.h" #include typedef struct _LogRewriteSetSeverity LogRewriteSetSeverity; struct _LogRewriteSetSeverity { LogRewrite super; LogTemplate *severity; }; static gint _convert_severity_as_number(GString *severity_text) { char *endptr; long int severity = strtol(severity_text->str, &endptr, 10); if (0 == endptr) return -1; if (endptr[0] != '\0' || severity_text->str == endptr) return -1; if (severity > 7) return -1; return severity; } static gint _convert_severity_as_text(GString *severity_text) { return syslog_name_lookup_severity_by_name(severity_text->str); } static gint _convert_severity(GString *severity_text) { gint severity = _convert_severity_as_number(severity_text); if (severity >= 0) return severity; severity = _convert_severity_as_text(severity_text); if (severity >= 0) return severity; return -1; } static void _set_msg_severity(LogMessage *msg, const guint16 severity) { msg->pri = (msg->pri & ~SYSLOG_PRIMASK) | severity; } static void log_rewrite_set_severity_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { ScratchBuffersMarker marker; GString *result = scratch_buffers_alloc_and_mark(&marker); LogRewriteSetSeverity *self = (LogRewriteSetSeverity *) s; log_msg_make_writable(pmsg, path_options); log_template_format(self->severity, *pmsg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result); const gint severity = _convert_severity(result); if (severity < 0) { msg_debug("Warning: invalid value passed to set-severity()", evt_tag_str("severity", result->str), log_pipe_location_tag(&s->super)); goto error; } msg_trace("Setting syslog severity", evt_tag_int("old_severity", SYSLOG_PRI((*pmsg)->pri)), evt_tag_int("new_severity", severity), evt_tag_msg_reference(*pmsg)); _set_msg_severity(*pmsg, severity); error: scratch_buffers_reclaim_marked(marker); } static LogPipe * log_rewrite_set_severity_clone(LogPipe *s) { LogRewriteSetSeverity *self = (LogRewriteSetSeverity *) s; LogRewriteSetSeverity *cloned = (LogRewriteSetSeverity *)log_rewrite_set_severity_new(log_template_ref(self->severity), s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } void log_rewrite_set_severity_free(LogPipe *s) { LogRewriteSetSeverity *self = (LogRewriteSetSeverity *) s; log_template_unref(self->severity); log_rewrite_free_method(s); } LogRewrite * log_rewrite_set_severity_new(LogTemplate *severity, GlobalConfig *cfg) { LogRewriteSetSeverity *self = g_new0(LogRewriteSetSeverity, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_set_severity_free; self->super.super.clone = log_rewrite_set_severity_clone; self->super.process = log_rewrite_set_severity_process; self->severity = log_template_ref(severity); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-severity.h000066400000000000000000000022661450431004300241030ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_SEVERITY_H_INCLUDED #define REWRITE_SET_SEVERITY_H_INCLUDED #include "rewrite-expr.h" LogRewrite *log_rewrite_set_severity_new(LogTemplate *severity, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-tag.c000066400000000000000000000062521450431004300227760ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set-tag.h" #include "template/templates.h" #include "scratch-buffers.h" /* LogRewriteSetTag * * This class implements the "set-tag" expression in a rewrite rule. */ typedef struct _LogRewriteSetTag LogRewriteSetTag; struct _LogRewriteSetTag { LogRewrite super; LogTagId tag_id; gboolean value; LogTemplate *tag_template; }; static void _set_tag(LogRewriteSetTag *self, LogMessage *msg) { if (self->tag_id != LOG_TAGS_UNDEF) { log_msg_set_tag_by_id_onoff(msg, self->tag_id, self->value); return; } GString *result = scratch_buffers_alloc(); log_template_format(self->tag_template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result); LogTagId tag_id = log_tags_get_by_name(result->str); log_msg_set_tag_by_id_onoff(msg, tag_id, self->value); } static void _process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteSetTag *self = (LogRewriteSetTag *) s; log_msg_make_writable(pmsg, path_options); _set_tag(self, *pmsg); } static LogPipe * _clone(LogPipe *s) { LogRewriteSetTag *self = (LogRewriteSetTag *) s; LogRewriteSetTag *cloned; cloned = (LogRewriteSetTag *) log_rewrite_set_tag_new(self->tag_template, self->value, self->super.super.cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } static void _free(LogPipe *s) { LogRewriteSetTag *self = (LogRewriteSetTag *) s; log_template_unref(self->tag_template); log_rewrite_free_method(s); } LogRewrite * log_rewrite_set_tag_new(LogTemplate *tag_template, gboolean value, GlobalConfig *cfg) { LogRewriteSetTag *self = g_new0(LogRewriteSetTag, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.clone = _clone; self->super.super.free_fn = _free; self->super.process = _process; self->value = value; self->tag_template = log_template_ref(tag_template); if (log_template_is_literal_string(tag_template)) { const gchar *tag_name = log_template_get_literal_value(tag_template, NULL); self->tag_id = log_tags_get_by_name(tag_name); } else { self->tag_id = LOG_TAGS_UNDEF; } return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set-tag.h000066400000000000000000000023211450431004300227740ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_TAG_H_INCLUDED #define REWRITE_SET_TAG_H_INCLUDED #include "rewrite-expr.h" /* LogRewriteSetTag */ LogRewrite *log_rewrite_set_tag_new(LogTemplate *tag_template, gboolean onoff, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set.c000066400000000000000000000066131450431004300222260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-set.h" #include "scratch-buffers.h" /* LogRewriteSet * * This class implements the "set" expression in a rewrite rule. */ typedef struct _LogRewriteSet LogRewriteSet; struct _LogRewriteSet { LogRewrite super; LogTemplate *value_template; LogTemplateOptions template_options; }; LogTemplateOptions * log_rewrite_set_get_template_options(LogRewrite *s) { LogRewriteSet *self = (LogRewriteSet *) s; return &self->template_options; } static void log_rewrite_set_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteSet *self = (LogRewriteSet *) s; GString *result; LogMessageValueType type; result = scratch_buffers_alloc(); LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, 0, NULL, LM_VT_STRING}; log_template_format_value_and_type(self->value_template, *pmsg, &options, result, &type); log_msg_make_writable(pmsg, path_options); log_msg_set_value_with_type(*pmsg, self->super.value_handle, result->str, result->len, type); } static LogPipe * log_rewrite_set_clone(LogPipe *s) { LogRewriteSet *self = (LogRewriteSet *) s; LogRewriteSet *cloned; cloned = (LogRewriteSet *) log_rewrite_set_new(self->value_template, s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); log_template_options_clone(&self->template_options, &cloned->template_options); return &cloned->super.super; } static void log_rewrite_set_free(LogPipe *s) { LogRewriteSet *self = (LogRewriteSet *) s; log_template_options_destroy(&self->template_options); log_template_unref(self->value_template); log_rewrite_free_method(s); } gboolean log_rewrite_set_init_method(LogPipe *s) { LogRewriteSet *self = (LogRewriteSet *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (log_rewrite_init_method(s)) { log_template_options_init(&self->template_options, cfg); return TRUE; } else return FALSE; } LogRewrite * log_rewrite_set_new(LogTemplate *new_value, GlobalConfig *cfg) { LogRewriteSet *self = g_new0(LogRewriteSet, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_set_free; self->super.super.clone = log_rewrite_set_clone; self->super.super.init = log_rewrite_set_init_method; self->super.process = log_rewrite_set_process; self->value_template = log_template_ref(new_value); log_template_options_defaults(&self->template_options); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-set.h000066400000000000000000000024001450431004300222210ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SET_H_INCLUDED #define REWRITE_SET_H_INCLUDED #include "rewrite/rewrite-expr.h" /* LogRewriteSet */ LogRewrite *log_rewrite_set_new(LogTemplate *new_value, GlobalConfig *cfg); LogTemplateOptions *log_rewrite_set_get_template_options(LogRewrite *s); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-subst.c000066400000000000000000000114561450431004300225740ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-subst.h" /* LogRewriteSubst * * This class implements the "subst" expression in a rewrite rule. */ typedef struct _LogRewriteSubst LogRewriteSubst; struct _LogRewriteSubst { LogRewrite super; LogMatcherOptions matcher_options; LogMatcher *matcher; LogTemplate *replacement; }; LogMatcherOptions * log_rewrite_subst_get_matcher_options(LogRewrite *s) { LogRewriteSubst *self = (LogRewriteSubst *) s; return &self->matcher_options; } void log_rewrite_subst_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteSubst *self = (LogRewriteSubst *) s; LogMessage *msg; NVTable *nvtable; const gchar *value; gchar *new_value; gssize length; gssize new_length = -1; msg = log_msg_make_writable(pmsg, path_options); nvtable = nv_table_ref(msg->payload); value = log_msg_get_value(msg, self->super.value_handle, &length); new_value = log_matcher_replace(self->matcher, msg, self->super.value_handle, value, length, self->replacement, &new_length); if (new_value) { msg_trace("Performing subst() rewrite", evt_tag_str("rule", s->name), evt_tag_str("value", log_msg_get_value_name(s->value_handle, NULL)), evt_tag_mem("input", value, length), evt_tag_str("type", self->matcher_options.type), evt_tag_str("pattern", self->matcher->pattern), evt_tag_str("replacement", self->replacement->template_str), log_pipe_location_tag(&s->super)); log_msg_set_value(msg, self->super.value_handle, new_value, new_length); } else { msg_trace("Performing subst() rewrite failed, pattern did not match", evt_tag_str("rule", s->name), evt_tag_str("value", log_msg_get_value_name(s->value_handle, NULL)), evt_tag_mem("input", value, length), evt_tag_str("type", self->matcher_options.type), evt_tag_str("pattern", self->matcher->pattern), evt_tag_str("replacement", self->replacement->template_str), log_pipe_location_tag(&s->super)); } nv_table_unref(nvtable); g_free(new_value); } gboolean log_rewrite_subst_compile_pattern(LogRewrite *s, const gchar *regexp, GError **error) { LogRewriteSubst *self = (LogRewriteSubst *) s; log_matcher_options_init(&self->matcher_options); self->matcher = log_matcher_new(&self->matcher_options); if (!log_matcher_is_replace_supported(self->matcher)) { g_set_error(error, LOG_MATCHER_ERROR, 0, "subst() only supports matchers that allow replacement, glob is not one of these"); return FALSE; } return log_matcher_compile(self->matcher, regexp, error); } static LogPipe * log_rewrite_subst_clone(LogPipe *s) { LogRewriteSubst *self = (LogRewriteSubst *) s; LogRewriteSubst *cloned; cloned = (LogRewriteSubst *) log_rewrite_subst_new(self->replacement, s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); cloned->matcher = log_matcher_ref(self->matcher); return &cloned->super.super; } void log_rewrite_subst_free(LogPipe *s) { LogRewriteSubst *self = (LogRewriteSubst *) s; log_matcher_unref(self->matcher); log_template_unref(self->replacement); log_matcher_options_destroy(&self->matcher_options); log_rewrite_free_method(s); } LogRewrite * log_rewrite_subst_new(LogTemplate *replacement, GlobalConfig *cfg) { LogRewriteSubst *self = g_new0(LogRewriteSubst, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.free_fn = log_rewrite_subst_free; self->super.super.clone = log_rewrite_subst_clone; self->super.process = log_rewrite_subst_process; self->replacement = log_template_ref(replacement); log_matcher_options_defaults(&self->matcher_options); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-subst.h000066400000000000000000000025741450431004300226020ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_SUBST_H_INCLUDED #define REWRITE_SUBST_H_INCLUDED #include "rewrite-expr.h" #include "logmatcher.h" /* LogRewriteSubst */ LogMatcherOptions *log_rewrite_subst_get_matcher_options(LogRewrite *s); gboolean log_rewrite_subst_compile_pattern(LogRewrite *s, const gchar *regexp, GError **error); LogRewrite *log_rewrite_subst_new(LogTemplate *replacement, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-unset-matches.c000066400000000000000000000040711450431004300242070ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-unset-matches.h" /* LogRewriteUnsetMatches * * This class implements the "unset-matches" expression in a rewrite rule. */ typedef struct _LogRewriteUnsetMatches LogRewriteUnsetMatches; struct _LogRewriteUnsetMatches { LogRewrite super; }; static void log_rewrite_unset_matches_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { log_msg_make_writable(pmsg, path_options); log_msg_clear_matches(*pmsg); } static LogPipe * log_rewrite_unset_matches_clone(LogPipe *s) { LogRewriteUnsetMatches *self = (LogRewriteUnsetMatches *) s; LogRewriteUnsetMatches *cloned; cloned = (LogRewriteUnsetMatches *) log_rewrite_unset_matches_new(s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } LogRewrite * log_rewrite_unset_matches_new(GlobalConfig *cfg) { LogRewriteUnsetMatches *self = g_new0(LogRewriteUnsetMatches, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.clone = log_rewrite_unset_matches_clone; self->super.process = log_rewrite_unset_matches_process; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-unset-matches.h000066400000000000000000000022251450431004300242130ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_UNSET_MATCHES_H_INCLUDED #define REWRITE_UNSET_MATCHES_H_INCLUDED #include "rewrite/rewrite-expr.h" LogRewrite *log_rewrite_unset_matches_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-unset.c000066400000000000000000000040211450431004300225600ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 1998-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "rewrite-unset.h" /* LogRewriteUnset * * This class implements the "unset" expression in a rewrite rule. */ typedef struct _LogRewriteUnset LogRewriteUnset; struct _LogRewriteUnset { LogRewrite super; }; static void log_rewrite_unset_process(LogRewrite *s, LogMessage **pmsg, const LogPathOptions *path_options) { LogRewriteUnset *self = (LogRewriteUnset *) s; log_msg_make_writable(pmsg, path_options); log_msg_unset_value(*pmsg, self->super.value_handle); } static LogPipe * log_rewrite_unset_clone(LogPipe *s) { LogRewriteUnset *self = (LogRewriteUnset *) s; LogRewriteUnset *cloned; cloned = (LogRewriteUnset *) log_rewrite_unset_new(s->cfg); log_rewrite_clone_method(&cloned->super, &self->super); return &cloned->super.super; } LogRewrite * log_rewrite_unset_new(GlobalConfig *cfg) { LogRewriteUnset *self = g_new0(LogRewriteUnset, 1); log_rewrite_init_instance(&self->super, cfg); self->super.super.clone = log_rewrite_unset_clone; self->super.process = log_rewrite_unset_process; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/rewrite/rewrite-unset.h000066400000000000000000000022451450431004300225730ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef REWRITE_UNSET_H_INCLUDED #define REWRITE_UNSET_H_INCLUDED #include "rewrite/rewrite-expr.h" /* LogRewriteSet */ LogRewrite *log_rewrite_unset_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/000077500000000000000000000000001450431004300207445ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/CMakeLists.txt000066400000000000000000000006001450431004300235000ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_rewrite) add_unit_test(LIBTEST CRITERION TARGET test_set_pri) add_unit_test(LIBTEST CRITERION TARGET test_set_matches) add_unit_test(LIBTEST CRITERION TARGET test_set_tag) add_unit_test(LIBTEST CRITERION TARGET test_rename) add_unit_test(LIBTEST CRITERION TARGET test_set_severity) add_unit_test(LIBTEST CRITERION TARGET test_set_facility) syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/Makefile.am000066400000000000000000000034371450431004300230070ustar00rootroot00000000000000lib_rewrite_tests_TESTS = \ lib/rewrite/tests/test_rewrite \ lib/rewrite/tests/test_set_pri \ lib/rewrite/tests/test_set_matches \ lib/rewrite/tests/test_set_tag \ lib/rewrite/tests/test_rename \ lib/rewrite/tests/test_set_severity \ lib/rewrite/tests/test_set_facility EXTRA_DIST += lib/rewrite/tests/CMakeLists.txt check_PROGRAMS += ${lib_rewrite_tests_TESTS} lib_rewrite_tests_test_rewrite_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_rewrite_LDADD = $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) lib_rewrite_tests_test_rewrite_SOURCES = \ lib/rewrite/tests/test_rewrite.c lib_rewrite_tests_test_rename_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_rename_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_rename_SOURCES = \ lib/rewrite/tests/test_rename.c lib_rewrite_tests_test_set_severity_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_set_severity_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_set_severity_SOURCES = \ lib/rewrite/tests/test_set_severity.c lib_rewrite_tests_test_set_facility_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_set_facility_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_set_facility_SOURCES = \ lib/rewrite/tests/test_set_facility.c lib_rewrite_tests_test_set_pri_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_set_pri_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_set_pri_SOURCES = \ lib/rewrite/tests/test_set_pri.c lib_rewrite_tests_test_set_matches_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_set_matches_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_set_matches_SOURCES = \ lib/rewrite/tests/test_set_matches.c lib_rewrite_tests_test_set_tag_CFLAGS = $(TEST_CFLAGS) lib_rewrite_tests_test_set_tag_LDADD = $(TEST_LDADD) lib_rewrite_tests_test_set_tag_SOURCES = \ lib/rewrite/tests/test_set_tag.c syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_rename.c000066400000000000000000000075231450431004300234250ustar00rootroot00000000000000/* * Copyright (c) 2021 Balabit * Copyright (c) 2021 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "libtest/msg_parse_lib.h" #include "rewrite/rewrite-rename.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" #include "apphook.h" GlobalConfig *cfg = NULL; LogMessage *msg; static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; cr_assert(log_pipe_init(&rewrite->super)); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_rename(const gchar *from, const char *to, LogMessage *msg_) { LogRewrite *rename = log_rewrite_rename_new(cfg, log_msg_get_value_handle(from), log_msg_get_value_handle(to)); _perform_rewrite(rename, msg_); } Test(rename, basic_rename) { _perform_rename("MESSAGE", "m", msg); assert_log_message_value_by_name(msg, "m", "example"); assert_log_message_value_unset_by_name(msg, "MESSAGE"); } Test(rename, override_existing) { _perform_rename(".SDATA.bar", "MESSAGE", msg); assert_log_message_value_by_name(msg, "MESSAGE", "foo"); assert_log_message_value_unset_by_name(msg, ".SDATA.bar"); } Test(rename, structued) { _perform_rename(".SDATA.bar", ".json.bar", msg); assert_log_message_value_by_name(msg, ".json.bar", "foo"); assert_log_message_value_unset_by_name(msg, ".SDATA.bar"); } Test(rename, rename_empty) { _perform_rename("empty", "really-empty", msg); assert_log_message_value_by_name(msg, "really-empty", ""); assert_log_message_value_unset_by_name(msg, "empty"); } Test(rename, source_destination_equals) { _perform_rename("MESSAGE", "MESSAGE", msg); assert_log_message_value_by_name(msg, "MESSAGE", "example"); } Test(rename, rename_not_existing_should_not_create_old_or_new) { _perform_rename("should-not-exists", "something-else", msg); assert_log_message_value_unset_by_name(msg, "should-not-exists"); assert_log_message_value_unset_by_name(msg, "something-else"); } Test(rename, source_option_mandatory) { LogRewrite *rename = log_rewrite_rename_new(cfg, 0, LM_V_MESSAGE); cr_assert_not(log_pipe_init(&rename->super)); log_pipe_unref(&rename->super); } Test(rename, destination_option_mandatory) { LogRewrite *rename = log_rewrite_rename_new(cfg, LM_V_MESSAGE, 0); cr_assert_not(log_pipe_init(&rename->super)); log_pipe_unref(&rename->super); } static void setup(void) { app_startup(); cfg = cfg_new_snippet(); start_grabbing_messages(); msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, "example", -1); log_msg_set_value_by_name(msg, ".SDATA.bar", "foo", -1); log_msg_set_value_by_name(msg, "empty", "", -1); } static void teardown(void) { scratch_buffers_explicit_gc(); log_msg_unref(msg); stop_grabbing_messages(); cfg_free(cfg); app_shutdown(); } TestSuite(rename, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_rewrite.c000066400000000000000000000323451450431004300236370ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/config_parse_lib.h" #include "libtest/msg_parse_lib.h" #include "libtest/grab-logging.h" #include "apphook.h" #include "plugin.h" #include "cfg-grammar.h" #include "rewrite/rewrite-expr.h" #include "scratch-buffers.h" void expect_config_parse_failure(const char *raw_rewrite_rule) { char raw_config[1024]; configuration = cfg_new_snippet(); snprintf(raw_config, sizeof(raw_config), "rewrite s_test{ %s };", raw_rewrite_rule); cr_assert_not(parse_config(raw_config, LL_CONTEXT_ROOT, NULL, NULL), "Parsing the given configuration failed"); cfg_free(configuration); }; LogRewrite * create_rewrite_rule(const char *raw_rewrite_rule) { char raw_config[1024]; configuration = cfg_new_snippet(); snprintf(raw_config, sizeof(raw_config), "rewrite s_test{ %s }; log{ rewrite(s_test); };", raw_rewrite_rule); cr_assert(parse_config(raw_config, LL_CONTEXT_ROOT, NULL, NULL), "Parsing the given configuration failed"); cr_assert(cfg_init(configuration), "Config initialization failed"); LogExprNode *expr_node = cfg_tree_get_object(&configuration->tree, ENC_REWRITE, "s_test"); return (LogRewrite *)expr_node->children->object; } LogMessage * create_message_with_fields(const char *field_name, ...) { va_list args; const char *arg; LogMessage *msg = log_msg_new_empty(); msg->timestamps[LM_TS_STAMP].ut_sec = 365 * 24 * 3600; arg = field_name; va_start(args, field_name); while (arg != NULL) { NVHandle handle = log_msg_get_value_handle(arg); arg = va_arg(args, char *); log_msg_set_value(msg, handle, arg, -1); arg = va_arg(args, char *); } va_end(args); return msg; } LogMessage * create_message_with_field(const char *field_name, const char *field_value) { return create_message_with_fields(field_name, field_value, NULL); } void invoke_rewrite_rule(LogRewrite *pipe_, LogMessage *msg) { LogPathOptions po = LOG_PATH_OPTIONS_INIT; log_pipe_queue((LogPipe *) pipe_, log_msg_ref(msg), &po); }; void rewrite_teardown(LogMessage *msg) { log_msg_unref(msg); cfg_free(configuration); } Test(rewrite, condition_success) { LogRewrite *test_rewrite = create_rewrite_rule("set(\"00100\", value(\"device_id\") condition(program(\"ARCGIS\")));"); LogMessage *msg = create_message_with_field("PROGRAM", "ARCGIS"); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "device_id", "00100"); rewrite_teardown(msg); } Test(rewrite, reference_on_condition_cloned) { LogRewrite *test_rewrite = create_rewrite_rule("set(\"00100\", value(\"device_id\") condition(program(\"ARCGIS\")));"); LogPipe *cloned_rule = log_pipe_clone(&test_rewrite->super); cr_assert_eq(test_rewrite->condition->ref_cnt, 2, "Bad reference number of condition"); log_pipe_unref(cloned_rule); cr_assert_eq(test_rewrite->condition->ref_cnt, 1, "Bad reference number of condition"); cfg_free(configuration); } Test(rewrite, set_field_exist_and_set_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("set(\"value\" value(\"field1\") );"); LogMessage *msg = create_message_with_field("field1", "oldvalue"); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_not_exist_and_set_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("set(\"value\" value(\"field1\") );"); LogMessage *msg = log_msg_new_empty(); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_set_template_string) { LogRewrite *test_rewrite = create_rewrite_rule("set(\"$field2\" value(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "field2", "newvalue", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "newvalue"); rewrite_teardown(msg); } Test(rewrite, set_field_not_exist_and_set_typed_template_string) { LogRewrite *test_rewrite = create_rewrite_rule("set(int64(\"$PID\") value(\"field1\") );"); LogMessage *msg = create_message_with_fields("PID", "123", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_and_type_by_name(msg, "field1", "123", LM_VT_INTEGER); rewrite_teardown(msg); } Test(rewrite, subst_field_exist_and_substring_substituted) { LogRewrite *test_rewrite = create_rewrite_rule("subst(\"substring\" \"substitute\" value(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "asubstringb", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "asubstituteb"); rewrite_teardown(msg); } Test(rewrite, subst_pcre_unused_subpattern) { LogRewrite *test_rewrite = create_rewrite_rule("subst('(a|(z))(bc)', '.', value('field1') type(pcre) flags('store-matches'));"); LogMessage *msg = create_message_with_fields("field1", "abc", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "."); assert_log_message_value_by_name(msg, "0", "abc"); assert_log_message_value_by_name(msg, "1", "a"); assert_log_message_value_by_name(msg, "2", ""); assert_log_message_value_by_name(msg, "3", "bc"); rewrite_teardown(msg); } Test(rewrite, subst_field_exist_and_substring_substituted_with_template) { LogRewrite *test_rewrite = create_rewrite_rule("subst(\"substring\" \"$field2\" value(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "asubstringb", "field2", "substitute", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "asubstituteb"); rewrite_teardown(msg); } Test(rewrite, subst_field_exist_and_substring_substituted_only_once_without_global) { LogRewrite *test_rewrite = create_rewrite_rule("subst(\"substring\" \"substitute\" value(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "substring substring", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "substitute substring"); rewrite_teardown(msg); } Test(rewrite, subst_field_exist_and_substring_substituted_every_occurrence_with_global) { LogRewrite *test_rewrite = create_rewrite_rule("subst(\"substring\" \"substitute\" value(\"field1\") flags(global) );"); LogMessage *msg = create_message_with_fields("field1", "substring substring", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "substitute substitute"); rewrite_teardown(msg); } Test(rewrite, subst_field_exist_and_substring_substituted_when_regexp_matched) { LogRewrite *test_rewrite = create_rewrite_rule("subst(\"[0-9]+\" \"substitute\" value(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "a123b", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "asubstituteb"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field1\") );"); LogMessage *msg = create_message_with_field("field1", "oldvalue"); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_honors_time_zone) { LogRewrite *test_rewrite = create_rewrite_rule("set('${ISODATE}' value('UTCDATE') time-zone('Asia/Tokyo'));"); LogMessage *msg = create_message_with_fields("field1", "a123b", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "UTCDATE", "1971-01-01T09:00:00+09:00"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_multiple_fields_with_glob_pattern_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field.*\") );"); LogMessage *msg = create_message_with_fields("field.name1", "oldvalue", "field.name2", "oldvalue", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field.name1", "value"); assert_log_message_value_by_name(msg, "field.name2", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_multiple_fields_with_glob_question_mark_pattern_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field?\") );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "field2", "oldvalue", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); assert_log_message_value_by_name(msg, "field2", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_multiple_fields_with_multiple_glob_pattern_literal_string) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field1\" \"field2\") );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "field2", "oldvalue", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); assert_log_message_value_by_name(msg, "field2", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_template_string) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"$field2\" values(\"field1\") );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "field2", "value", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_template_string_with_old_value) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"$_ alma\" values(\"field1\") );"); LogMessage *msg = create_message_with_field("field1", "value"); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value alma"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_when_condition_doesnt_match) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field1\") condition( program(\"program1\") ) );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "PROGRAM", "program2", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "oldvalue"); rewrite_teardown(msg); } Test(rewrite, set_field_exist_and_group_set_when_condition_matches) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field1\") condition( program(\"program\") ) );"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "PROGRAM", "program", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", "value"); rewrite_teardown(msg); } Test(rewrite, set_field_cloned) { LogRewrite *test_rewrite = create_rewrite_rule("groupset(\"value\" values(\"field1\") condition( program(\"program\") ) );"); LogPipe *cloned_rule = log_pipe_clone(&test_rewrite->super); cr_assert(cloned_rule != NULL, "Can't cloned the rewrite"); log_pipe_unref(cloned_rule); cfg_free(configuration); } Test(rewrite, set_field_invalid_template) { expect_config_parse_failure("groupset(\"${alma\" values(\"field1\") );"); } Test(rewrite, unset_field_disappears) { LogRewrite *test_rewrite = create_rewrite_rule("unset(value('field1'));"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "PROGRAM", "foobar", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", ""); assert_log_message_value_by_name(msg, "PROGRAM", "foobar"); rewrite_teardown(msg); } Test(rewrite, groupunset_field_disappears) { LogRewrite *test_rewrite = create_rewrite_rule("groupunset(values('field?'));"); LogMessage *msg = create_message_with_fields("field1", "oldvalue", "field2", "oldvalue2", "PROGRAM", "foobar", NULL); invoke_rewrite_rule(test_rewrite, msg); assert_log_message_value_by_name(msg, "field1", ""); assert_log_message_value_by_name(msg, "field2", ""); assert_log_message_value_by_name(msg, "PROGRAM", "foobar"); rewrite_teardown(msg); } void setup(void) { app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); start_grabbing_messages(); } void teardown(void) { scratch_buffers_explicit_gc(); stop_grabbing_messages(); app_shutdown(); } TestSuite(rewrite, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_set_facility.c000066400000000000000000000100751450431004300246310ustar00rootroot00000000000000/* * Copyright (c) 2020 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "syslog-names.h" #include "apphook.h" #include "rewrite/rewrite-set-facility.h" #include "logmsg/logmsg.h" GlobalConfig *cfg = NULL; LogMessage *msg; static LogTemplate * _create_template(const gchar *str) { GError *error = NULL; LogTemplate *template = log_template_new(cfg, NULL); cr_assert(log_template_compile(template, str, &error)); cr_expect_null(error); return template; } static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_pipe_init(&rewrite->super); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_set_facility(LogTemplate *template, LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_set_facility_new(template, cfg); log_template_unref(template); _perform_rewrite(rewrite, msg_); } static gboolean _msg_facility_equals(LogMessage *msg_, gint fac) { return (msg_->pri & SYSLOG_FACMASK) == fac; } Test(set_facility, text) { _perform_set_facility(_create_template("mail"), msg); cr_assert(_msg_facility_equals(msg, LOG_MAIL)); _perform_set_facility(_create_template("news"), msg); cr_assert(_msg_facility_equals(msg, LOG_NEWS)); _perform_set_facility(_create_template("kern"), msg); cr_assert(_msg_facility_equals(msg, LOG_KERN)); } Test(set_facility, numeric) { _perform_set_facility(_create_template("1"), msg); cr_assert(_msg_facility_equals(msg, SYSLOG_FACILITY_CODE(1))); _perform_set_facility(_create_template("2"), msg); cr_assert(_msg_facility_equals(msg, SYSLOG_FACILITY_CODE(2))); } Test(set_facility, test_set_facility_with_template_evaluating_to_empty_string) { debug_flag = 1; gint default_facility = msg->pri & SYSLOG_FACMASK; _perform_set_facility(_create_template("${nonexistentvalue}"), msg); cr_assert(_msg_facility_equals(msg, default_facility), "empty templates should not change the original facility"); assert_grabbed_log_contains("invalid value passed to set-facility()"); } Test(set_facility, large_number) { debug_flag = 1; gint default_facility = msg->pri & SYSLOG_FACMASK; _perform_set_facility(_create_template("128"), msg); cr_assert(_msg_facility_equals(msg, default_facility), "too large values should not change the original facility"); assert_grabbed_log_contains("invalid value passed to set-facility()"); } Test(set_facility, invalid) { debug_flag = 1; gint default_facility = msg->pri & SYSLOG_FACMASK; _perform_set_facility(_create_template("random-text"), msg); cr_assert(_msg_facility_equals(msg, default_facility), "too large values should not change the original facility"); assert_grabbed_log_contains("invalid value passed to set-facility()"); } static void setup(void) { app_startup(); cfg = cfg_new_snippet(); start_grabbing_messages(); msg = log_msg_new_empty(); } static void teardown(void) { log_msg_unref(msg); stop_grabbing_messages(); cfg_free(cfg); app_shutdown(); } TestSuite(set_facility, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_set_matches.c000066400000000000000000000113501450431004300244460ustar00rootroot00000000000000/* * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "libtest/msg_parse_lib.h" #include "libtest/cr_template.h" #include "apphook.h" #include "rewrite/rewrite-set-matches.h" #include "rewrite/rewrite-unset-matches.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" GlobalConfig *configuration = NULL; LogMessage *msg; static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_pipe_init(&rewrite->super); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_set_matches(LogTemplate *template, LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_set_matches_new(template, configuration); log_template_unref(template); _perform_rewrite(rewrite, msg_); } static void _perform_unset_matches(LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_unset_matches_new(configuration); _perform_rewrite(rewrite, msg_); } Test(set_matches, numeric) { log_msg_set_match(msg, 0, "whatever", -1); _perform_set_matches(compile_template("foo,bar"), msg); assert_log_message_value_unset_by_name(msg, "0"); assert_log_message_match_value(msg, 1, "foo"); assert_log_message_match_value(msg, 2, "bar"); } Test(set_matches, too_many_items) { cr_assert(LOGMSG_MAX_MATCHES == 256); log_msg_set_match(msg, 0, "whatever", -1); _perform_set_matches( compile_template("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15," "16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31," "32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47," "48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63," "64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79," "80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95," "96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111," "112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127," "128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143," "144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159," "160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175," "176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191," "192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207," "208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223," "224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239," "240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,thisisignored"), msg); assert_log_message_value_unset_by_name(msg, "0"); for (gint i = 1; i < 256; i++) { gchar buf[16]; g_snprintf(buf, sizeof(buf), "%d", i); assert_log_message_match_value(msg, i, buf); } /* the last item is ignored */ assert_log_message_match_value(msg, 256, ""); assert_log_message_value_by_name(msg, "256", ""); } Test(set_matches, unset_matches) { log_msg_set_match(msg, 0, "whatever", -1); log_msg_set_match(msg, 1, "foo", -1); log_msg_set_match(msg, 2, "bar", -1); _perform_unset_matches(msg); assert_log_message_value_unset_by_name(msg, "0"); assert_log_message_value_unset_by_name(msg, "1"); assert_log_message_value_unset_by_name(msg, "2"); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); start_grabbing_messages(); msg = log_msg_new_empty(); } static void teardown(void) { scratch_buffers_explicit_gc(); log_msg_unref(msg); stop_grabbing_messages(); cfg_free(configuration); app_shutdown(); } TestSuite(set_matches, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_set_pri.c000066400000000000000000000112121450431004300236110ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "apphook.h" #include "rewrite/rewrite-set-pri.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" GlobalConfig *cfg = NULL; LogMessage *msg; static LogTemplate * _create_template(const gchar *str) { GError *error = NULL; LogTemplate *template = log_template_new(cfg, NULL); cr_assert(log_template_compile(template, str, &error)); cr_expect_null(error); return template; } static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_pipe_init(&rewrite->super); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_set_pri(LogTemplate *template, LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_set_pri_new(template, cfg); log_template_unref(template); _perform_rewrite(rewrite, msg_); } static gboolean _msg_pri_equals(LogMessage *msg_, gint pri) { return msg_->pri == pri; } Test(set_pri, numeric) { _perform_set_pri(_create_template("7"), msg); cr_assert(_msg_pri_equals(msg, LOG_KERN | LOG_DEBUG)); _perform_set_pri(_create_template("189"), msg); cr_assert(_msg_pri_equals(msg, LOG_LOCAL7 | LOG_NOTICE)); log_msg_set_value_by_name(msg, "pri_value", "137", -1); _perform_set_pri(_create_template("$pri_value"), msg); cr_assert(_msg_pri_equals(msg, 137)); _perform_set_pri(_create_template("1023"), msg); cr_assert(_msg_pri_equals(msg, 127*8+7)); _perform_set_pri(_create_template(" 123"), msg); cr_assert(_msg_pri_equals(msg, 123)); } Test(set_pri, test_set_pri_with_various_invalid_values) { debug_flag = 1; int default_pri = msg->pri; _perform_set_pri(_create_template("${nonexistentvalue}"), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "empty templates should not change the original pri"); reset_grabbed_messages(); _perform_set_pri(_create_template("1024"), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "too large numeric values should not change the original pri"); reset_grabbed_messages(); _perform_set_pri(_create_template("-1"), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "negative values should not change the original pri"); reset_grabbed_messages(); _perform_set_pri(_create_template("random-text"), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "non-numeric data should not change the original pri"); reset_grabbed_messages(); _perform_set_pri(_create_template("123 "), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "non-numeric data should not change the original pri"); reset_grabbed_messages(); _perform_set_pri(_create_template("123d"), msg); assert_grabbed_log_contains("invalid value passed to set-pri()"); cr_assert(_msg_pri_equals(msg, default_pri), "non-numeric data should not change the original pri"); } static void setup(void) { app_startup(); cfg = cfg_new_snippet(); start_grabbing_messages(); msg = log_msg_new_empty(); } static void teardown(void) { scratch_buffers_explicit_gc(); log_msg_unref(msg); stop_grabbing_messages(); cfg_free(cfg); app_shutdown(); } TestSuite(set_pri, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_set_severity.c000066400000000000000000000101361450431004300246750ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "apphook.h" #include "rewrite/rewrite-set-severity.h" #include "logmsg/logmsg.h" #include "syslog-names.h" GlobalConfig *cfg = NULL; LogMessage *msg; static LogTemplate * _create_template(const gchar *str) { GError *error = NULL; LogTemplate *template = log_template_new(cfg, NULL); cr_assert(log_template_compile(template, str, &error)); cr_expect_null(error); return template; } static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_pipe_init(&rewrite->super); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_set_severity(LogTemplate *template, LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_set_severity_new(template, cfg); log_template_unref(template); _perform_rewrite(rewrite, msg_); } static gboolean _msg_severity_equals(LogMessage *msg_, gint sev) { return (msg_->pri & SYSLOG_PRIMASK) == sev; } Test(set_severity, text) { _perform_set_severity(_create_template("error"), msg); cr_assert(_msg_severity_equals(msg, LOG_ERR)); _perform_set_severity(_create_template("crit"), msg); cr_assert(_msg_severity_equals(msg, LOG_CRIT)); _perform_set_severity(_create_template("debug"), msg); cr_assert(_msg_severity_equals(msg, LOG_DEBUG)); } Test(set_severity, numeric) { _perform_set_severity(_create_template("1"), msg); cr_assert(_msg_severity_equals(msg, 1)); } Test(set_severity, test_set_severity_with_various_invalid_values) { debug_flag = 1; int default_severity = msg->pri & SYSLOG_PRIMASK; _perform_set_severity(_create_template("${nonexistentvalue}"), msg); assert_grabbed_log_contains("invalid value passed to set-severity()"); cr_assert(_msg_severity_equals(msg, default_severity), "empty templates should not change the original severity"); reset_grabbed_messages(); _perform_set_severity(_create_template("8"), msg); assert_grabbed_log_contains("invalid value passed to set-severity()"); cr_assert(_msg_severity_equals(msg, default_severity), "too large numeric values should not change the original severity"); reset_grabbed_messages(); _perform_set_severity(_create_template("-1"), msg); assert_grabbed_log_contains("invalid value passed to set-severity()"); cr_assert(_msg_severity_equals(msg, default_severity), "negative values should not change the original severity"); reset_grabbed_messages(); _perform_set_severity(_create_template("random-text"), msg); assert_grabbed_log_contains("invalid value passed to set-severity()"); cr_assert(_msg_severity_equals(msg, default_severity), "non-numeric data should not change the original severity"); } static void setup(void) { app_startup(); cfg = cfg_new_snippet(); start_grabbing_messages(); msg = log_msg_new_empty(); } static void teardown(void) { log_msg_unref(msg); stop_grabbing_messages(); cfg_free(cfg); app_shutdown(); } TestSuite(set_severity, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/rewrite/tests/test_set_tag.c000066400000000000000000000101021450431004300235670ustar00rootroot00000000000000/* * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/msg_parse_lib.h" #include "apphook.h" #include "rewrite/rewrite-set-tag.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" GlobalConfig *cfg = NULL; LogMessage *msg; static LogTemplate * _create_template(const gchar *str) { GError *error = NULL; LogTemplate *template = log_template_new(cfg, NULL); cr_assert(log_template_compile(template, str, &error)); cr_expect_null(error); return template; } static void _perform_rewrite(LogRewrite *rewrite, LogMessage *msg_) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_pipe_init(&rewrite->super); log_pipe_queue(&rewrite->super, log_msg_ref(msg_), &path_options); log_pipe_deinit(&rewrite->super); log_pipe_unref(&rewrite->super); } static void _perform_set_tag(LogTemplate *template, gboolean onoff, LogMessage *msg_) { LogRewrite *rewrite = log_rewrite_set_tag_new(template, onoff, cfg); log_template_unref(template); _perform_rewrite(rewrite, msg_); } Test(set_tag, literal_tags) { _perform_set_tag(_create_template("literal-tag"), TRUE, msg); assert_log_message_has_tag(msg, "literal-tag"); _perform_set_tag(_create_template("literal-tag"), FALSE, msg); assert_log_message_doesnt_have_tag(msg, "literal-tag"); } Test(set_tag, templates_in_set_tag) { log_msg_set_value_by_name(msg, "tag_name", "FOOBAR", -1); _perform_set_tag(_create_template("tag-${tag_name}"), TRUE, msg); log_msg_set_value_by_name(msg, "tag_name", "BARFOO", -1); _perform_set_tag(_create_template("tag-${tag_name}"), TRUE, msg); assert_log_message_has_tag(msg, "tag-FOOBAR"); assert_log_message_has_tag(msg, "tag-BARFOO"); _perform_set_tag(_create_template("tag-${tag_name}"), FALSE, msg); assert_log_message_doesnt_have_tag(msg, "tag-BARFOO"); } Test(set_tag, clone_template) { LogTemplate *template = log_template_new(cfg, "dummy"); cr_assert(log_template_compile(template, "not literal $MESSAGE", NULL)); LogRewrite *rewrite = log_rewrite_set_tag_new(template, true, cfg); LogRewrite *clone = (LogRewrite *)log_pipe_clone(&rewrite->super); cr_assert(log_pipe_init(&rewrite->super)); cr_assert(log_pipe_init(&clone->super)); cr_assert(log_pipe_deinit(&rewrite->super)); cr_assert(log_pipe_deinit(&clone->super)); log_pipe_unref(&rewrite->super); log_pipe_unref(&clone->super); } Test(set_tag, clone_tag_id) { LogTemplate *template = log_template_new(cfg, "dummy"); cr_assert(log_template_compile(template, "syslog", NULL)); LogRewrite *rewrite = log_rewrite_set_tag_new(template, true, cfg); LogRewrite *clone = (LogRewrite *)log_pipe_clone(&rewrite->super); cr_assert(log_pipe_init(&rewrite->super)); cr_assert(log_pipe_init(&clone->super)); cr_assert(log_pipe_deinit(&rewrite->super)); cr_assert(log_pipe_deinit(&clone->super)); log_pipe_unref(&rewrite->super); log_pipe_unref(&clone->super); } static void setup(void) { app_startup(); cfg = cfg_new_snippet(); msg = log_msg_new_empty(); } static void teardown(void) { scratch_buffers_explicit_gc(); log_msg_unref(msg); cfg_free(cfg); app_shutdown(); } TestSuite(set_tag, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/ringbuffer.c000066400000000000000000000071321450431004300204210ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "ringbuffer.h" void ring_buffer_init(RingBuffer *self) { self->head = 0; self->tail = 0; self->count = 0; self->capacity = 0; self->element_size = 0; self->buffer = NULL; } void ring_buffer_alloc(RingBuffer *self, guint32 element_size, guint32 capacity) { g_assert(capacity > 0); self->head = 0; self->tail = 0; self->count = 0; self->capacity = capacity; self->element_size = element_size; self->buffer = g_malloc0((gsize) element_size * self->capacity); } gboolean ring_buffer_is_allocated(RingBuffer *self) { return (self->buffer != NULL); } void ring_buffer_free(RingBuffer *self) { g_free(self->buffer); self->head = 0; self->tail = 0; self->count = 0; self->capacity = 0; self->element_size = 0; self->buffer = NULL; } gboolean ring_buffer_is_full(RingBuffer *self) { return self->capacity == self->count ? TRUE : FALSE; } gboolean ring_buffer_is_empty(RingBuffer *self) { return (self->count == 0) ? TRUE : FALSE; } gpointer ring_buffer_push(RingBuffer *self) { gpointer r = ring_buffer_tail(self); if (!r) return NULL; ++self->count; self->tail = (self->tail + 1) % self->capacity; return r; } gpointer ring_buffer_tail (RingBuffer *self) { g_assert(self->buffer != NULL); if (ring_buffer_is_full(self)) return NULL; gpointer r = (guint8 *) (self->buffer) + self->tail * self->element_size; return r; } gpointer ring_buffer_pop(RingBuffer *self) { g_assert(self->buffer != NULL); if (ring_buffer_is_empty(self)) return NULL; gpointer r = (guint8 *) (self->buffer) + self->head * self->element_size; --self->count; self->head = (self->head + 1) % self->capacity; return r; } gboolean ring_buffer_drop(RingBuffer *self, guint32 n) { g_assert(self->buffer != NULL); if (ring_buffer_count(self) < n) return FALSE; self->count -= n; self->head = (self->head + n) % self->capacity; return TRUE; } guint32 ring_buffer_capacity(RingBuffer *self) { return self->buffer ? self->capacity : 0; } guint32 ring_buffer_count(RingBuffer *self) { return self->count; } gpointer ring_buffer_element_at(RingBuffer *self, guint32 idx) { g_assert(self->buffer != NULL); if (idx >= self->count) return NULL; return (guint8 *) (self->buffer) + ((self->head + idx) % self->capacity) * self->element_size; } guint32 ring_buffer_get_continual_range_length(RingBuffer *self, RingBufferIsContinuousPredicate pred) { guint32 r = 0, i; g_assert(self->buffer != NULL); for (i = 0; i < ring_buffer_count(self); i++) { if (!pred(ring_buffer_element_at(self, i))) { break; } ++r; } return r; } syslog-ng-syslog-ng-4.4.0/lib/ringbuffer.h000066400000000000000000000040421450431004300204230ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef RINGBUFFER_H_INCLUDED #define RINGBUFFER_H_INCLUDED #include typedef struct _RingBuffer { gpointer buffer; guint32 head; guint32 tail; guint32 count; guint32 capacity; guint32 element_size; } RingBuffer; typedef gboolean(*RingBufferIsContinuousPredicate)(gpointer element); void ring_buffer_init(RingBuffer *self); void ring_buffer_alloc(RingBuffer *self, guint32 size_of_element, guint32 capacity); gboolean ring_buffer_is_allocated(RingBuffer *self); void ring_buffer_free(RingBuffer *self); gboolean ring_buffer_is_full(RingBuffer *self); gboolean ring_buffer_is_empty(RingBuffer *self); gpointer ring_buffer_push(RingBuffer *self); gpointer ring_buffer_pop(RingBuffer *self); gpointer ring_buffer_tail(RingBuffer *self); gboolean ring_buffer_drop(RingBuffer *self, guint32 n); guint32 ring_buffer_capacity(RingBuffer *self); guint32 ring_buffer_count(RingBuffer *self); gpointer ring_buffer_element_at(RingBuffer *self, guint32 idx); guint32 ring_buffer_get_continual_range_length(RingBuffer *self, RingBufferIsContinuousPredicate pred); #endif syslog-ng-syslog-ng-4.4.0/lib/run-id.c000066400000000000000000000100611450431004300174610ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "run-id.h" #include "persistable-state-header.h" #include "str-format.h" #include "messages.h" #define RUN_ID_PERSIST_KEY "run_id" int cached_run_id = 0; typedef struct _RunIDState { PersistableStateHeader header; gint run_id; } RunIDState; static void _run_id_set_entry(PersistState *state, PersistEntryHandle handle, guint32 value) { RunIDState *mapped_entry; mapped_entry = persist_state_map_entry(state, handle); mapped_entry->run_id = value; persist_state_unmap_entry(state, handle); } static guint32 _run_id_recover_legacy_entry(PersistState *state, PersistEntryHandle handle) { guint32 old_entry; guint32 *mapped_entry; mapped_entry = persist_state_map_entry(state, handle); old_entry = *mapped_entry; persist_state_unmap_entry(state, handle); return old_entry; } static PersistEntryHandle _run_id_process_existing_entry(PersistState *state, PersistEntryHandle handle, gsize size, guint8 version) { if (size == sizeof(RunIDState)) { return handle; } if (size == sizeof(guint32)) { // In some legacy code we only used a single guint32 value to store the run_id. (without the proper header) // If the size of the entry matches exactly, we convert it. Otherwise we can not use it, and allocate a new one. msg_warning("run-id: persist state: found a legacy run-id state, reinitialize it"); guint32 old_entry = _run_id_recover_legacy_entry(state, handle); PersistEntryHandle new_handle = persist_state_alloc_entry(state, RUN_ID_PERSIST_KEY, sizeof(RunIDState)); if (new_handle) _run_id_set_entry(state, new_handle, old_entry); return new_handle; } msg_warning("run-id: persist state: invalid run-id found, allocating a new state", evt_tag_int("size", size), evt_tag_int("version", version)); return persist_state_alloc_entry(state, RUN_ID_PERSIST_KEY, sizeof(RunIDState)); } static PersistEntryHandle _run_id_get_validated_handle(PersistState *state) { gsize size; guint8 version; PersistEntryHandle handle; handle = persist_state_lookup_entry(state, RUN_ID_PERSIST_KEY, &size, &version); if (handle) { return _run_id_process_existing_entry(state, handle, size, version); } return persist_state_alloc_entry(state, RUN_ID_PERSIST_KEY, sizeof(RunIDState)); } gboolean run_id_init(PersistState *state) { PersistEntryHandle handle; RunIDState *run_id_state; handle = _run_id_get_validated_handle(state); if (handle == 0) { msg_error("run-id: could not allocate persist state"); return FALSE; } run_id_state = persist_state_map_entry(state, handle); run_id_state->run_id++; cached_run_id = run_id_state->run_id; persist_state_unmap_entry(state, handle); return TRUE; }; int run_id_get(void) { return cached_run_id; }; gboolean run_id_is_same_run(gint other_id) { return cached_run_id == other_id; }; void run_id_append_formatted_id(GString *str) { if (cached_run_id) format_uint32_padded(str, 0, 0, 10, cached_run_id); }; void run_id_deinit(void) { cached_run_id = 0; }; syslog-ng-syslog-ng-4.4.0/lib/run-id.h000066400000000000000000000024101450431004300174650ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _RUN_ID_H #define _RUN_ID_H #include "persist-state.h" gboolean run_id_init(PersistState *state); void run_id_deinit(void); int run_id_get(void); gboolean run_id_is_same_run(gint other_run_id); void run_id_append_formatted_id(GString *str); #endif syslog-ng-syslog-ng-4.4.0/lib/scanner/000077500000000000000000000000001450431004300175525ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/CMakeLists.txt000066400000000000000000000007361450431004300223200ustar00rootroot00000000000000add_subdirectory(csv-scanner) add_subdirectory(list-scanner) add_subdirectory(kv-scanner) add_subdirectory(xml-scanner) set(SCANNER_SOURCES scanner/${CSV_SCANNER_SOURCES} scanner/${KV_SCANNER_SOURCES} scanner/${LIST_SCANNER_SOURCES} scanner/${XML_SCANNER_SOURCES} PARENT_SCOPE) set(SCANNER_HEADERS scanner/${CSV_SCANNER_HEADERS} scanner/${KV_SCANNER_HEADERS} scanner/${LIST_SCANNER_HEADERS} scanner/${XML_SCANNER_HEADERS} PARENT_SCOPE) syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/000077500000000000000000000000001450431004300217745ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/CMakeLists.txt000066400000000000000000000003531450431004300245350ustar00rootroot00000000000000set(CSV_SCANNER_HEADERS csv-scanner/csv-scanner.h PARENT_SCOPE) set(CSV_SCANNER_SOURCES csv-scanner/csv-scanner.c PARENT_SCOPE) set(CSV_SCANNER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/Makefile.am000066400000000000000000000005211450431004300240260ustar00rootroot00000000000000csvscannerincludedir = ${pkgincludedir}/scanner/csv-scanner EXTRA_DIST += lib/scanner/CMakeLists.txt \ lib/scanner/csv-scanner/CMakeLists.txt csvscannerinclude_HEADERS = \ lib/scanner/csv-scanner/csv-scanner.h csvscanner_sources = \ lib/scanner/csv-scanner/csv-scanner.c include lib/scanner/csv-scanner/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/csv-scanner.c000066400000000000000000000313131450431004300243630ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "csv-scanner.h" #include "str-utils.h" #include "string-list.h" #include "scratch-buffers.h" #include /************************************************************************ * CSVScannerOptions ************************************************************************/ void csv_scanner_options_set_flags(CSVScannerOptions *options, guint32 flags) { options->flags = flags; } void csv_scanner_options_set_dialect(CSVScannerOptions *options, CSVScannerDialect dialect) { options->dialect = dialect; } void csv_scanner_options_set_columns(CSVScannerOptions *options, GList *columns) { string_list_free(options->columns); options->columns = columns; } void csv_scanner_options_set_delimiters(CSVScannerOptions *options, const gchar *delimiters) { g_free(options->delimiters); options->delimiters = g_strdup(delimiters); } void csv_scanner_options_set_string_delimiters(CSVScannerOptions *options, GList *string_delimiters) { string_list_free(options->string_delimiters); options->string_delimiters = string_delimiters; } void csv_scanner_options_set_quotes_start_and_end(CSVScannerOptions *options, const gchar *quotes_start, const gchar *quotes_end) { g_free(options->quotes_start); g_free(options->quotes_end); options->quotes_start = g_strdup(quotes_start); options->quotes_end = g_strdup(quotes_end); } void csv_scanner_options_set_quotes(CSVScannerOptions *options, const gchar *quotes) { csv_scanner_options_set_quotes_start_and_end(options, quotes, quotes); } void csv_scanner_options_set_quote_pairs(CSVScannerOptions *options, const gchar *quote_pairs) { gint i; g_free(options->quotes_start); g_free(options->quotes_end); options->quotes_start = g_malloc((strlen(quote_pairs) / 2) + 1); options->quotes_end = g_malloc((strlen(quote_pairs) / 2) + 1); for (i = 0; quote_pairs[i] && quote_pairs[i+1]; i += 2) { options->quotes_start[i / 2] = quote_pairs[i]; options->quotes_end[i / 2] = quote_pairs[i + 1]; } options->quotes_start[i / 2] = 0; options->quotes_end[i / 2] = 0; } void csv_scanner_options_set_null_value(CSVScannerOptions *options, const gchar *null_value) { g_free(options->null_value); options->null_value = null_value && null_value[0] ? g_strdup(null_value) : NULL; } void csv_scanner_options_copy(CSVScannerOptions *dst, CSVScannerOptions *src) { csv_scanner_options_set_delimiters(dst, src->delimiters); csv_scanner_options_set_quotes_start_and_end(dst, src->quotes_start, src->quotes_end); csv_scanner_options_set_null_value(dst, src->null_value); csv_scanner_options_set_string_delimiters(dst, string_list_clone(src->string_delimiters)); csv_scanner_options_set_columns(dst, string_list_clone(src->columns)); dst->dialect = src->dialect; dst->flags = src->flags; } void csv_scanner_options_clean(CSVScannerOptions *options) { g_free(options->quotes_start); g_free(options->quotes_end); g_free(options->null_value); g_free(options->delimiters); string_list_free(options->string_delimiters); string_list_free(options->columns); } /************************************************************************ * CSVScanner ************************************************************************/ static gboolean _is_whitespace_char(const gchar *str) { return (*str == ' ' || *str == '\t'); } static void _skip_whitespace(const gchar **src) { while (_is_whitespace_char(*src)) (*src)++; } static void _parse_opening_quote_character(CSVScanner *self) { gchar *quote = _strchr_optimized_for_single_char_haystack(self->options->quotes_start, *self->src); if (quote != NULL) { /* ok, quote character found */ self->src++; self->current_quote = self->options->quotes_end[quote - self->options->quotes_start]; } else { /* we didn't start with a quote character, no need for escaping, delimiter terminates */ self->current_quote = 0; } } static void _parse_left_whitespace(CSVScanner *self) { if ((self->options->flags & CSV_SCANNER_STRIP_WHITESPACE) == 0) return; _skip_whitespace(&self->src); } static gint _decode_xdigit(gchar xdigit) { if (xdigit >= '0' && xdigit <= '9') return xdigit - '0'; if (xdigit >= 'a' && xdigit <= 'f') return xdigit - 'a' + 10; if (xdigit >= 'A' && xdigit <= 'F') return xdigit - 'A' + 10; return -1; } static gint _decode_xbyte(gchar xdigit1, gchar xdigit2) { gint nibble_hi, nibble_lo; nibble_hi = _decode_xdigit(xdigit1); nibble_lo = _decode_xdigit(xdigit2); if (nibble_hi < 0 || nibble_lo < 0) return -1; return (nibble_hi << 4) + nibble_lo; } static void _parse_character_with_quotation(CSVScanner *self) { gchar ch; /* quoted character */ if (self->options->dialect == CSV_SCANNER_ESCAPE_BACKSLASH && *self->src == '\\' && *(self->src + 1)) { self->src++; ch = *self->src; } else if (self->options->dialect == CSV_SCANNER_ESCAPE_BACKSLASH_WITH_SEQUENCES && *self->src == '\\' && *(self->src + 1)) { self->src++; ch = *self->src; if (ch != self->current_quote) { switch (ch) { case 'a': ch = '\a'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'v': ch = '\v'; break; case 'x': if (*(self->src+1) && *(self->src+2)) { ch = _decode_xbyte(*(self->src+1), *(self->src+2)); if (ch >= 0) self->src += 2; else ch = 'x'; } break; default: break; } } } else if (self->options->dialect == CSV_SCANNER_ESCAPE_DOUBLE_CHAR && *self->src == self->current_quote && *(self->src+1) == self->current_quote) { self->src++; ch = *self->src; } else if (*self->src == self->current_quote) { self->current_quote = 0; self->src++; return; } else { ch = *self->src; } g_string_append_c(self->current_value, ch); self->src++; } /* searches for str in list and returns the first occurrence, otherwise NULL */ static gboolean _match_string_delimiters_at_current_position(const char *input, GList *string_delimiters, int *result_length) { GList *l; for (l = string_delimiters; l; l = l->next) { gint len = strlen(l->data); if (strncmp(input, l->data, len) == 0) { *result_length = len; return TRUE; } } return FALSE; } static gboolean _parse_string_delimiters_at_current_position(CSVScanner *self) { gint delim_len; if (!self->options->string_delimiters) return FALSE; if (_match_string_delimiters_at_current_position(self->src, self->options->string_delimiters, &delim_len)) { self->src += delim_len; return TRUE; } return FALSE; } static gboolean _parse_character_delimiters_at_current_position(CSVScanner *self) { if (_strchr_optimized_for_single_char_haystack(self->options->delimiters, *self->src) != NULL) { self->src++; return TRUE; } return FALSE; } static gboolean _parse_delimiter(CSVScanner *self) { if (_parse_string_delimiters_at_current_position(self)) return TRUE; if (_parse_character_delimiters_at_current_position(self)) return TRUE; return FALSE; } static void _parse_unquoted_literal_character(CSVScanner *self) { g_string_append_c(self->current_value, *self->src); self->src++; } static void _parse_value_with_whitespace_and_delimiter(CSVScanner *self) { while (*self->src) { if (self->current_quote) { /* within quotation marks */ _parse_character_with_quotation(self); } else { /* unquoted value */ if (_parse_delimiter(self)) break; _parse_unquoted_literal_character(self); } } } static gint _get_value_length_without_right_whitespace(CSVScanner *self) { gint len = self->current_value->len; while (len > 0 && _is_whitespace_char(self->current_value->str + len - 1)) len--; return len; } static void _translate_rstrip_whitespace(CSVScanner *self) { if (self->options->flags & CSV_SCANNER_STRIP_WHITESPACE) g_string_truncate(self->current_value, _get_value_length_without_right_whitespace(self)); } static void _translate_null_value(CSVScanner *self) { if (self->options->null_value && strcmp(self->current_value->str, self->options->null_value) == 0) g_string_truncate(self->current_value, 0); } static void _translate_value(CSVScanner *self) { _translate_rstrip_whitespace(self); _translate_null_value(self); } static gboolean _is_last_column(CSVScanner *self) { return self->current_column && self->current_column->next == NULL; } static gboolean _switch_to_next_column(CSVScanner *self) { g_string_truncate(self->current_value, 0); switch (self->state) { case CSV_STATE_INITIAL: self->state = CSV_STATE_COLUMNS; self->current_column = self->options->columns; if (self->current_column) return TRUE; self->state = CSV_STATE_FINISH; return FALSE; case CSV_STATE_COLUMNS: case CSV_STATE_GREEDY_COLUMN: self->current_column = self->current_column->next; if (self->current_column) return TRUE; self->state = CSV_STATE_FINISH; return FALSE; case CSV_STATE_PARTIAL_INPUT: case CSV_STATE_FINISH: return FALSE; default: break; } g_assert_not_reached(); } gboolean csv_scanner_scan_next(CSVScanner *self) { if (!_switch_to_next_column(self)) return FALSE; if (_is_last_column(self) && (self->options->flags & CSV_SCANNER_GREEDY)) { _parse_left_whitespace(self); g_string_assign(self->current_value, self->src); self->src += self->current_value->len; self->state = CSV_STATE_GREEDY_COLUMN; _translate_value(self); return TRUE; } else if (self->src[0] == 0) { /* no more input data and a real column, not a greedy one */ self->state = CSV_STATE_PARTIAL_INPUT; return FALSE; } else { _parse_opening_quote_character(self); _parse_left_whitespace(self); _parse_value_with_whitespace_and_delimiter(self); _translate_value(self); return TRUE; } } const gchar * csv_scanner_get_current_name(CSVScanner *self) { if (self->current_column) return (const gchar *) self->current_column->data; else if (self->state == CSV_STATE_INITIAL && self->options->columns) return self->options->columns->data; else return NULL; } gboolean csv_scanner_is_scan_complete(CSVScanner *self) { /* we didn't process all of the input */ if (self->src[0] != 0) return FALSE; return self->state == CSV_STATE_FINISH; } void csv_scanner_init(CSVScanner *scanner, CSVScannerOptions *options, const gchar *input) { memset(scanner, 0, sizeof(*scanner)); scanner->state = CSV_STATE_INITIAL; scanner->src = input; scanner->current_value = scratch_buffers_alloc(); scanner->current_column = NULL; scanner->options = options; } void csv_scanner_deinit(CSVScanner *self) { } const gchar * csv_scanner_get_current_value(CSVScanner *self) { return self->current_value->str; } gint csv_scanner_get_current_value_len(CSVScanner *self) { return self->current_value->len; } gchar * csv_scanner_dup_current_value(CSVScanner *self) { return g_strndup(csv_scanner_get_current_value(self), csv_scanner_get_current_value_len(self)); } syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/csv-scanner.h000066400000000000000000000065661450431004300244040ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CSVSCANNER_H_INCLUDED #define CSVSCANNER_H_INCLUDED #include "syslog-ng.h" typedef enum { CSV_SCANNER_ESCAPE_NONE, CSV_SCANNER_ESCAPE_BACKSLASH, CSV_SCANNER_ESCAPE_BACKSLASH_WITH_SEQUENCES, CSV_SCANNER_ESCAPE_DOUBLE_CHAR, } CSVScannerDialect; #define CSV_SCANNER_STRIP_WHITESPACE 0x0001 #define CSV_SCANNER_GREEDY 0x0002 typedef struct _CSVScannerOptions { GList *columns; gchar *delimiters; gchar *quotes_start; gchar *quotes_end; gchar *null_value; GList *string_delimiters; CSVScannerDialect dialect; guint32 flags; } CSVScannerOptions; void csv_scanner_options_clean(CSVScannerOptions *options); void csv_scanner_options_copy(CSVScannerOptions *dst, CSVScannerOptions *src); void csv_scanner_options_set_dialect(CSVScannerOptions *options, CSVScannerDialect dialect); void csv_scanner_options_set_flags(CSVScannerOptions *options, guint32 flags); void csv_scanner_options_set_columns(CSVScannerOptions *options, GList *columns); void csv_scanner_options_set_delimiters(CSVScannerOptions *options, const gchar *delimiters); void csv_scanner_options_set_string_delimiters(CSVScannerOptions *options, GList *string_delimiters); void csv_scanner_options_set_quotes_start_and_end(CSVScannerOptions *options, const gchar *quotes_start, const gchar *quotes_end); void csv_scanner_options_set_quotes(CSVScannerOptions *options, const gchar *quotes); void csv_scanner_options_set_quote_pairs(CSVScannerOptions *options, const gchar *quote_pairs); void csv_scanner_options_set_null_value(CSVScannerOptions *options, const gchar *null_value); typedef struct { CSVScannerOptions *options; enum { CSV_STATE_INITIAL, CSV_STATE_COLUMNS, CSV_STATE_GREEDY_COLUMN, CSV_STATE_PARTIAL_INPUT, CSV_STATE_FINISH, } state; GList *current_column; const gchar *src; GString *current_value; gchar current_quote; } CSVScanner; const gchar *csv_scanner_get_current_name(CSVScanner *pstate); const gchar *csv_scanner_get_current_value(CSVScanner *pstate); gint csv_scanner_get_current_value_len(CSVScanner *self); gboolean csv_scanner_scan_next(CSVScanner *pstate); gboolean csv_scanner_is_scan_complete(CSVScanner *pstate); gchar *csv_scanner_dup_current_value(CSVScanner *self); void csv_scanner_init(CSVScanner *pstate, CSVScannerOptions *options, const gchar *input); void csv_scanner_deinit(CSVScanner *pstate); #endif syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/tests/000077500000000000000000000000001450431004300231365ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/tests/CMakeLists.txt000066400000000000000000000001371450431004300256770ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_csv_scanner INCLUDES "${CSV_SCANNER_INCLUDE_DIR}") syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/tests/Makefile.am000066400000000000000000000005651450431004300252000ustar00rootroot00000000000000lib_csv_scanner_tests_TESTS = \ lib/scanner/csv-scanner/tests/test_csv_scanner EXTRA_DIST += lib/scanner/csv-scanner/tests/CMakeLists.txt check_PROGRAMS += ${lib_csv_scanner_tests_TESTS} lib_scanner_csv_scanner_tests_test_csv_scanner_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/scanner/csv-scanner lib_scanner_csv_scanner_tests_test_csv_scanner_LDADD = $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/scanner/csv-scanner/tests/test_csv_scanner.c000066400000000000000000000272251450431004300266550ustar00rootroot00000000000000/* * Copyright (c) 2015-2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "scratch-buffers.h" #include "apphook.h" #include "csv-scanner.h" #include "string-list.h" CSVScannerOptions options; CSVScanner scanner; CSVScannerOptions * _default_options(const gchar *columns[]) { csv_scanner_options_clean(&options); csv_scanner_options_set_delimiters(&options, ","); csv_scanner_options_set_quote_pairs(&options, "\"\"''"); csv_scanner_options_set_flags(&options, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_DOUBLE_CHAR); csv_scanner_options_set_columns(&options, string_array_to_list(columns)); return &options; } CSVScannerOptions * _default_options_with_flags(const gchar *columns[], gint flags) { CSVScannerOptions *o; o = _default_options(columns); csv_scanner_options_set_flags(&options, flags); return o; } static gboolean _column_name_equals(const gchar *name) { return strcmp(csv_scanner_get_current_name(&scanner), name) == 0; } static gboolean _column_name_unset(void) { return csv_scanner_get_current_name(&scanner) == NULL; } static gboolean _column_nv_equals(const gchar *name, const gchar *value) { return _column_name_equals(name) && strcmp(csv_scanner_get_current_value(&scanner), value) == 0; } static gboolean _scan_complete(void) { return csv_scanner_is_scan_complete(&scanner); } static gboolean _scan_next(void) { return csv_scanner_scan_next(&scanner); } Test(csv_scanner, simple_comma_separate_values) { const gchar *columns[] = { "foo", "bar", "baz", NULL }; csv_scanner_init(&scanner, _default_options(columns), "val1,val2,val3"); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("foo", "val1")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("bar", "val2")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("baz", "val3")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, null_value) { const gchar *columns[] = { "foo", "bar", "baz", NULL }; _default_options(columns); csv_scanner_options_set_null_value(&options, "null"); csv_scanner_init(&scanner, &options, "val1,null,val3"); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("foo", "val1")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("bar", "")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("baz", "val3")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, empty_input_with_some_expected_columns) { const gchar *columns[] = { "foo", "bar", "baz", NULL }; csv_scanner_init(&scanner, _default_options(columns), ""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(!_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); csv_scanner_deinit(&scanner); } Test(csv_scanner, empty_input_with_no_columns) { const gchar *columns[] = { NULL }; csv_scanner_init(&scanner, _default_options(columns), ""); cr_expect(_column_name_unset()); cr_expect(!_scan_complete()); cr_expect(!_scan_next()); cr_expect(_column_name_unset()); cr_expect(_scan_complete()); csv_scanner_deinit(&scanner); } Test(csv_scanner, partial_input) { const gchar *columns[] = { "foo", "bar", "baz", NULL }; csv_scanner_init(&scanner, _default_options(columns), "val1,val2"); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("foo", "val1")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_nv_equals("bar", "val2")); cr_expect(!_scan_complete()); cr_expect(!_scan_next()); cr_expect(_column_name_equals("baz")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(!_scan_complete()); cr_expect(_column_name_equals("baz")); csv_scanner_deinit(&scanner); } Test(csv_scanner, greedy_column) { const gchar *columns[] = { "foo", "bar", NULL }; csv_scanner_init(&scanner, _default_options_with_flags(columns, CSV_SCANNER_GREEDY), "foo,bar,baz"); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "bar,baz")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, greedy_column_strip_whitespace) { const gchar *columns[] = { "foo", "bar", NULL }; csv_scanner_init(&scanner, _default_options_with_flags(columns, CSV_SCANNER_GREEDY|CSV_SCANNER_STRIP_WHITESPACE), "foo, bar,baz "); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "bar,baz")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, greedy_column_null_value) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_GREEDY|CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_null_value(&options, "bar,baz"); csv_scanner_init(&scanner, &options, "foo, bar,baz "); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, escape_double_char) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_DOUBLE_CHAR); csv_scanner_init(&scanner, &options, "foo,\"this is a single quote \"\" character\""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "this is a single quote \" character")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, escape_backslash) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_BACKSLASH); csv_scanner_init(&scanner, &options, "foo,\"this is a single quote \\\" character\\n\""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "this is a single quote \" charactern")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, escape_backslash_sequences) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_BACKSLASH_WITH_SEQUENCES); csv_scanner_init(&scanner, &options, "foo,\"\\\"\\a\\t\\v\\r\\n\\\"\""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "\"\a\t\v\r\n\"")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, escape_backslash_x_sequences) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_BACKSLASH_WITH_SEQUENCES); csv_scanner_init(&scanner, &options, "foo,\"\\x41\\x00\\x40\""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "A\x00@")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } Test(csv_scanner, escape_backslash_invalid_x_sequence) { const gchar *columns[] = { "foo", "bar", NULL }; _default_options_with_flags(columns, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&options, CSV_SCANNER_ESCAPE_BACKSLASH_WITH_SEQUENCES); csv_scanner_init(&scanner, &options, "foo,\"\\x4Q\""); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("foo")); cr_expect(!_scan_complete()); cr_expect(_scan_next()); cr_expect(_column_name_equals("bar")); cr_expect(_column_nv_equals("bar", "x4Q")); cr_expect(!_scan_complete()); /* go past the last column */ cr_expect(!_scan_next()); cr_expect(_scan_complete()); cr_expect(_column_name_unset()); csv_scanner_deinit(&scanner); } static void setup(void) { app_startup(); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(csv_scanner, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/000077500000000000000000000000001450431004300216215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/CMakeLists.txt000066400000000000000000000003441450431004300243620ustar00rootroot00000000000000set(KV_SCANNER_HEADERS kv-scanner/kv-scanner.h PARENT_SCOPE) set(KV_SCANNER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(KV_SCANNER_SOURCES kv-scanner/kv-scanner.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/Makefile.am000066400000000000000000000004511450431004300236550ustar00rootroot00000000000000kvscannerincludedir = ${pkgincludedir}/scanner/kv-scanner EXTRA_DIST += lib/scanner/kv-scanner/CMakeLists.txt kvscannerinclude_HEADERS = \ lib/scanner/kv-scanner/kv-scanner.h kvscanner_sources = \ lib/scanner/kv-scanner/kv-scanner.c include lib/scanner/kv-scanner/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/kv-scanner.c000066400000000000000000000202301450431004300240310ustar00rootroot00000000000000/* * Copyright (c) 2015-2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "kv-scanner.h" #include "str-repr/decode.h" #include "str-repr/encode.h" #include "scratch-buffers.h" #include static inline gboolean _is_valid_key_character(gchar c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '-'); } static inline const gchar * _locate_separator(KVScanner *self, const gchar *start) { return strchr(start, self->value_separator); } static inline void _locate_start_of_key(KVScanner *self, const gchar *end_of_key, const gchar **start_of_key) { const gchar *input = &self->input[self->input_pos]; const gchar *cur; cur = end_of_key; while (cur > input && self->is_valid_key_character(*(cur - 1))) cur--; *start_of_key = cur; } static inline void _locate_end_of_key(KVScanner *self, const gchar *separator, const gchar **end_of_key) { const gchar *input = &self->input[self->input_pos]; const gchar *cur; /* this function locates the character pointing right next to the end of * the key, e.g. with this input * foo = bar * * it would start with the '=' sign and skip spaces backwards, to locate * the space right next to "foo" */ cur = separator; while (cur > input && (*(cur - 1)) == ' ') cur--; *end_of_key = cur; } static inline gboolean _extract_key_from_positions(KVScanner *self, const gchar *start_of_key, const gchar *end_of_key) { gint len = end_of_key - start_of_key; if (len >= 1) { g_string_assign_len(self->key, start_of_key, len); return TRUE; } return FALSE; } static inline void _extract_stray_word(KVScanner *self, const gchar *stray_word, gssize len) { if (len < 0) len = strlen(stray_word); if (self->stray_words && len > 0) { while (len > 0 && stray_word[len - 1] == ' ') len--; while (len > 0 && stray_word[0] == ' ') { stray_word++; len--; } if (len > 0) { if (self->stray_words->len) g_string_append_c(self->stray_words, ','); str_repr_encode_append(self->stray_words, stray_word, len, ","); } } } static gboolean _should_stop(KVScanner *self) { const gchar *input = &self->input[self->input_pos]; return *input == self->stop_char; } static gboolean _extract_key(KVScanner *self) { const gchar *input = &self->input[self->input_pos]; const gchar *start_of_key, *end_of_key; const gchar *separator; separator = _locate_separator(self, input); while (separator) { _locate_end_of_key(self, separator, &end_of_key); _locate_start_of_key(self, end_of_key, &start_of_key); if (_extract_key_from_positions(self, start_of_key, end_of_key)) { _extract_stray_word(self, input, start_of_key - input); self->input_pos = separator - self->input + 1; return TRUE; } separator = _locate_separator(self, separator + 1); } _extract_stray_word(self, input, -1); return FALSE; } static gboolean _is_quoted(const gchar *input) { return *input == '\'' || *input == '\"'; } static gboolean _key_follows(KVScanner *self, const gchar *cur) { const gchar *key = cur; while (self->is_valid_key_character(*key)) key++; while (*key == ' ') key++; return (key != cur) && (*key == self->value_separator); } static inline void _skip_spaces(const gchar **input) { const gchar *cur = *input; while (*cur == ' ') cur++; *input = cur; } static inline gboolean _end_of_string(const gchar *cur) { return *cur == 0; } static inline gboolean _pair_separator(KVScanner *self, const gchar *cur, const gchar **new_cur) { if (self->pair_separator && (strncmp(cur, self->pair_separator, self->pair_separator_len) == 0)) { *new_cur = cur + self->pair_separator_len; return TRUE; } return FALSE; } static inline gboolean _pair_separator_starts_with_a_space(KVScanner *self) { return (self->pair_separator && self->pair_separator[0] == ' '); } static gboolean _match_delimiter(const gchar *cur, const gchar **new_cur, gpointer user_data) { KVScanner *self = (gpointer) user_data; gboolean result = FALSE; if (!self->value_was_quoted && *cur == ' ') { if (_pair_separator_starts_with_a_space(self) && _pair_separator(self, cur, new_cur)) { result = TRUE; } else { _skip_spaces(&cur); if (_end_of_string(cur) || _key_follows(self, cur)) { *new_cur = cur; result = TRUE; } else if (_pair_separator(self, cur, new_cur)) { result = TRUE; } } } else if (*cur == ' ') { result = TRUE; *new_cur = cur + 1; } else if (*cur == self->stop_char) { result = TRUE; *new_cur = cur; } else { result = _pair_separator(self, cur, new_cur); } return result; } static inline void _skip_initial_spaces(KVScanner *self) { const gchar *input = &self->input[self->input_pos]; const gchar *end; while (*input == ' ' && !_match_delimiter(input, &end, self)) input++; self->input_pos = input - self->input; } static inline void _decode_value(KVScanner *self) { const gchar *input = &self->input[self->input_pos]; const gchar *end; StrReprDecodeOptions options = { .match_delimiter = _match_delimiter, .match_delimiter_data = self, .delimiter_chars = { ' ', self->pair_separator[0], self->stop_char }, }; self->value_was_quoted = _is_quoted(input); if (str_repr_decode_with_options(self->value, input, &end, &options)) { self->input_pos = end - self->input; } else { /* quotation error, set was_quoted to FALSE */ self->value_was_quoted = FALSE; } } static void _extract_optional_annotation(KVScanner *self) { if (self->extract_annotation) self->extract_annotation(self); } static void _extract_value(KVScanner *self) { self->value_was_quoted = FALSE; _skip_initial_spaces(self); _decode_value(self); } static inline void _transform_value(KVScanner *self) { if (self->transform_value) { g_string_truncate(self->decoded_value, 0); if (self->transform_value(self)) g_string_assign_len(self->value, self->decoded_value->str, self->decoded_value->len); } } gboolean kv_scanner_scan_next(KVScanner *s) { KVScanner *self = (KVScanner *)s; if (_should_stop(self)) return FALSE; if (!_extract_key(self)) return FALSE; _extract_optional_annotation(self); _extract_value(self); _transform_value(s); return TRUE; } void kv_scanner_deinit(KVScanner *self) { } void kv_scanner_init(KVScanner *self, gchar value_separator, const gchar *pair_separator, gboolean extract_stray_words) { memset(self, 0, sizeof(*self)); self->key = scratch_buffers_alloc(); self->value = scratch_buffers_alloc(); self->decoded_value = scratch_buffers_alloc(); if (extract_stray_words) self->stray_words = scratch_buffers_alloc(); self->value_separator = value_separator; self->pair_separator = pair_separator ? : ", "; self->pair_separator_len = strlen(self->pair_separator); self->is_valid_key_character = _is_valid_key_character; self->stop_char = 0; } syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/kv-scanner.h000066400000000000000000000057741450431004300240560ustar00rootroot00000000000000/* * Copyright (c) 2015-2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef KV_SCANNER_H_INCLUDED #define KV_SCANNER_H_INCLUDED #include "syslog-ng.h" #include "str-utils.h" typedef struct _KVScanner KVScanner; typedef gboolean (*KVTransformValueFunc)(KVScanner *); typedef void (*KVExtractAnnotationFunc)(KVScanner *); typedef gboolean (*KVIsValidKeyCharFunc)(gchar c); struct _KVScanner { const gchar *input; gsize input_pos; GString *key; GString *value; GString *decoded_value; GString *stray_words; gboolean value_was_quoted; gchar value_separator; const gchar *pair_separator; gsize pair_separator_len; gchar stop_char; KVTransformValueFunc transform_value; KVExtractAnnotationFunc extract_annotation; KVIsValidKeyCharFunc is_valid_key_character; }; void kv_scanner_init(KVScanner *self, gchar value_separator, const gchar *pair_separator, gboolean extract_stray_words); void kv_scanner_deinit(KVScanner *self); static inline void kv_scanner_input(KVScanner *self, const gchar *input) { self->input = input; self->input_pos = 0; if (self->stray_words) g_string_truncate(self->stray_words, 0); } static inline const gchar * kv_scanner_get_current_key(KVScanner *self) { return self->key->str; } static inline const gchar * kv_scanner_get_current_value(KVScanner *self) { return self->value->str; } static inline const gchar * kv_scanner_get_stray_words(KVScanner *self) { return self->stray_words ? self->stray_words->str : NULL; } static inline void kv_scanner_set_transform_value(KVScanner *self, KVTransformValueFunc transform_value) { self->transform_value = transform_value; } static inline void kv_scanner_set_extract_annotation_func(KVScanner *self, KVExtractAnnotationFunc extract_annotation) { self->extract_annotation = extract_annotation; } static inline void kv_scanner_set_valid_key_character_func(KVScanner *self, KVIsValidKeyCharFunc is_valid_key_character) { self->is_valid_key_character = is_valid_key_character; } static inline void kv_scanner_set_stop_character(KVScanner *self, gchar stop_char) { self->stop_char = stop_char; } gboolean kv_scanner_scan_next(KVScanner *self); #endif syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/tests/000077500000000000000000000000001450431004300227635ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/tests/CMakeLists.txt000066400000000000000000000001351450431004300255220ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_kv_scanner INCLUDES "${KV_SCANNER_INCLUDE_DIR}") syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/tests/Makefile.am000066400000000000000000000005531450431004300250220ustar00rootroot00000000000000lib_kv_scanner_tests_TESTS = \ lib/scanner/kv-scanner/tests/test_kv_scanner EXTRA_DIST += lib/scanner/kv-scanner/tests/CMakeLists.txt check_PROGRAMS += ${lib_kv_scanner_tests_TESTS} lib_scanner_kv_scanner_tests_test_kv_scanner_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/scanner/kv-scanner lib_scanner_kv_scanner_tests_test_kv_scanner_LDADD = $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/scanner/kv-scanner/tests/test_kv_scanner.c000066400000000000000000000733031450431004300263250ustar00rootroot00000000000000/* * Copyright (c) 2015-2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/stopwatch.h" #include "scratch-buffers.h" #include "apphook.h" #include "kv-scanner.h" #include static gboolean _expect_no_more_tokens(KVScanner *scanner, gchar **error) { GString *msg; gboolean ok = kv_scanner_scan_next(scanner); if (ok) { msg = g_string_new("kv_scanner is expected to return no more key-value pairs "); do { const gchar *key = kv_scanner_get_current_key(scanner); if (!key) key = ""; const gchar *value = kv_scanner_get_current_value(scanner); if (!value) value = ""; g_string_append_printf(msg, "[%s/%s]", key, value); } while (kv_scanner_scan_next(scanner)); *error = g_string_free(msg, FALSE); return FALSE; } return TRUE; } static gboolean _expect_current_key_equals(KVScanner *scanner, const gchar *expected_key, gchar **error) { const gchar *key = kv_scanner_get_current_key(scanner); if (strcmp(key, expected_key) != 0) { *error = g_strdup_printf("expected key mismatch key=%s, expected=%s", key, expected_key); return FALSE; } return TRUE; } static gboolean _expect_current_value_equals(KVScanner *scanner, const gchar *expected_value, gchar **error) { const gchar *value = kv_scanner_get_current_value(scanner); if (strcmp(value, expected_value) != 0) { *error = g_strdup_printf("expected value mismatch value=%s, expected=%s", value, expected_value); return FALSE; } return TRUE; } static gboolean _expect_next_key_value(KVScanner *scanner, const gchar *key, const gchar *value, gchar **error) { g_assert(value); gboolean ok = kv_scanner_scan_next(scanner); if (ok) { return _expect_current_key_equals(scanner, key, error) && _expect_current_value_equals(scanner, value, error); } else { *error = g_strdup_printf("kv_scanner is expected to return TRUE for scan_next(), " "first unconsumed pair: [%s/%s]", key, value); } return FALSE; } typedef struct _ScannerConfig { gchar kv_separator; const gchar *pair_separator; gboolean extract_stray_words; KVTransformValueFunc transform_value; } ScannerConfig; typedef struct _KVQElement { const gchar *const key; const gchar *const value; gboolean quoted; } KVQElement; typedef struct _KVQContainer { const gsize n; const KVQElement arg[8]; } KVQContainer; typedef struct _KVElement { const gchar *key; const gchar *value; } KVElement; typedef struct _KVContainer { gsize n; const KVElement arg[32]; } KVContainer; typedef struct Testcase_t { gchar *input; KVContainer expected; } Testcase; static KVScanner * create_kv_scanner(const ScannerConfig *config) { KVScanner *scanner = g_new(KVScanner, 1); kv_scanner_init(scanner, config->kv_separator, config->pair_separator, config->extract_stray_words); kv_scanner_set_transform_value(scanner, config->transform_value); return scanner; } static inline void kv_scanner_free(KVScanner *scanner) { g_free(scanner); } #define VARARG_STRUCT(VARARG_STRUCT_cont, VARARG_STRUCT_elem, ...) \ (const VARARG_STRUCT_cont) { \ .n = sizeof((const VARARG_STRUCT_elem[]) { __VA_ARGS__ }) / sizeof(VARARG_STRUCT_elem), \ .arg = {__VA_ARGS__}\ } static gboolean _expect_kv_pairs(KVScanner *scanner, KVContainer args, gchar **error) { for (gsize i = 0; i < args.n; i++) { if (!_expect_next_key_value(scanner, args.arg[i].key, args.arg[i].value, error)) { return FALSE; } } return _expect_no_more_tokens(scanner, error); } static gboolean _expect_kvq_triplets(KVScanner *scanner, KVQContainer args, gchar **error) { for (gsize i = 0; i < args.n; i++) { if (!_expect_next_key_value(scanner, args.arg[i].key, args.arg[i].value, error)) return FALSE; if (scanner->value_was_quoted != args.arg[i].quoted) { *error = g_strdup_printf("mismatch in value_was_quoted for [%s/%s]", args.arg[i].key, args.arg[i].value); return FALSE; } } return _expect_no_more_tokens(scanner, error); } #define INIT_KVQCONTAINER(...) VARARG_STRUCT(KVQContainer, KVQElement, __VA_ARGS__) #define _IMPL_EXPECT_KVQ(SCANNER_config, TEST_KV_SCAN_input, ...) \ do { \ KVScanner *scanner = create_kv_scanner(&SCANNER_config); \ gchar *error = NULL; \ \ kv_scanner_input(scanner, TEST_KV_SCAN_input); \ if (!_expect_kvq_triplets(scanner, INIT_KVQCONTAINER(__VA_ARGS__), &error)) \ { \ cr_expect(FALSE, "%s", error); \ g_free(error);\ } \ kv_scanner_free(scanner); \ } while (0) #define _EXPECT_KVQ_TRIPLETS(...) \ do { \ _IMPL_EXPECT_KVQ(((ScannerConfig) {'='}), __VA_ARGS__); \ } while(0) #define INIT_KVCONTAINER(...) VARARG_STRUCT(KVContainer, KVElement, __VA_ARGS__) #define _IMPL_EXPECT_KV(TEST_KV_SCAN_config, TEST_KV_SCAN_input, ...) \ do { \ KVScanner *scanner = create_kv_scanner(&TEST_KV_SCAN_config); \ gchar *error = NULL; \ \ kv_scanner_input(scanner, TEST_KV_SCAN_input); \ if (!_expect_kv_pairs(scanner, INIT_KVCONTAINER(__VA_ARGS__), &error)) \ { \ cr_expect(FALSE, "%s", error); \ g_free(error);\ } \ cr_expect_eq(kv_scanner_get_stray_words(scanner), NULL, \ "stray words are not expected but still returned"); \ kv_scanner_free(scanner); \ } while (0) #define _EXPECT_KV_PAIRS(...) \ do { \ _IMPL_EXPECT_KV(((ScannerConfig) {'='}), __VA_ARGS__); \ } while (0) #define _EXPECT_KV_PAIRS_WITH_CONFIG(TEST_KV_SCAN_config, ...) \ do { \ _IMPL_EXPECT_KV(TEST_KV_SCAN_config, __VA_ARGS__); \ } while (0) #define _EXPECT_KV_AND_STRAY_WORDS(INPUT, STRAY, ...) \ do { \ KVScanner *scanner = create_kv_scanner(&((ScannerConfig) { \ .kv_separator = '=', \ .extract_stray_words=TRUE})); \ gchar *error = NULL; \ \ kv_scanner_input(scanner, INPUT); \ if (!_expect_kv_pairs(scanner, INIT_KVCONTAINER(__VA_ARGS__), &error)) \ { \ cr_expect(FALSE, "%s", error); \ g_free(error);\ } \ cr_expect_str_eq(kv_scanner_get_stray_words(scanner), STRAY, \ "Stray words mismatch, value=%s, expected=%s", \ kv_scanner_get_stray_words(scanner), STRAY); \ kv_scanner_free(scanner); \ } while (0) Test(kv_scanner, incomplete_string_returns_no_pairs) { _EXPECT_KV_PAIRS(""); _EXPECT_KV_PAIRS("f"); _EXPECT_KV_PAIRS("fo"); _EXPECT_KV_PAIRS("foo"); } Test(kv_scanner, name_equals_value_returns_a_pair) { _EXPECT_KV_PAIRS("foo=", { "foo", "" }); _EXPECT_KV_PAIRS("foo=b", { "foo", "b" }); _EXPECT_KV_PAIRS("foo=bar", { "foo", "bar" }); _EXPECT_KV_PAIRS("foo=barbar", { "foo", "barbar" }); } Test(kv_scanner, allowed_characters_in_a_key_are_letters_digits_dash_underscore_and_dot) { _EXPECT_KV_PAIRS("FOOfoo123-_._-321oofOOF=value", {"FOOfoo123-_._-321oofOOF", "value"}); } Test(kv_scanner, initial_stray_words_are_ignored) { _EXPECT_KV_PAIRS("lorem ipsum foo=bar", { "foo", "bar" }); _EXPECT_KV_PAIRS("lorem ipsum/dolor @sitamen foo=bar", { "foo", "bar" }); _EXPECT_KV_PAIRS("lorem ipsum/dolor = foo=bar\"", { "dolor", "" }, { "foo", "bar\"" }); _EXPECT_KV_PAIRS("a b c=d", {"c", "d"}); _EXPECT_KV_PAIRS("x *k=v", { "k", "v" }); } Test(kv_scanner, non_initial_stray_words_are_added_to_the_last_value) { _EXPECT_KV_PAIRS("foo=bar lorem ipsum key=value some more values", { "foo", "bar lorem ipsum" }, { "key", "value some more values" }); } Test(kv_scanner, empty_values_in_a_series_of_key_values) { _EXPECT_KV_PAIRS("k= a=b c=d", {"k", ""}, {"a", "b"}, {"c", "d"}); _EXPECT_KV_PAIRS("k=v a= c=d", {"k", "v"}, {"a", ""}, {"c", "d"}); _EXPECT_KV_PAIRS("k=v a=b c=", {"k", "v"}, {"a", "b"}, {"c", ""}); } Test(kv_scanner, multiple_key_values_return_multiple_pairs) { _EXPECT_KV_PAIRS("key1=value1 key2=value2 key3=value3 ", { "key1", "value1" }, { "key2", "value2" }, { "key3", "value3" }); } Test(kv_scanner, spaces_between_values_are_ignored) { _EXPECT_KV_PAIRS("key1=value1 key2=value2 key3=value3 ", { "key1", "value1" }, { "key2", "value2" }, { "key3", "value3" }); } Test(kv_scanner, comma_separated_values) { _EXPECT_KV_PAIRS("key1=value1, key2=value2, key3=value3", { "key1", "value1" }, { "key2", "value2" }, { "key3", "value3" }); /* NOTE: comma on its own is not a delimiter, as the default delimiter is ", " * A testcase below would test single character separator with ';' */ _EXPECT_KV_PAIRS("key1=value1,key2=value2,key3=value3", { "key1", "value1,key2=value2,key3=value3" }); /* In value2 the spaces are considered part of the value as we don't have * a delimiter and spaces get concatenated into the value */ _EXPECT_KV_PAIRS("key1=value1, key2=value2 , key3=value3", { "key1", "value1" }, { "key2", "value2" }, { "key3", "value3" }); } Test(kv_scanner, tab_is_not_considered_a_separator) { _EXPECT_KV_PAIRS("key1=value1\tkey2=value2 key3=value3", { "key1", "value1\tkey2=value2" }, { "key3", "value3" }); _EXPECT_KV_PAIRS("key1=value1,\tkey2=value2 key3=value3", { "key1", "value1,\tkey2=value2" }, { "key3", "value3" }); _EXPECT_KV_PAIRS("key1=value1\t key2=value2 key3=value3", { "key1", "value1\t" }, { "key2", "value2" }, { "key3", "value3" }); _EXPECT_KV_PAIRS("k=\t", { "k", "\t" }); _EXPECT_KV_PAIRS("k=,\t", { "k", ",\t" }); } Test(kv_scanner, quoted_values_are_unquoted_like_c_strings) { _EXPECT_KV_PAIRS("foo=\"\\\"\" bar=baz", { "foo", "\"" }, { "bar", "baz"}); _EXPECT_KV_PAIRS("foo='\"' bar=baz", { "foo", "\"" }, { "bar", "baz"}); _EXPECT_KV_PAIRS("foo=\"bar\"", { "foo", "bar" }); _EXPECT_KV_PAIRS("key1=\"value1\" key2=\"value2\"", { "key1", "value1" }, { "key2", "value2" }); /* embedded quote */ _EXPECT_KV_PAIRS("key1=\"\\\"value1\"", { "key1", "\"value1" }); /* control sequences */ _EXPECT_KV_PAIRS("key1=\"\\b \\f \\n \\r \\t \\\\\"", { "key1", "\b \f \n \r \t \\" }); /* unknown backslash escape is left as is */ _EXPECT_KV_PAIRS("key1=\"\\p\"", { "key1", "\\p" }); _EXPECT_KV_PAIRS("key1='value1' key2='value2'", { "key1", "value1" }, { "key2", "value2" }); /* embedded quote */ _EXPECT_KV_PAIRS("key1='\\'value1'", { "key1", "'value1" }); /* control sequences */ _EXPECT_KV_PAIRS("key1='\\b \\f \\n \\r \\t \\\\'", { "key1", "\b \f \n \r \t \\" }); /* unknown backslash escape is left as is */ _EXPECT_KV_PAIRS("key1='\\p'", { "key1", "\\p" }); _EXPECT_KV_PAIRS("key1=\\b\\f\\n\\r\\t\\\\", { "key1", "\\b\\f\\n\\r\\t\\\\" }); _EXPECT_KV_PAIRS("key1=\b\f\n\r\\", { "key1", "\b\f\n\r\\" }); _EXPECT_KV_PAIRS("foo=\"bar baz\"", {"foo", "bar baz"}); } Test(kv_scanner, quotes_embedded_in_an_unquoted_value_are_left_intact) { _EXPECT_KV_PAIRS("foo=a \"bar baz\" ", {"foo", "a \"bar baz\""}); _EXPECT_KV_PAIRS("foo=a \"bar baz", {"foo", "a \"bar baz"}); _EXPECT_KV_PAIRS("foo=a \"bar baz c=d", {"foo", "a \"bar baz"}, {"c", "d"}); _EXPECT_KV_PAIRS("foo=a \"bar baz\"=f c=d a", {"foo", "a \"bar baz\"=f"}, {"c", "d a"}); _EXPECT_KV_PAIRS("foo=\\\"bar baz\\\"", {"foo", "\\\"bar baz\\\""}); } Test(kv_scanner, separator_in_an_unquoted_value_is_taken_literally) { _EXPECT_KV_PAIRS("k=a=b c=d", {"k", "a=b"}, {"c", "d"}); _EXPECT_KV_PAIRS("a==b=", {"a", "=b="}); _EXPECT_KV_PAIRS("a=,=b=a", {"a", ",=b=a"}); _EXPECT_KV_PAIRS("a= =a", {"a", "=a"}); } Test(kv_scanner, keys_without_value_separator_are_ignored) { _EXPECT_KV_PAIRS("key1 key2=value2 key3 key4=value4", { "key2", "value2 key3" }, { "key4", "value4" }); _EXPECT_KV_PAIRS("key1= key2=value2 key3= key4=value4 key5= key6=value6", { "key1", "" }, { "key2", "value2" }, { "key3", "" }, { "key4", "value4" }, { "key5", "" }, { "key6", "value6" }); } Test(kv_scanner, quoted_values_are_considered_one_token_thus_space_based_concatenation_does_not_happen) { _EXPECT_KV_PAIRS("key1=\"value foo\" key2=marker", { "key1", "value foo" }, { "key2", "marker" }); _EXPECT_KV_PAIRS("key1=\"value foo embedded_key=emb_value\" key2=marker", { "key1", "value foo embedded_key=emb_value" }, { "key2", "marker" }); /* embedded quote */ _EXPECT_KV_PAIRS("key1=\"value foo\\\"\" key2=marker", { "key1", "value foo\"" }, { "key2", "marker" }); _EXPECT_KV_PAIRS("key1='value foo\\'' key2=marker", { "key1", "value foo'" }, { "key2", "marker" }); _EXPECT_KV_PAIRS("key1=\"value foo, foo2 =@,\\\"\" key2='value foo, a='", { "key1", "value foo, foo2 =@,\"" }, { "key2", "value foo, a=" }); /* NOTE: baz is not added to the value, it is a stray word */ _EXPECT_KV_PAIRS("foo=\"bar\" baz c=d", {"foo", "bar"}, {"c", "d"}); } static gboolean _parse_value_by_incrementing_all_bytes(KVScanner *self) { gint i; g_string_assign(self->decoded_value, self->value->str); for (i = 0; i < self->decoded_value->len; i++) self->decoded_value->str[i]++; return TRUE; } Test(kv_scanner, transforms_values_if_transform_value_is_set) { ScannerConfig config = { .kv_separator = '=', .transform_value = _parse_value_by_incrementing_all_bytes }; _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=\"bar\"", { "foo", "cbs" }); } Test(kv_scanner, pair_separator_space_disables_space_related_heuristics) { ScannerConfig config = { .kv_separator = '=', .pair_separator = " ", }; /* v2 and v4 below goes to stray words, as the pair-separator is a space, * so we disable the heuristics about spaces embedded in non-quoted values * */ _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=v1 v2 bar=v3 v4", {"foo", "v1"}, {"bar", "v3"}); /* if the separator is multiple spaces, we still trim spaces at the end of * line (that is a partial separator). */ config.pair_separator = " "; _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=v1 v2 bar=v3 v4 ", {"foo", "v1 v2"}, {"bar", "v3 v4"}); } Test(kv_scanner, pair_separator_causes_values_to_be_split_at_that_character) { ScannerConfig config = { .kv_separator = '=', .pair_separator = ";", }; _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=bar; bar=foo;", {"foo", "bar"}, {"bar", "foo"}); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=bar;bar=foo;baz=foo", {"foo", "bar"}, {"bar", "foo"}, {"baz", "foo"}); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=bar;bar=foo;", {"foo", "bar"}, {"bar", "foo"}); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=bar baz;bar=foo;", {"foo", "bar baz"}, {"bar", "foo"}); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "foo=bar baz ;bar=foo;", {"foo", "bar baz"}, {"bar", "foo"}); } Test(kv_scanner, quotation_is_stored_in_the_was_quoted_value_member) { _EXPECT_KVQ_TRIPLETS("foo=\"bar\"", {"foo", "bar", TRUE}); _EXPECT_KVQ_TRIPLETS("foo='bar'", {"foo", "bar", TRUE}); _EXPECT_KVQ_TRIPLETS("foo=bar", {"foo", "bar", FALSE}); _EXPECT_KVQ_TRIPLETS("foo='bar' k=v", {"foo", "bar", TRUE}, {"k", "v", FALSE}); } Test(kv_scanner, spaces_around_value_separator_are_ignored) { ScannerConfig config= { .kv_separator=':', }; _IMPL_EXPECT_KV(config, "key1: \"value1\" key2 : value2 key3 :value3 ", {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}); } Test(kv_scanner, value_separator_is_used_to_separate_key_from_value) { ScannerConfig config= { .kv_separator = ':', }; _EXPECT_KV_PAIRS_WITH_CONFIG(config, "key1:value1 key2:value2 key3:value3 ", { "key1", "value1" }, { "key2", "value2" }, { "key3", "value3" }); } Test(kv_scanner, invalid_value_encoding_is_copied_literally) { _EXPECT_KV_PAIRS("k=\xc3", { "k", "\xc3" }); _EXPECT_KV_PAIRS("k=\xc3v", { "k", "\xc3v" }); _EXPECT_KV_PAIRS("k=\xff", { "k", "\xff" }); _EXPECT_KV_PAIRS("k=\xffv", { "k", "\xffv" }); _EXPECT_KV_PAIRS("k=\"\xc3\"", { "k", "\xc3" }); _EXPECT_KV_PAIRS("k=\"\xc3v\"", { "k", "\xc3v" }); _EXPECT_KV_PAIRS("k=\"\xff\"", { "k", "\xff" }); _EXPECT_KV_PAIRS(" k=\"\xffv\"", { "k", "\xffv" }); } Test(kv_scanner, separator_in_key) { ScannerConfig config= { .kv_separator = '-', }; _EXPECT_KV_PAIRS_WITH_CONFIG(config, "k-v", { "k", "v" }); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "k--v", { "k", "-v" }); _EXPECT_KV_PAIRS_WITH_CONFIG(config, "---", { "-", "-" }); } Test(kv_scanner, empty_keys) { _EXPECT_KV_PAIRS("=v"); _EXPECT_KV_PAIRS("k*=v"); _EXPECT_KV_PAIRS("="); _EXPECT_KV_PAIRS("=="); _EXPECT_KV_PAIRS("==="); _EXPECT_KV_PAIRS(" ="); _EXPECT_KV_PAIRS(" =="); _EXPECT_KV_PAIRS(" ==="); _EXPECT_KV_PAIRS(" = ="); _EXPECT_KV_PAIRS(" ==k=", { "k", "" }); _EXPECT_KV_PAIRS(" = =k=", { "k", "" }); _EXPECT_KV_PAIRS(" =k=", { "k", "" }); _EXPECT_KV_PAIRS(" =k=v", { "k", "v" }); _EXPECT_KV_PAIRS(" ==k=v", { "k", "v" }); _EXPECT_KV_PAIRS(" =k=v=w", { "k", "v=w" }); } Test(kv_scanner, unclosed_quotes) { _EXPECT_KV_PAIRS("k=\"a", { "k", "\"a" }); _EXPECT_KV_PAIRS("k=\\", { "k", "\\" }); _EXPECT_KV_PAIRS("k=\"\\", { "k", "\"\\" }); _EXPECT_KV_PAIRS("k='a", { "k", "'a" }); _EXPECT_KV_PAIRS("k='\\", { "k", "'\\" }); /* backslash is not special if not within quotes */ _EXPECT_KV_PAIRS("k=\\", {"k", "\\"}); _EXPECT_KV_PAIRS("foo=bar\"", {"foo", "bar\""}); _EXPECT_KV_PAIRS("foo='bar", {"foo", "'bar"}); } Test(kv_scanner, comma_separator) { _EXPECT_KV_PAIRS(", k=v", { "k", "v" }); _EXPECT_KV_PAIRS(",k=v", { "k", "v" }); _EXPECT_KV_PAIRS("k=v,", { "k", "v," }); _EXPECT_KV_PAIRS("k=v, ", { "k", "v" }); } Test(kv_scanner, multiple_separators) { _EXPECT_KV_PAIRS("k==", { "k", "=" }); _EXPECT_KV_PAIRS("k===", { "k", "==" }); _EXPECT_KV_PAIRS("k===a", {"k", "==a"}); _EXPECT_KV_PAIRS("k===a=b", {"k", "==a=b"}); } Test(kv_scanner, keys_only_use_a_restricted_set_of_characters) { _EXPECT_KV_PAIRS("k-j=v", { "k-j", "v" }); _EXPECT_KV_PAIRS("0=v", { "0", "v" }); _EXPECT_KV_PAIRS("_=v", { "_", "v" }); _EXPECT_KV_PAIRS(":=v"); _EXPECT_KV_PAIRS(":="); _EXPECT_KV_PAIRS("Z=v", { "Z", "v" }); /* no value, as the key is not in [a-zA-Z0-9-_] */ _EXPECT_KV_PAIRS("á=v"); _EXPECT_KV_PAIRS("*k=v", { "k", "v" }); } Test(kv_scanner, unquoted_values_can_have_embedded_control_characters) { _EXPECT_KV_PAIRS("k1=\\b\\f\\n\\r\\t\\\\", {"k1", "\\b\\f\\n\\r\\t\\\\"}); _EXPECT_KV_PAIRS("k1=\b\f\n\r\\", {"k1", "\b\f\n\r\\"}); } Test(kv_scanner, spaces_are_trimmed_between_key_and_separator) { _EXPECT_KV_PAIRS("foo =bar", {"foo", "bar"}); _EXPECT_KV_PAIRS("foo= bar", {"foo", "bar"}); } Test(kv_scanner, space_is_only_a_delimiter_if_a_key_follows) { _EXPECT_KV_PAIRS("foo=bar ggg", {"foo", "bar ggg"}); _EXPECT_KV_PAIRS("foo=bar ggg baz=ez", {"foo", "bar ggg"}, {"baz", "ez"}); } Test(kv_scanner, spaces_are_trimmed_from_key_names) { _EXPECT_KV_PAIRS(" foo =bar ggg baz=ez", {"foo", "bar ggg"}, {"baz", "ez"}); _EXPECT_KV_PAIRS("foo =bar ggg baz=ez", {"foo", "bar ggg"}, {"baz", "ez"}); _EXPECT_KV_PAIRS(" foo=bar ggg baz=ez", {"foo", "bar ggg"}, {"baz", "ez"}); _EXPECT_KV_PAIRS("foo = bar ggg baz = ez", {"foo", "bar ggg"}, {"baz", "ez"}); _EXPECT_KV_PAIRS("k=== a", {"k", "== a"}); } Test(kv_scanner, initial_spaces_are_trimmed_from_values) { _EXPECT_KV_PAIRS(" k= b", {"k", "b"}); } Test(kv_scanner, stray_words_are_stored) { _EXPECT_KV_AND_STRAY_WORDS("foo=bar", "", {"foo", "bar"}); _EXPECT_KV_AND_STRAY_WORDS("alma foo=bar", "alma", {"foo", "bar"}); _EXPECT_KV_AND_STRAY_WORDS("alma foo=bar, korte bar=foo", "alma,korte", {"foo", "bar"}, {"bar", "foo"}); _EXPECT_KV_AND_STRAY_WORDS("alma foo=bar, korte bar=foo, narancs", "alma,korte,narancs", {"foo", "bar"}, {"bar", "foo"}); } Test(kv_scanner, key_buffer_underrun) { const gchar *buffer = "ab=v"; const gchar *input = buffer + 2; _EXPECT_KV_PAIRS(input); } static Testcase * _provide_cases_for_performance_test_nothing_to_parse(void) { Testcase tc[] = { { .input = "Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. \ Try to increase stolen memory size if available in BIOS.", .expected = INIT_KVCONTAINER(), }, { .input = "interrupt took too long (3136 > 3127), lowering kernel.perf_event_max_sample_rate to 63750", .expected = INIT_KVCONTAINER(), }, { .input = "Linux version 4.6.3-040603-generic (kernel@gomeisa) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-4ubuntu1) ) \ #201606241434 SMP Fri Jun 24 18:36:33 UTC 2016", .expected = INIT_KVCONTAINER(), }, {} }; return g_memdup(tc, sizeof(tc)); } static Testcase * _provide_cases_for_performance_test_parse_long_msg(void) { Testcase tc[] = { { .input = "PF: filter/forward DROP \ IN=15dd205a6ac8b0c80ab3bcdcc5649c9c830074cdbdc094ff1d79f20f17c56843 \ OUT=980816f36b77e58d342de41f85854376d10cf9bf33aa1934e129ffd77ddc833d \ SRC=cc8177fc0c8681d3d5d2a42bc1ed86990f773589592fa3100c23fae445f8a260 \ DST=5fee25396500fc798e10b4dcb0b3fb315618ff11843be59978c0d5b41cd9f12c \ LEN=71ee45a3c0db9a9865f7313dd3372cf60dca6479d46261f3542eb9346e4a04d6 \ TOS=c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7 \ PREC=c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7 \ TTL=da4ea2a5506f2693eae190d9360a1f31793c98a1adade51d93533a6f520ace1c \ ID=242a9377518dd1afaf021b2d0bfe6484e3fe48a878152f76dec99a396160022c \ PROTO=dc4030f9688d6e67dfc4c5f8f7afcbdbf5c30de866d8a3c6e1dd038768ab91c3 \ SPT=1e7996c7b0181429bba237ac2799ee5edc31aca2d5d90c39a48f9e9a3d4078bd \ DPT=ca902d4a8acbdea132ada81a004081f51c5c9279d409cee414de5a39a139fab6 \ LEN=c2356069e9d1e79ca924378153cfbbfb4d4416b1f99d41a2940bfdb66c5319db", .expected = INIT_KVCONTAINER( {"IN", "15dd205a6ac8b0c80ab3bcdcc5649c9c830074cdbdc094ff1d79f20f17c56843"}, {"OUT", "980816f36b77e58d342de41f85854376d10cf9bf33aa1934e129ffd77ddc833d"}, {"SRC", "cc8177fc0c8681d3d5d2a42bc1ed86990f773589592fa3100c23fae445f8a260"}, {"DST", "5fee25396500fc798e10b4dcb0b3fb315618ff11843be59978c0d5b41cd9f12c"}, {"LEN", "71ee45a3c0db9a9865f7313dd3372cf60dca6479d46261f3542eb9346e4a04d6"}, {"TOS", "c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7"}, {"PREC", "c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7"}, {"TTL", "da4ea2a5506f2693eae190d9360a1f31793c98a1adade51d93533a6f520ace1c"}, {"ID", "242a9377518dd1afaf021b2d0bfe6484e3fe48a878152f76dec99a396160022c"}, {"PROTO", "dc4030f9688d6e67dfc4c5f8f7afcbdbf5c30de866d8a3c6e1dd038768ab91c3"}, {"SPT", "1e7996c7b0181429bba237ac2799ee5edc31aca2d5d90c39a48f9e9a3d4078bd"}, {"DPT", "ca902d4a8acbdea132ada81a004081f51c5c9279d409cee414de5a39a139fab6"}, {"LEN", "c2356069e9d1e79ca924378153cfbbfb4d4416b1f99d41a2940bfdb66c5319db"}), }, { .input = "PF: filter/forward DROP \ IN='15dd205a6ac8b0c80ab3bcdcc5649c9c830074cdbdc094ff1d79f20f17c56843' \ OUT='980816f36b77e58d342de41f85854376d10cf9bf33aa1934e129ffd77ddc833d' \ SRC='cc8177fc0c8681d3d5d2a42bc1ed86990f773589592fa3100c23fae445f8a260' \ DST='5fee25396500fc798e10b4dcb0b3fb315618ff11843be59978c0d5b41cd9f12c' \ LEN='71ee45a3c0db9a9865f7313dd3372cf60dca6479d46261f3542eb9346e4a04d6' \ TOS='c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7' \ PREC='c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7' \ TTL='da4ea2a5506f2693eae190d9360a1f31793c98a1adade51d93533a6f520ace1c' \ ID='242a9377518dd1afaf021b2d0bfe6484e3fe48a878152f76dec99a396160022c' \ PROTO='dc4030f9688d6e67dfc4c5f8f7afcbdbf5c30de866d8a3c6e1dd038768ab91c3' \ SPT='1e7996c7b0181429bba237ac2799ee5edc31aca2d5d90c39a48f9e9a3d4078bd' \ DPT='ca902d4a8acbdea132ada81a004081f51c5c9279d409cee414de5a39a139fab6' \ LEN='c2356069e9d1e79ca924378153cfbbfb4d4416b1f99d41a2940bfdb66c5319db'", .expected = INIT_KVCONTAINER( {"IN", "15dd205a6ac8b0c80ab3bcdcc5649c9c830074cdbdc094ff1d79f20f17c56843"}, {"OUT", "980816f36b77e58d342de41f85854376d10cf9bf33aa1934e129ffd77ddc833d"}, {"SRC", "cc8177fc0c8681d3d5d2a42bc1ed86990f773589592fa3100c23fae445f8a260"}, {"DST", "5fee25396500fc798e10b4dcb0b3fb315618ff11843be59978c0d5b41cd9f12c"}, {"LEN", "71ee45a3c0db9a9865f7313dd3372cf60dca6479d46261f3542eb9346e4a04d6"}, {"TOS", "c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7"}, {"PREC", "c4dd67368286d02d62bdaa7a775b7594765d5210c9ad20cc3c24148d493353d7"}, {"TTL", "da4ea2a5506f2693eae190d9360a1f31793c98a1adade51d93533a6f520ace1c"}, {"ID", "242a9377518dd1afaf021b2d0bfe6484e3fe48a878152f76dec99a396160022c"}, {"PROTO", "dc4030f9688d6e67dfc4c5f8f7afcbdbf5c30de866d8a3c6e1dd038768ab91c3"}, {"SPT", "1e7996c7b0181429bba237ac2799ee5edc31aca2d5d90c39a48f9e9a3d4078bd"}, {"DPT", "ca902d4a8acbdea132ada81a004081f51c5c9279d409cee414de5a39a139fab6"}, {"LEN", "c2356069e9d1e79ca924378153cfbbfb4d4416b1f99d41a2940bfdb66c5319db"}), }, { .input = "fw=108.53.156.38 pri=6 c=262144 m=98 msg=\"Connection Opened\" f=2 sess=\"None\" \ n=16351474 src=10.0.5.200:57719:X0:MOGWAI dst=71.250.0.14:53:X1 dstMac=f8:c0:01:73:c7:c1 proto=udp/dns sent=66", .expected = INIT_KVCONTAINER( {"fw", "108.53.156.38"}, {"pri", "6"}, {"c", "262144"}, {"m", "98"}, {"msg", "Connection Opened"}, {"f", "2"}, {"sess", "None"}, {"n", "16351474"}, {"src", "10.0.5.200:57719:X0:MOGWAI"}, {"dst", "71.250.0.14:53:X1"}, {"dstMac", "f8:c0:01:73:c7:c1"}, {"proto", "udp/dns"}, {"sent", "66"}), }, { .input = "sn=C0EAE484E43E time=\"2016-07-08 13:42:58\" fw=132.237.143.192 pri=5 c=4 m=16 msg=\"Web site access allowed\" \ app=11 sess=\"Auto\" n=5086 usr=\"DEMO\\primarystudent\" src=10.2.3.64:50682:X2-V3023 dst=157.55.240.220:443:X1 \ srcMac=00:50:56:8e:55:8e dstMac=c0:ea:e4:84:e4:40 proto=tcp/https dstname=sls.update.microsoft.com arg= code=27 \ Category=\"Information Technology/Computers\" fw_action=\"process\"", .expected = INIT_KVCONTAINER( {"sn", "C0EAE484E43E"}, {"time", "2016-07-08 13:42:58"}, {"fw", "132.237.143.192"}, {"pri", "5"}, {"c", "4"}, {"m", "16"}, {"msg", "Web site access allowed"}, {"app", "11"}, {"sess", "Auto"}, {"n", "5086"}, {"usr", "DEMO\\primarystudent"}, {"src", "10.2.3.64:50682:X2-V3023"}, {"dst", "157.55.240.220:443:X1"}, {"srcMac", "00:50:56:8e:55:8e"}, {"dstMac", "c0:ea:e4:84:e4:40"}, {"proto", "tcp/https"}, {"dstname", "sls.update.microsoft.com"}, {"arg", ""}, {"code", "27"}, {"Category", "Information Technology/Computers"}, {"fw_action", "process"}), }, { .input = "IN=em1 OUT= MAC=a2:be:d2:ab:11:af:e2:f2:00:00 SRC=192.168.2.115 DST=192.168.1.23 " "LEN=52 TOS=0x00 PREC=0x00 TTL=127 ID=9434 DF PROTO=TCP SPT=58428 DPT=443 WINDOW=8192 " "RES=0x00 SYN URGP=0", .expected = INIT_KVCONTAINER( {"IN", "em1"}, {"OUT", ""}, {"MAC", "a2:be:d2:ab:11:af:e2:f2:00:00"}, {"SRC", "192.168.2.115"}, {"DST", "192.168.1.23"}, {"LEN", "52"}, {"TOS", "0x00"}, {"PREC", "0x00"}, {"TTL", "127"}, {"ID", "9434 DF"}, {"PROTO", "TCP"}, {"SPT", "58428"}, {"DPT", "443"}, {"WINDOW", "8192"}, {"RES", "0x00 SYN"}, {"URGP", "0"}, ), }, {} }; return g_memdup(tc, sizeof(tc)); } #define ITERATION_NUMBER 100000 static void _test_performance(Testcase *tcs, gchar *title) { const Testcase *tc; gint iteration_index = 0; if (title) { printf("Performance test: %s\n", title); } for (tc = tcs; tc->input; tc++) { KVScanner scanner; start_stopwatch(); for (iteration_index = 0; iteration_index < ITERATION_NUMBER; iteration_index++) { gchar *error = NULL; kv_scanner_init(&scanner, '=', ",", FALSE); kv_scanner_input(&scanner, tc->input); if (!_expect_kv_pairs(&scanner, tc->expected, &error)) { cr_expect(FALSE, "%s", error); g_free(error); } kv_scanner_deinit(&scanner); scratch_buffers_explicit_gc(); } stop_stopwatch_and_display_result(iteration_index, "%.64s...", tc->input); } g_free(tcs); } Test(kv_scanner, performance_tests) { _test_performance(_provide_cases_for_performance_test_nothing_to_parse(), "Nothing to parse in the message"); _test_performance(_provide_cases_for_performance_test_parse_long_msg(), "Parse long strings"); } static void setup(void) { app_startup(); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(kv_scanner, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/000077500000000000000000000000001450431004300221545ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/CMakeLists.txt000066400000000000000000000002651450431004300247170ustar00rootroot00000000000000set(LIST_SCANNER_HEADERS list-scanner/list-scanner.h PARENT_SCOPE) set(LIST_SCANNER_SOURCES list-scanner/list-scanner.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/Makefile.am000066400000000000000000000004751450431004300242160ustar00rootroot00000000000000listscannerincludedir = ${pkgincludedir}/scanner/list-scanner EXTRA_DIST += lib/scanner/list-scanner/CMakeLists.txt listscannerinclude_HEADERS = \ lib/scanner/list-scanner/list-scanner.h listscanner_sources = \ lib/scanner/list-scanner/list-scanner.c include lib/scanner/list-scanner/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/list-scanner.c000066400000000000000000000122031450431004300247200ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "scanner/list-scanner/list-scanner.h" #include "str-repr/encode.h" #include "str-repr/decode.h" #include "str-utils.h" #include #include static void _free_input(ListScanner *self) { if (self->argv) { if (self->free_argv_payload) g_ptr_array_foreach(self->argv_buffer, (GFunc) g_free, NULL); } g_ptr_array_set_size(self->argv_buffer, 0); } static void _store_input(ListScanner *self, gint argc, gchar **argv, gboolean free_argv) { self->argc = argc; self->argv = (gchar **) self->argv_buffer->pdata; self->free_argv_payload = free_argv; self->current_arg_ndx = 0; self->current_arg = self->argv[self->current_arg_ndx]; } void list_scanner_input_va(ListScanner *self, const gchar *arg1, ...) { va_list va; gint i; const char *arg; _free_input(self); va_start(va, arg1); for (i = 0, arg = arg1; arg; i++, arg = va_arg(va, const gchar *)) { g_ptr_array_add(self->argv_buffer, g_strdup(arg)); } g_ptr_array_add(self->argv_buffer, NULL); va_end(va); _store_input(self, i, (gchar **) self->argv_buffer->pdata, TRUE); } void list_scanner_input_gstring_array(ListScanner *self, gint argc, GString *const *argv) { gint i; for (i = 0; i < argc; i++) { g_ptr_array_add(self->argv_buffer, argv[i]->str); } g_ptr_array_add(self->argv_buffer, NULL); _store_input(self, argc, (gchar **) self->argv_buffer->pdata, FALSE); } void list_scanner_input_string(ListScanner *self, const gchar *value, gssize value_len) { _free_input(self); if (value_len < 0) value_len = strlen(value); g_ptr_array_add(self->argv_buffer, g_strndup(value, value_len)); g_ptr_array_add(self->argv_buffer, NULL); _store_input(self, 1, (gchar **) self->argv_buffer->pdata, TRUE); } static gboolean _is_finished_with_args(ListScanner *self) { return self->current_arg_ndx >= self->argc; } static gboolean _parse_value_from_current_position(ListScanner *self) { StrReprDecodeOptions options = { 0, .delimiter_chars = ",", }; const gchar *end; /* NOTE: we always try to parse elements, even if the string is malformed, * otherwise we would be losing data. Prefer to have data in an * incorrectly formatted way, than no data at all. */ if (!str_repr_decode_with_options(self->value, self->current_arg, &end, &options)) { g_string_truncate(self->value, 0); g_string_append_len(self->value, self->current_arg, end - self->current_arg); } self->current_arg = end; return TRUE; } static gboolean _skip_if_current_arg_is_empty(ListScanner *self) { if (self->current_arg[0] == 0) { self->current_arg_ndx++; self->current_arg = self->argv[self->current_arg_ndx]; return TRUE; } return FALSE; } static gboolean _skip_unquoted_empty_value(ListScanner *self) { if (*self->current_arg == ',') { self->current_arg = self->current_arg + 1; return TRUE; } return FALSE; } static void _skip_empty_values(ListScanner *self) { while (!_is_finished_with_args(self)) { if (!_skip_if_current_arg_is_empty(self) && !_skip_unquoted_empty_value(self)) break; } return; } gboolean list_scanner_scan_next(ListScanner *self) { g_string_truncate(self->value, 0); _skip_empty_values(self); if (!_is_finished_with_args(self) && _parse_value_from_current_position(self)) return TRUE; return FALSE; } void list_scanner_skip_n(ListScanner *self, gint n) { gint count = 0; while (++count <= n && list_scanner_scan_next(self)) ; } const gchar * list_scanner_get_current_value(ListScanner *self) { return self->value->str; } gsize list_scanner_get_current_value_len(ListScanner *self) { return self->value->len; } void list_scanner_init(ListScanner *self) { memset(self, 0, sizeof(*self)); self->value = g_string_sized_new(32); self->argv_buffer = g_ptr_array_new(); } void list_scanner_deinit(ListScanner *self) { _free_input(self); g_string_free(self->value, TRUE); g_ptr_array_free(self->argv_buffer, TRUE); } ListScanner * list_scanner_new(void) { ListScanner *self = g_new0(ListScanner, 1); list_scanner_init(self); return self; } void list_scanner_free(ListScanner *self) { list_scanner_deinit(self); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/list-scanner.h000066400000000000000000000037231450431004300247340ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIST_SCANNER_H_INCLUDED #define LIST_SCANNER_H_INCLUDED #include "syslog-ng.h" typedef struct _ListScanner ListScanner; struct _ListScanner { gint argc; gchar **argv; GPtrArray *argv_buffer; GString *value; gboolean free_argv_payload; const gchar *current_arg; gint current_arg_ndx; gboolean current_arg_split; }; void list_scanner_input_va(ListScanner *self, const gchar *arg1, ...); void list_scanner_input_gstring_array(ListScanner *self, gint argc, GString *const *argv); void list_scanner_input_string(ListScanner *self, const gchar *value, gssize value_len); gboolean list_scanner_scan_next(ListScanner *self); void list_scanner_skip_n(ListScanner *self, gint n); const gchar *list_scanner_get_current_value(ListScanner *self); gsize list_scanner_get_current_value_len(ListScanner *self); void list_scanner_free_method(ListScanner *self); void list_scanner_init(ListScanner *self); void list_scanner_deinit(ListScanner *self); ListScanner *list_scanner_new(void); void list_scanner_free(ListScanner *self); #endif syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/tests/000077500000000000000000000000001450431004300233165ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/tests/CMakeLists.txt000066400000000000000000000000621450431004300260540ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_list_scanner) syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/tests/Makefile.am000066400000000000000000000005511450431004300253530ustar00rootroot00000000000000lib_scanner_list_scanner_tests_TESTS = \ lib/scanner/list-scanner/tests/test_list_scanner EXTRA_DIST += lib/scanner/list-scanner/tests/CMakeLists.txt check_PROGRAMS += ${lib_scanner_list_scanner_tests_TESTS} lib_scanner_list_scanner_tests_test_list_scanner_CFLAGS = $(TEST_CFLAGS) lib_scanner_list_scanner_tests_test_list_scanner_LDADD = \ $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/scanner/list-scanner/tests/test_list_scanner.c000066400000000000000000000173241450431004300272140ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "scanner/list-scanner/list-scanner.h" ListScanner *list_scanner; static void assert_no_more_tokens(void) { cr_assert(!list_scanner_scan_next(list_scanner), "list_scanner is expected to return no more key-value pairs"); } static void scan_next_token(void) { cr_assert(list_scanner_scan_next(list_scanner), "list_scanner is expected to return TRUE for scan_next"); } static void assert_current_value_is(const gchar *expected_key) { const gchar *key = list_scanner_get_current_value(list_scanner); gint key_len = list_scanner_get_current_value_len(list_scanner); cr_assert_str_eq(key, expected_key, "current key mismatch"); cr_assert_eq(key_len, strlen(expected_key)); } static void assert_next_value_is(const gchar *expected_value) { scan_next_token(); assert_current_value_is(expected_value); } static void setup(void) { list_scanner = list_scanner_new(); } static void teardown(void) { list_scanner_free(list_scanner); } TestSuite(list_scanner, .init = setup, .fini = teardown); Test(list_scanner, individual_items_are_scanned) { list_scanner_input_va(list_scanner, "foo", NULL); assert_next_value_is("foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "foo", "bar", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "foo", "bar", "baz", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_no_more_tokens(); } Test(list_scanner, unquoted_empty_items_are_skipped_to_make_it_easy_to_concatenate_lists) { list_scanner_input_va(list_scanner, "", NULL); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "", "foo", "bar", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "", "", "", ",,,,", "", "", "", "foo", "bar", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "foo", "", "bar", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "foo,", NULL); assert_next_value_is("foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "''", ",foo,", "bar,", ",baz", "foobar", "\"\"", NULL); assert_next_value_is(""); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_next_value_is("foobar"); assert_next_value_is(""); assert_no_more_tokens(); } Test(list_scanner, quoted_empty_items_are_parsed_as_empty_values) { list_scanner_input_va(list_scanner, "foo", "''", "bar", NULL); assert_next_value_is("foo"); assert_next_value_is(""); assert_next_value_is("bar"); assert_no_more_tokens(); } Test(list_scanner, comma_delimiter_values_are_split) { list_scanner_input_va(list_scanner, "foo,bar", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "foo,bar,baz", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_no_more_tokens(); } Test(list_scanner, comma_and_arg_are_equivalent) { list_scanner_input_va(list_scanner, "foo,bar,baz", "xxx", "", "yyy", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_next_value_is("xxx"); assert_next_value_is("yyy"); assert_no_more_tokens(); } Test(list_scanner, works_with_gstring_input) { GString *argv[] = { g_string_new("foo,bar,baz"), g_string_new("xxx"), g_string_new(""), g_string_new("yyy"), }; const gint argc = 4; gint i; list_scanner_input_gstring_array(list_scanner, argc, argv); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_next_value_is("xxx"); assert_next_value_is("yyy"); assert_no_more_tokens(); for (i = 0; i < argc; i++) g_string_free(argv[i], TRUE); } Test(list_scanner, works_with_simple_input) { list_scanner_input_string(list_scanner, "foo,bar,baz", -1); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_next_value_is("baz"); assert_no_more_tokens(); /* nonzero terminated */ list_scanner_input_string(list_scanner, "foo,bar,baz", 7); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); } Test(list_scanner, handles_single_quotes) { list_scanner_input_va(list_scanner, "'foo'", NULL); assert_next_value_is("foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "'foo','bar'", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "'foo,bar'", NULL); assert_next_value_is("foo,bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "'foo''bar'", NULL); assert_next_value_is("'foo''bar'"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "'foo'bar", NULL); assert_next_value_is("'foo'bar"); assert_no_more_tokens(); } Test(list_scanner, handles_double_quotes) { list_scanner_input_va(list_scanner, "\"foo\"", NULL); assert_next_value_is("foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "\"\\\"foo\"", NULL); assert_next_value_is("\"foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "\"foo\",\"bar\"", NULL); assert_next_value_is("foo"); assert_next_value_is("bar"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "\"foo,bar\"", NULL); assert_next_value_is("foo,bar"); assert_no_more_tokens(); /* no separator, thus two string tokens are concatenated */ list_scanner_input_va(list_scanner, "\"foo\"\"bar\"", NULL); assert_next_value_is("\"foo\"\"bar\""); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "\"foo\"bar", NULL); assert_next_value_is("\"foo\"bar"); assert_no_more_tokens(); } Test(list_scanner, malformed_quotes) { list_scanner_input_va(list_scanner, "'foo", NULL); assert_next_value_is("'foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "bar,'foo", NULL); assert_next_value_is("bar"); assert_next_value_is("'foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "bar,'foo,", NULL); assert_next_value_is("bar"); assert_next_value_is("'foo,"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "\"foo", NULL); assert_next_value_is("\"foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "bar,\"foo", NULL); assert_next_value_is("bar"); assert_next_value_is("\"foo"); assert_no_more_tokens(); list_scanner_input_va(list_scanner, "bar,\"foo,", NULL); assert_next_value_is("bar"); assert_next_value_is("\"foo,"); assert_no_more_tokens(); } syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/000077500000000000000000000000001450431004300220015ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/CMakeLists.txt000066400000000000000000000003531450431004300245420ustar00rootroot00000000000000set(XML_SCANNER_HEADERS xml-scanner/xml-scanner.h PARENT_SCOPE) set(XML_SCANNER_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(XML_SCANNER_SOURCES xml-scanner/xml-scanner.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/Makefile.am000066400000000000000000000004631450431004300240400ustar00rootroot00000000000000xmlscannerincludedir = ${pkgincludedir}/scanner/xml-scanner EXTRA_DIST += lib/scanner/xml-scanner/CMakeLists.txt xmlscannerinclude_HEADERS = \ lib/scanner/xml-scanner/xml-scanner.h xmlscanner_sources = \ lib/scanner/xml-scanner/xml-scanner.c include lib/scanner/xml-scanner/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/tests/000077500000000000000000000000001450431004300231435ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/tests/CMakeLists.txt000066400000000000000000000001371450431004300257040ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_xml_scanner INCLUDES "${XML_SCANNER_INCLUDE_DIR}") syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/tests/Makefile.am000066400000000000000000000005651450431004300252050ustar00rootroot00000000000000lib_xml_scanner_tests_TESTS = \ lib/scanner/xml-scanner/tests/test_xml_scanner EXTRA_DIST += lib/scanner/xml-scanner/tests/CMakeLists.txt check_PROGRAMS += ${lib_xml_scanner_tests_TESTS} lib_scanner_xml_scanner_tests_test_xml_scanner_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/scanner/xml-scanner lib_scanner_xml_scanner_tests_test_xml_scanner_LDADD = $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/tests/test_xml_scanner.c000066400000000000000000000117041450431004300266620ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "xml-scanner.h" #include "apphook.h" #include "scratch-buffers.h" #include "cfg.h" typedef struct { gchar *name; gchar *value; } NameValuePair; typedef struct { NameValuePair *expected_pairs; PushCurrentKeyValueCB test_push_function; } Expected; typedef struct { gboolean strip_whitespaces; GList *exclude_tags; Expected expected; } XMLScannerTestOptions; static void setup(void) { configuration = cfg_new_snippet(); app_startup(); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); cfg_free(configuration); } static XMLScannerOptions * _create_new_scanner_options(XMLScannerTestOptions *test_options) { XMLScannerOptions *scanner_options = g_new0(XMLScannerOptions, 1); xml_scanner_options_defaults(scanner_options); if (test_options->strip_whitespaces) xml_scanner_options_set_strip_whitespaces(scanner_options, test_options->strip_whitespaces); if (test_options->exclude_tags) xml_scanner_options_set_and_compile_exclude_tags(scanner_options, test_options->exclude_tags); return scanner_options; } static XMLScanner * _construct_xml_scanner(XMLScannerTestOptions *test_options) { XMLScanner *scanner = g_new(XMLScanner, 1); XMLScannerOptions *scanner_options = _create_new_scanner_options(test_options); xml_scanner_init(scanner, scanner_options, test_options->expected.test_push_function, test_options, NULL); return scanner; } static void _destroy_xml_scanner(XMLScanner *scanner) { xml_scanner_options_destroy(scanner->options); g_free(scanner->options); xml_scanner_deinit(scanner); g_free(scanner); } #define REPORT_POSSIBLE_PARSE_ERROR(x) (_report_possible_parse_error((x), __LINE__)) static void _report_possible_parse_error(GError *error, gint line) { cr_expect(error == NULL, "Unexpected error happened in %d", line); if (error) { fprintf(stderr, "Parsing error happened: %s\n", error->message); g_error_free(error); } } TestSuite(xml_scanner, .init = setup, .fini = teardown); Test(xml_scanner, shouldreverse) { GList *with_wildcard; with_wildcard = NULL; with_wildcard = g_list_append(with_wildcard, "tag1"); with_wildcard = g_list_append(with_wildcard, "tag2"); with_wildcard = g_list_append(with_wildcard, "tag*"); cr_assert(joker_or_wildcard(with_wildcard)); g_list_free(with_wildcard); GList *with_joker = NULL; with_joker = g_list_append(with_joker, "tag1"); with_joker = g_list_append(with_joker, "t?g2"); with_joker = g_list_append(with_joker, "tag3"); cr_assert(joker_or_wildcard(with_joker)); g_list_free(with_joker); GList *no_joker_or_wildcard = NULL; no_joker_or_wildcard = g_list_append(no_joker_or_wildcard, "tag1"); no_joker_or_wildcard = g_list_append(no_joker_or_wildcard, "tag2"); no_joker_or_wildcard = g_list_append(no_joker_or_wildcard, "tag3"); cr_assert_not(joker_or_wildcard(no_joker_or_wildcard)); g_list_free(no_joker_or_wildcard); } static void _test_strip(const gchar *name, const gchar *value, gssize value_length, gpointer user_data) { static guint times_called = 0; XMLScannerTestOptions *test_options = (XMLScannerTestOptions *) user_data; NameValuePair *expected_pairs = test_options->expected.expected_pairs; fprintf(stderr, "Name-value pushed!!! name:%s\tvalue:%s (value_len:%ld)\n", name, value, value_length); cr_assert_str_eq(name, expected_pairs[times_called].name); cr_assert_str_eq(value, expected_pairs[times_called].value); times_called++; } Test(xml_scanner, test_strip_whitespaces) { const gchar *input = " \n\t part1 part2 \n\n"; XMLScanner *xml_scanner = _construct_xml_scanner(&(XMLScannerTestOptions) { .strip_whitespaces = TRUE, .expected.test_push_function = _test_strip, .expected.expected_pairs = (NameValuePair []) { {"tag", "part1part2"}, } }); GError *error = NULL; xml_scanner_parse(xml_scanner, input, strlen(input), &error); REPORT_POSSIBLE_PARSE_ERROR(error); _destroy_xml_scanner(xml_scanner); } syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/xml-scanner.c000066400000000000000000000265261450431004300244070ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "xml-scanner.h" #include "scratch-buffers.h" #include "compat/glib.h" /* For some patterns, GPatternSpec stores the pattern as reversed string. In such cases, the matching must be executed against the reversed matchstring. If one uses g_pattern_match_string, glib will reverse the string internally in these cases, but it is suboptimal if the same matchstring must be matched against different patterns, because memory is allocated each time and string is copied as reversed, though it would be enough to execute this reverse once. For that reason one can use g_pattern_match(), which accepts both the matchstring and a reversed matchstring as parameters. Though there are cases when no reverse is needed at all. This is decided in the constructor of GPatternSpec, but at this time of writing this information is not exported, and cannot be extracted in any safe way, because GPatternSpec is forward declared. This function below is an oversimplified/safe version of the logic used glib to decide if the pattern will be reversed or not. One need to note the worst case scenario is if syslog-ng will not reverse the matchstring, though it should because in that case number of extra memory allocations and string reversals scale linearly with the number of patterns. We need to avoid not pre-reversing, when glib would. */ gboolean joker_or_wildcard(GList *patterns) { gboolean retval = FALSE; GList *pattern = patterns; while (pattern != NULL) { gchar *str = ((gchar *)pattern->data); if (strpbrk(str, "*?")) { retval = TRUE; break; } pattern = g_list_next(pattern); } return retval; } static void _compile_and_add(gpointer tag_glob, gpointer exclude_patterns) { g_ptr_array_add(exclude_patterns, g_pattern_spec_new(tag_glob)); } static void xml_scanner_options_compile_exclude_tags_to_patterns(XMLScannerOptions *self) { g_ptr_array_free(self->exclude_patterns, TRUE); self->exclude_patterns = g_ptr_array_new_with_free_func((GDestroyNotify)g_pattern_spec_free); g_list_foreach(self->exclude_tags, _compile_and_add, self->exclude_patterns); self->matchstring_shouldreverse = joker_or_wildcard(self->exclude_tags); } void xml_scanner_options_set_and_compile_exclude_tags(XMLScannerOptions *self, GList *exclude_tags) { g_list_free_full(self->exclude_tags, g_free); self->exclude_tags = g_list_copy_deep(exclude_tags, ((GCopyFunc)g_strdup), NULL); xml_scanner_options_compile_exclude_tags_to_patterns(self); } void xml_scanner_options_set_strip_whitespaces(XMLScannerOptions *self, gboolean setting) { self->strip_whitespaces = setting; } void xml_scanner_options_destroy(XMLScannerOptions *self) { g_list_free_full(self->exclude_tags, g_free); self->exclude_tags = NULL; g_ptr_array_free(self->exclude_patterns, TRUE); self->exclude_patterns = NULL; } void xml_scanner_options_copy(XMLScannerOptions *dest, XMLScannerOptions *source) { xml_scanner_options_set_strip_whitespaces(dest, source->strip_whitespaces); xml_scanner_options_set_and_compile_exclude_tags(dest, source->exclude_tags); } void xml_scanner_options_defaults(XMLScannerOptions *self) { self->exclude_patterns = g_ptr_array_new_with_free_func((GDestroyNotify)g_pattern_spec_free); self->strip_whitespaces = FALSE; } static void scanner_push_attributes(XMLScanner *self, const gchar **attribute_names, const gchar **attribute_values) { GString *attr_key; if (attribute_names[0]) { attr_key = scratch_buffers_alloc(); g_string_assign(attr_key, self->key->str); g_string_append(attr_key, "._"); } else return; gint base_index = attr_key->len; gint attrs = 0; while (attribute_names[attrs]) { attr_key = g_string_overwrite(attr_key, base_index, attribute_names[attrs]); xml_scanner_push_current_key_value(self, attr_key->str, attribute_values[attrs], -1); attrs++; } } static gboolean tag_matches_patterns(const GPtrArray *patterns, const gint tag_length, const gchar *element_name, const gchar *reversed_name) { for (int i = 0; i < patterns->len; i++) if (g_pattern_match((GPatternSpec *)g_ptr_array_index(patterns, i), tag_length, element_name, reversed_name)) { return TRUE; } return FALSE; } static GString * _pop_text_from_stack(XMLScanner *self) { return g_queue_pop_head(self->text_stack); } static void _push_current_text_to_stack(XMLScanner *self) { g_queue_push_tail(self->text_stack, self->text); } static void _start_new_text_buffer(XMLScanner *self) { if (self->text) _push_current_text_to_stack(self); self->text = scratch_buffers_alloc(); } static gint before_last_dot(GString *str) { const gchar *s = str->str; gchar *pos = strrchr(s, '.'); if (!pos) return 0; return (pos-s); } static void _clear_current_element_from_key(XMLScanner *self) { g_string_truncate(self->key, before_last_dot(self->key)); } static void _add_current_element_to_key(XMLScanner *self, const gchar *element_name) { if (self->key->len > 0) g_string_append_c(self->key, '.'); g_string_append(self->key, element_name); } static GMarkupParser skip = {}; gboolean xml_scanner_start_element_method(XMLScanner *self, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { gchar *reversed = NULL; guint tag_length = strlen(element_name); if (self->options->matchstring_shouldreverse) { reversed = g_utf8_strreverse(element_name, tag_length); } if (tag_matches_patterns(self->options->exclude_patterns, tag_length, element_name, reversed)) { msg_debug("xml: subtree skipped", evt_tag_str("tag", element_name)); self->pop_next_time = 1; g_markup_parse_context_push(self->xml_ctx, &skip, NULL); g_free(reversed); return FALSE; } g_free(reversed); _add_current_element_to_key(self, element_name); return TRUE; } static void _xml_scanner_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { XMLScanner *self = (XMLScanner *)user_data; _start_new_text_buffer(self); if (self->start_element_cb(self, element_name, attribute_names, attribute_values, error)) scanner_push_attributes(self, attribute_names, attribute_values); } void xml_scanner_end_element_method(XMLScanner *self, const gchar *element_name, GError **error) { if (self->pop_next_time) { g_markup_parse_context_pop(self->xml_ctx); self->pop_next_time = 0; return; } _clear_current_element_from_key(self); } void xml_scanner_push_text_method(XMLScanner *self) { if (self->text->len) xml_scanner_push_current_key_value(self, self->key->str, self->text->str, self->text->len); } void _xml_scanner_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { XMLScanner *self = (XMLScanner *)user_data; self->push_text(self); self->end_element_cb(self, element_name, error); self->text = _pop_text_from_stack(self); } static void _strip_and_append_text(XMLScanner *self, const gchar *text, gsize text_len) { gchar *buffer = g_strndup(text, text_len); g_strstrip(buffer); g_string_append(self->text, buffer); g_free(buffer); } static void _append_text(XMLScanner *self, const gchar *text, gsize text_len) { if (self->options->strip_whitespaces) { _strip_and_append_text(self, text, text_len); return; } g_string_append_len(self->text, text, text_len); } void xml_scanner_text_method(XMLScanner *self, const gchar *element_name, const gchar *text, gsize text_len, GError **error) { if (text_len == 0) return; _append_text(self, text, text_len); } static void _xml_scanner_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { XMLScanner *self = (XMLScanner *)user_data; const gchar *element_name = g_markup_parse_context_get_element(context); self->text_cb(self, element_name, text, text_len, error); } void xml_scanner_parse(XMLScanner *self, const gchar *input, gsize input_len, GError **error) { g_assert(self->push_key_value.push_function); GMarkupParser scanner_callbacks = { .start_element = _xml_scanner_start_element, .end_element = _xml_scanner_end_element, .text = _xml_scanner_text }; ScratchBuffersMarker marker; scratch_buffers_mark(&marker); self->xml_ctx = g_markup_parse_context_new(&scanner_callbacks, 0, self, NULL); g_markup_parse_context_parse(self->xml_ctx, input, input_len, error); if (error && *error) goto exit; g_markup_parse_context_end_parse(self->xml_ctx, error); exit: scratch_buffers_reclaim_marked(marker); g_markup_parse_context_free(self->xml_ctx); self->xml_ctx = NULL; } void xml_scanner_init(XMLScanner *self, XMLScannerOptions *options, PushCurrentKeyValueCB push_function, gpointer user_data, gchar *key_prefix) { memset(self, 0, sizeof(*self)); self->start_element_cb = xml_scanner_start_element_method; self->end_element_cb = xml_scanner_end_element_method; self->text_cb = xml_scanner_text_method; self->push_text = xml_scanner_push_text_method; self->options = options; self->push_key_value.push_function = push_function; self->push_key_value.user_data = user_data; self->key = scratch_buffers_alloc(); g_string_assign(self->key, key_prefix); self->text = NULL; self->text_stack = g_queue_new(); } void xml_scanner_deinit(XMLScanner *self) { self->options = NULL; g_queue_free(self->text_stack); } syslog-ng-syslog-ng-4.4.0/lib/scanner/xml-scanner/xml-scanner.h000066400000000000000000000071251450431004300244060ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef XML_SCANNER_H_INCLUDED #define XML_SCANNER_H_INCLUDED #include "syslog-ng.h" #include "messages.h" #include typedef struct _XMLScanner XMLScanner; typedef void (*PushCurrentKeyValueCB)(const gchar *name, const gchar *value, gssize value_length, gpointer user_data); typedef struct { gboolean strip_whitespaces; GList *exclude_tags; gboolean matchstring_shouldreverse; GPtrArray *exclude_patterns; } XMLScannerOptions; typedef struct { PushCurrentKeyValueCB push_function; gpointer user_data; } PushCurrentKeyValue; struct _XMLScanner { GMarkupParseContext *xml_ctx; XMLScannerOptions *options; gboolean pop_next_time; GString *key; GString *text; GQueue *text_stack; gboolean (*start_element_cb) (XMLScanner *self, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error); void (*end_element_cb) (XMLScanner *self, const gchar *element_name, GError **error); void (*text_cb) (XMLScanner *self, const gchar *element_name, const gchar *text, gsize text_len, GError **error); PushCurrentKeyValue push_key_value; void (*push_text) (XMLScanner *self); }; void xml_scanner_init(XMLScanner *self, XMLScannerOptions *options, PushCurrentKeyValueCB push_function, gpointer user_data, gchar *key_prefix); void xml_scanner_deinit(XMLScanner *self); void xml_scanner_parse(XMLScanner *self, const gchar *input, gsize input_len, GError **error); static inline void xml_scanner_push_current_key_value(XMLScanner *self, const gchar *name, const gchar *value, gssize value_length) { self->push_key_value.push_function(name, value, value_length, self->push_key_value.user_data); } void xml_scanner_push_text_method(XMLScanner *self); gboolean xml_scanner_start_element_method(XMLScanner *self, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error); void xml_scanner_end_element_method(XMLScanner *self, const gchar *element_name, GError **error); void xml_scanner_text_method(XMLScanner *self, const gchar *element_name, const gchar *text, gsize text_len, GError **error); void xml_scanner_options_set_and_compile_exclude_tags(XMLScannerOptions *self, GList *exclude_tags); void xml_scanner_options_set_strip_whitespaces(XMLScannerOptions *self, gboolean setting); void xml_scanner_options_copy(XMLScannerOptions *dest, XMLScannerOptions *source); void xml_scanner_options_destroy(XMLScannerOptions *self); void xml_scanner_options_defaults(XMLScannerOptions *self); gboolean joker_or_wildcard(GList *patterns); #endif syslog-ng-syslog-ng-4.4.0/lib/scratch-buffers.c000066400000000000000000000243031450431004300213500ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "scratch-buffers.h" #include "tls-support.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "timeutils/cache.h" #include "messages.h" #include "apphook.h" #include /* * scratch_buffers * * The design of this API is to allow call-sites to use GString based string * buffers easily, without incurring the allocation overhead at all such * invocations and the need to always explicitly free them. * * Use-cases: * - something needs a set of GString buffers, such that their number is * not determinable at init time, so no preallocation is possible. * Allocating/freeing these buffers on-demand generates a non-trivial * overhead. * * - We need a GString buffer that is needed for the duration of the * processing of the given message, for example CSVScanner/KVScanner's * buffers. Right now, these are locked data structures or GString's * are allocated on demand, both of which slows them down. By using * this API, these could reuse existing allocations and only free them * once processing is finished of the given message. * * Design principles: * - you can allocate a GString instance using scratch_buffers_alloc() * * - these are thread specific allocations and should not be leaked * through thread boundaries, not until your own next invocation * * - you need to assume that once you return from your functions, the * previous allocations are gone! * * - you don't need to free these allocations, as they get released * automatically at the end of the message processing by the worker * thread machinery * * - if you produce too much garbage, you can still explicitly free these * buffers in bulk using the mark/reclaim functions. * * - reclaim works by freeing _all_ allocations up to a mark, so even * those that are allocated by the functions you called. Please make * sure that those do not hold references after returning. * * Other notes: * - this is not a complete garbage collector, but a very simple allocator for * buffers that creates coupling between various/independent parts of * the codebase. * * - ONLY USE IT IF YOU UNDERSTAND THE IMPLICATIONS AND PROVIDES A * MEASURABLE PERFORMANCE IMPACT. */ TLS_BLOCK_START { GPtrArray *scratch_buffers; gint scratch_buffers_used; gssize scratch_buffers_bytes_reported; time_t scratch_buffers_time_of_last_maintenance; struct iv_task scratch_buffers_gc; gboolean scratch_buffers_gc_executed; } TLS_BLOCK_END; /* accessed by the test program */ StatsCounterItem *stats_scratch_buffers_count; StatsCounterItem *stats_scratch_buffers_bytes; #define scratch_buffers __tls_deref(scratch_buffers) #define scratch_buffers_used __tls_deref(scratch_buffers_used) #define scratch_buffers_bytes_reported __tls_deref(scratch_buffers_bytes_reported) #define scratch_buffers_time_of_last_maintenance __tls_deref(scratch_buffers_time_of_last_maintenance) #define scratch_buffers_gc __tls_deref(scratch_buffers_gc) #define scratch_buffers_gc_executed __tls_deref(scratch_buffers_gc_executed) /* update allocation counters once every period, in seconds */ #define SCRATCH_BUFFERS_MAINTENANCE_PERIOD 5 static void _register_gc_task(void); void scratch_buffers_mark(ScratchBuffersMarker *marker) { *marker = scratch_buffers_used; } GString * scratch_buffers_alloc_and_mark(ScratchBuffersMarker *marker) { _register_gc_task(); if (marker) scratch_buffers_mark(marker); if (scratch_buffers_used >= scratch_buffers->len) { g_ptr_array_add(scratch_buffers, g_string_sized_new(255)); stats_counter_inc(stats_scratch_buffers_count); } GString *buffer = g_ptr_array_index(scratch_buffers, scratch_buffers_used); g_string_truncate(buffer, 0); scratch_buffers_used++; return buffer; } GString * scratch_buffers_alloc(void) { return scratch_buffers_alloc_and_mark(NULL); } void scratch_buffers_reclaim_allocations(void) { scratch_buffers_reclaim_marked(0); } void scratch_buffers_reclaim_marked(ScratchBuffersMarker marker) { scratch_buffers_used = marker; } /* get a snapshot of the global allocation counter, can be racy */ gssize scratch_buffers_get_global_allocation_count(void) { return stats_counter_get(stats_scratch_buffers_count); } /* get the number of thread-local allocations does not race */ gssize scratch_buffers_get_local_allocation_count(void) { return scratch_buffers->len; } gssize scratch_buffers_get_local_allocation_bytes(void) { gssize bytes = 0; for (gint i = 0; i < scratch_buffers->len; i++) { GString *str = g_ptr_array_index(scratch_buffers, i); bytes += str->allocated_len; } return bytes; } gint scratch_buffers_get_local_usage_count(void) { return scratch_buffers_used; } void scratch_buffers_update_stats(void) { gssize prev_reported = scratch_buffers_bytes_reported; scratch_buffers_bytes_reported = scratch_buffers_get_local_allocation_bytes(); stats_counter_add(stats_scratch_buffers_bytes, -prev_reported + scratch_buffers_bytes_reported); } void scratch_buffers_allocator_init(void) { scratch_buffers = g_ptr_array_sized_new(256); } void scratch_buffers_allocator_deinit(void) { /* check if GC was executed */ if (scratch_buffers_used > 0 && !scratch_buffers_gc_executed) { msg_warning("WARNING: an exiting thread left behind scratch buffers garbage without ever calling the GC. This message could indicate a memory leak", evt_tag_int("count", scratch_buffers->len), evt_tag_long("bytes", scratch_buffers_bytes_reported)); } /* remove our values from stats */ stats_counter_sub(stats_scratch_buffers_count, scratch_buffers->len); stats_counter_sub(stats_scratch_buffers_bytes, scratch_buffers_bytes_reported); /* free thread local scratch buffers */ for (int i = 0; i < scratch_buffers->len; i++) { GString *buffer = g_ptr_array_index(scratch_buffers, i); g_string_free(buffer, TRUE); } g_ptr_array_free(scratch_buffers, TRUE); } /********************************************************* * Lazy stats update *********************************************************/ static gboolean _thread_maintenance_period_elapsed(void) { if (!scratch_buffers_time_of_last_maintenance) return TRUE; if (scratch_buffers_time_of_last_maintenance - cached_g_current_time_sec() >= SCRATCH_BUFFERS_MAINTENANCE_PERIOD) return TRUE; return FALSE; } static void _thread_maintenance_update_time(void) { scratch_buffers_time_of_last_maintenance = cached_g_current_time_sec(); } void scratch_buffers_lazy_update_stats(void) { if (_thread_maintenance_period_elapsed()) { scratch_buffers_update_stats(); _thread_maintenance_update_time(); } } /********************************************************* * Ivykis task based garbage collector *********************************************************/ void scratch_buffers_explicit_gc(void) { scratch_buffers_lazy_update_stats(); scratch_buffers_reclaim_allocations(); scratch_buffers_gc_executed = TRUE; } static void _garbage_collect_scratch_buffers(gpointer arg) { scratch_buffers_explicit_gc(); } static void _register_gc_task(void) { if (scratch_buffers_gc.handler && iv_inited() && !iv_task_registered(&scratch_buffers_gc)) iv_task_register(&scratch_buffers_gc); } void scratch_buffers_automatic_gc_init(void) { IV_TASK_INIT(&scratch_buffers_gc); if (iv_inited()) { /* the automatic GC requires an ivykis thread */ scratch_buffers_gc.handler = _garbage_collect_scratch_buffers; } } void scratch_buffers_automatic_gc_deinit(void) { if (iv_task_registered(&scratch_buffers_gc)) iv_task_unregister(&scratch_buffers_gc); } void scratch_buffers_register_stats(void) { StatsClusterKey sc_key; stats_lock(); stats_cluster_single_key_set(&sc_key, "scratch_buffers_count", NULL, 0); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_GLOBAL, "scratch_buffers_count", NULL, "queued"); stats_register_counter(0, &sc_key, SC_TYPE_SINGLE_VALUE, &stats_scratch_buffers_count); stats_cluster_single_key_set(&sc_key, "scratch_buffers_bytes", NULL, 0); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_GLOBAL, "scratch_buffers_bytes", NULL, "queued"); stats_register_counter(0, &sc_key, SC_TYPE_SINGLE_VALUE, &stats_scratch_buffers_bytes); stats_unlock(); } void scratch_buffers_unregister_stats(void) { StatsClusterKey sc_key; stats_lock(); stats_cluster_single_key_set(&sc_key, "scratch_buffers_count", NULL, 0); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_GLOBAL, "scratch_buffers_count", NULL, "queued"); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &stats_scratch_buffers_count); stats_cluster_single_key_set(&sc_key, "scratch_buffers_bytes", NULL, 0); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, SCS_GLOBAL, "scratch_buffers_bytes", NULL, "queued"); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &stats_scratch_buffers_bytes); stats_unlock(); } void scratch_buffers_global_init(void) { register_application_hook(AH_RUNNING, (ApplicationHookFunc) scratch_buffers_register_stats, NULL, AHM_RUN_ONCE); } void scratch_buffers_global_deinit(void) { scratch_buffers_unregister_stats(); } syslog-ng-syslog-ng-4.4.0/lib/scratch-buffers.h000066400000000000000000000042361450431004300213600ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SCRATCH_BUFFERS2_H_INCLUDED #define SCRATCH_BUFFERS2_H_INCLUDED 1 #include "syslog-ng.h" typedef gint32 ScratchBuffersMarker; GString *scratch_buffers_alloc(void); GString *scratch_buffers_alloc_and_mark(ScratchBuffersMarker *marker); void scratch_buffers_mark(ScratchBuffersMarker *marker); void scratch_buffers_reclaim_allocations(void); void scratch_buffers_reclaim_marked(ScratchBuffersMarker marker); gssize scratch_buffers_get_global_allocation_count(void); gssize scratch_buffers_get_local_allocation_count(void); gssize scratch_buffers_get_local_allocation_bytes(void); gint scratch_buffers_get_local_usage_count(void); void scratch_buffers_update_stats(void); /* lazy stats update */ void scratch_buffers_lazy_update_stats(void); /* garbage collector */ void scratch_buffers_explicit_gc(void); void scratch_buffers_allocator_init(void); void scratch_buffers_allocator_deinit(void); void scratch_buffers_automatic_gc_init(void); void scratch_buffers_automatic_gc_deinit(void); void scratch_buffers_register_stats(void); void scratch_buffers_unregister_stats(void); void scratch_buffers_global_init(void); void scratch_buffers_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/secret-storage/000077500000000000000000000000001450431004300210505ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/secret-storage/CMakeLists.txt000066400000000000000000000012101450431004300236020ustar00rootroot00000000000000set(SECRET_STORAGE_SOURCES secret-storage.c nondumpable-allocator.c) set(SECRET_STORAGE_HEADERS secret-storage.h nondumpable-allocator.h) add_library(secret-storage SHARED ${SECRET_STORAGE_SOURCES}) target_include_directories(secret-storage PRIVATE # workaround, "compat" should be a separate static library ${PROJECT_SOURCE_DIR}/lib ) target_link_libraries(secret-storage PRIVATE GLib::GLib) set_target_properties(secret-storage PROPERTIES C_VISIBILITY_PRESET hidden) install(TARGETS secret-storage LIBRARY DESTINATION lib) install(FILES ${SECRET_STORAGE_HEADERS} DESTINATION include/syslog-ng) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/secret-storage/Makefile.am000066400000000000000000000011611450431004300231030ustar00rootroot00000000000000lib_LTLIBRARIES += lib/secret-storage/libsecret-storage.la EXTRA_DIST += lib/secret-storage/CMakeLists.txt lib_secret_storageincludedir = $(pkgincludedir) lib_secret_storageinclude_HEADERS = \ lib/secret-storage/secret-storage.h \ lib/secret-storage/nondumpable-allocator.h lib_secret_storage_libsecret_storage_la_SOURCES = \ lib/secret-storage/secret-storage.c \ lib/secret-storage/nondumpable-allocator.c lib_secret_storage_libsecret_storage_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden lib_secret_storage_libsecret_storage_la_LIBADD = @GLIB_LIBS@ include lib/secret-storage/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/secret-storage/nondumpable-allocator.c000066400000000000000000000115251450431004300255020ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include #include #include #include /* For compatibility with e.g. older macOS. */ #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) #define MAP_ANONYMOUS MAP_ANON #endif #include "nondumpable-allocator.h" #define ALLOCATION_HEADER_SIZE offsetof(Allocation, user_data) #define BUFFER_TO_ALLOCATION(buffer) ((Allocation *) ((guint8 *) buffer - ALLOCATION_HEADER_SIZE)) static void _silent(gchar *summary, gchar *reason) { } NonDumpableLogger logger_debug_fn INTERNAL = _silent; NonDumpableLogger logger_fatal_fn INTERNAL = _silent; void nondumpable_setlogger(NonDumpableLogger _debug, NonDumpableLogger _fatal) { logger_debug_fn = _debug; logger_fatal_fn = _fatal; } #define logger_debug(summary, fmt, ...) \ { \ gchar *reason = g_strdup_printf(fmt, __VA_ARGS__); \ logger_debug_fn(summary, reason); \ g_free(reason); \ } #define logger_fatal(summary, fmt, ...) \ { \ gchar *reason = g_strdup_printf(fmt, __VA_ARGS__); \ logger_fatal_fn(summary, reason); \ g_free(reason); \ } typedef struct { gsize alloc_size; gsize data_len; guint8 user_data[]; } Allocation; static gboolean _exclude_memory_from_core_dump(gpointer area, gsize len) { #if defined(MADV_DONTDUMP) if (madvise(area, len, MADV_DONTDUMP) < 0) { if (errno == EINVAL) { logger_debug("secret storage: MADV_DONTDUMP not supported", "len: %"G_GSIZE_FORMAT", errno: %d\n", len, errno); return TRUE; } logger_fatal("secret storage: cannot madvise buffer", "errno: %d\n", errno); return FALSE; } #endif return TRUE; } static gpointer _mmap(gsize len) { gpointer area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); if (area == MAP_FAILED) { logger_fatal("secret storage: cannot mmap buffer", "len: %"G_GSIZE_FORMAT", errno: %d\n", len, errno); return MAP_FAILED; } if (!_exclude_memory_from_core_dump(area, len)) goto err_munmap; if (mlock(area, len) < 0) { gchar *hint = (errno == ENOMEM) ? ". Maybe RLIMIT_MEMLOCK is too small?" : ""; logger_fatal("secret storage: cannot lock buffer", "len: %"G_GSIZE_FORMAT", errno: %d%s\n", len, errno, hint); goto err_munmap; } return area; err_munmap: munmap(area, len); return MAP_FAILED; } static gsize round_to_nearest(gsize number, gsize base) { return number + (base - (number % base)); } gpointer nondumpable_buffer_alloc(gsize len) { gsize minimum_size = len + ALLOCATION_HEADER_SIZE; gsize pagesize = sysconf(_SC_PAGE_SIZE); gsize alloc_size = round_to_nearest(minimum_size, pagesize); Allocation *buffer = _mmap(alloc_size); if (buffer == MAP_FAILED) return NULL; buffer->alloc_size = alloc_size; buffer->data_len = len; return buffer->user_data; } void nondumpable_mem_zero(gpointer s, gsize len) { volatile guchar *p = s; for (gsize i = 0; i < len; ++i) p[i] = 0; } void nondumpable_buffer_free(gpointer buffer) { Allocation *allocation = BUFFER_TO_ALLOCATION(buffer); nondumpable_mem_zero(allocation->user_data, allocation->data_len); munmap(allocation, allocation->alloc_size); } gpointer nondumpable_buffer_realloc(gpointer buffer, gsize len) { Allocation *allocation = BUFFER_TO_ALLOCATION(buffer); if (allocation->alloc_size >= len + ALLOCATION_HEADER_SIZE) { allocation->data_len = len; return allocation->user_data; } gpointer new_buffer = nondumpable_buffer_alloc(len); nondumpable_memcpy(new_buffer, allocation->user_data, allocation->data_len); nondumpable_buffer_free(buffer); return new_buffer; } /* glibc implementation of memcpy can use stack, exposing parts of the secrets */ gpointer nondumpable_memcpy(gpointer dest, gpointer src, gsize len) { gchar *_dest = dest; gchar *_src = src; for (gsize i = 0; i < len; i++) { _dest[i] = _src[i]; } return dest; } syslog-ng-syslog-ng-4.4.0/lib/secret-storage/nondumpable-allocator.h000066400000000000000000000031631450431004300255060ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef NONDUMPABLE_ALLOCATOR_H_INCLUDED #define NONDUMPABLE_ALLOCATOR_H_INCLUDED #include "compat/glib.h" #define PUBLIC __attribute__ ((visibility ("default"))) #define INTERNAL __attribute__ ((visibility ("hidden"))) typedef void(*NonDumpableLogger)(gchar *summary, gchar *reason); gpointer nondumpable_buffer_alloc(gsize len) PUBLIC; void nondumpable_buffer_free(gpointer buffer) PUBLIC; gpointer nondumpable_buffer_realloc(gpointer buffer, gsize len) PUBLIC; gpointer nondumpable_memcpy(gpointer dest, gpointer src, gsize len) PUBLIC; void nondumpable_mem_zero(gpointer s, gsize len) PUBLIC; void nondumpable_setlogger(NonDumpableLogger _debug, NonDumpableLogger _fatal) PUBLIC; #endif syslog-ng-syslog-ng-4.4.0/lib/secret-storage/secret-storage.c000066400000000000000000000212601450431004300241440ustar00rootroot00000000000000/* * Copyright (c) 2023 One Identity LLC * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include #include "nondumpable-allocator.h" #include "secret-storage.h" #define SECRET_HEADER_SIZE offsetof(Secret, data) #define SECRET_STORAGE_HEADER_SIZE (SECRET_HEADER_SIZE + offsetof(SecretStorage, secret)) #define SECRET_STORAGE_INITIAL_SIZE 2048 typedef struct { SecretStorageCB func; gpointer user_data; } Subscription; typedef struct { GArray *subscriptions; SecretStorageSecretState state; Secret secret; } SecretStorage; GHashTable *secret_manager INTERNAL; volatile gint secret_manager_uninitialized INTERNAL = 1; static SecretStorage * secret_storage_new(gsize len) { SecretStorage *storage = nondumpable_buffer_alloc(len + SECRET_STORAGE_HEADER_SIZE); return storage; } static void secret_storage_free(SecretStorage *self) { g_array_free(self->subscriptions, TRUE); nondumpable_buffer_free(self); } void secret_storage_init(void) { if (g_atomic_int_dec_and_test(&secret_manager_uninitialized)) { secret_manager = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)secret_storage_free); g_assert(secret_manager); } else g_assert_not_reached(); } void secret_storage_deinit(void) { g_assert(!secret_manager_uninitialized); g_atomic_int_inc(&secret_manager_uninitialized); g_assert(secret_manager_uninitialized == 1); g_hash_table_destroy(secret_manager); secret_manager = NULL; } static void write_secret(SecretStorage *storage, gchar *secret, gsize len) { storage->secret.len = len; nondumpable_memcpy(storage->secret.data, secret, len); } static SecretStorage * overwrite_secret(SecretStorage *storage, gchar *secret, gsize len) { nondumpable_mem_zero(storage->secret.data, storage->secret.len); write_secret(storage, secret, len); return storage; } static SecretStorage * realloc_and_write_secret(SecretStorage *secret_storage, const gchar *key, gchar *secret, gsize len) { SecretStorage *maybe_new_storage = nondumpable_buffer_realloc(secret_storage, len); write_secret(maybe_new_storage, secret, len); if (secret_storage != maybe_new_storage) g_hash_table_insert(secret_manager, g_strdup(key), maybe_new_storage); return maybe_new_storage; } static SecretStorage * update_storage_with_secret(SecretStorage *secret_storage, const gchar *key, gchar *secret, gsize len) { gboolean fits_into_storage = (len <= secret_storage->secret.len); if (fits_into_storage) return overwrite_secret(secret_storage, secret, len); else return realloc_and_write_secret(secret_storage, key, secret, len); } static SecretStorage * create_secret_storage_with_secret(const gchar *key, gchar *secret, gsize len) { SecretStorage *secret_storage = secret_storage_new(len); if (!secret_storage) return NULL; secret_storage->secret.len = len; nondumpable_memcpy(&secret_storage->secret.data, secret, len); g_hash_table_insert(secret_manager, g_strdup(key), secret_storage); secret_storage->subscriptions = g_array_new(FALSE, FALSE, sizeof(Subscription)); secret_storage->state = SECRET_STORAGE_STATUS_PENDING; return secret_storage; } static void run_callbacks_initiate(const gchar *key, GArray *subscriptions) { static gboolean initiated = FALSE; if (initiated) return; initiated = TRUE; gsize original_length = subscriptions->len; for (int i = 0; i < original_length; i++) { Subscription sub = g_array_index(subscriptions, Subscription, i); secret_storage_with_secret(key, sub.func, sub.user_data); } if (original_length) g_array_remove_range(subscriptions, 0, original_length); initiated = FALSE; } gboolean secret_storage_store_secret(const gchar *key, gchar *secret, gsize len) { if (!secret) len = 0; else if (len == -1) len = strlen(secret) + 1; SecretStorage *secret_storage; secret_storage = g_hash_table_lookup(secret_manager, key); if (secret_storage) secret_storage = update_storage_with_secret(secret_storage, key, secret, len); else secret_storage = create_secret_storage_with_secret(key, secret, len); if (!secret_storage) return FALSE; run_callbacks_initiate(key, secret_storage->subscriptions); return TRUE; } void secret_storage_wipe(gpointer s, gsize len) { nondumpable_mem_zero(s, len); } gboolean secret_storage_store_string(const gchar *key, gchar *secret) { return secret_storage_store_secret(key, secret, -1); } Secret *secret_storage_clone_secret(Secret *self) { Secret *copy = nondumpable_buffer_alloc(self->len + SECRET_HEADER_SIZE); if (!copy) return NULL; copy->len = self->len; nondumpable_memcpy(copy->data, self->data, self->len); return copy; } Secret * secret_storage_get_secret_by_name(const gchar *key) { SecretStorage *secret_storage = g_hash_table_lookup(secret_manager, key); if (!secret_storage) return NULL; return secret_storage_clone_secret(&secret_storage->secret); } void secret_storage_put_secret(Secret *self) { nondumpable_buffer_free(self); } void secret_storage_with_secret(const gchar *key, SecretStorageCB func, gpointer user_data) { Secret *secret = secret_storage_get_secret_by_name(key); if (!secret) return; func(secret, user_data); secret_storage_put_secret(secret); } static gboolean insert_empty_secret_storage(const gchar *key) { return secret_storage_store_string(key, NULL); } gboolean secret_storage_subscribe_for_key(const gchar *key, SecretStorageCB func, gpointer user_data) { SecretStorage *secret_storage; if (!g_hash_table_lookup(secret_manager, key)) if (!insert_empty_secret_storage(key)) return FALSE; secret_storage = g_hash_table_lookup(secret_manager, key); Subscription new_subscription = {.func = func, .user_data = user_data}; g_array_append_val(secret_storage->subscriptions, new_subscription); if (secret_storage->secret.len != 0) { run_callbacks_initiate(key, secret_storage->subscriptions); } return TRUE; } void secret_storage_unsubscribe(const gchar *key, SecretStorageCB func, gpointer user_data) { SecretStorage *secret_storage; secret_storage = g_hash_table_lookup(secret_manager, key); if (!secret_storage || !secret_storage->subscriptions) return; GArray *subscriptions = secret_storage->subscriptions; for (gsize i = 0; i < subscriptions->len; i++) { Subscription sub = g_array_index(subscriptions, Subscription, i); if (sub.func == func && sub.user_data == user_data) { secret_storage->subscriptions = g_array_remove_index(subscriptions, i); break; } } } typedef struct { SecretStatusCB func; gpointer user_data; } SecretCallBackAction; static gboolean run_callback_for_status(const gpointer key, gpointer value, gpointer user_data) { SecretStorage *storage = (SecretStorage *)value; SecretCallBackAction *action = (SecretCallBackAction *)user_data; gchar *key_with_obscured_location = g_strdup((const gchar *)key); SecretStatus secret_status = {.key = key_with_obscured_location, .state = storage->state}; gboolean should_continue = !action->func(&secret_status, action->user_data); g_free(key_with_obscured_location); return should_continue; } void secret_storage_status_foreach(SecretStatusCB cb, gpointer user_data) { SecretCallBackAction action = {.func = cb, .user_data = user_data}; g_hash_table_find(secret_manager, run_callback_for_status, &action); } void secret_storage_update_status(const gchar *key, SecretStorageSecretState state) { SecretStorage *secret_storage; secret_storage = g_hash_table_lookup(secret_manager, key); if (!secret_storage) return; secret_storage->state = state; } gboolean secret_storage_contains_key(const gchar *key) { SecretStorage *secret_storage = g_hash_table_lookup(secret_manager, key); return (secret_storage != NULL); } syslog-ng-syslog-ng-4.4.0/lib/secret-storage/secret-storage.h000066400000000000000000000051671450431004300241610ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SECRET_STORAGE_H_INCLUDED #define SECRET_STORAGE_H_INCLUDED #include "compat/glib.h" #define PUBLIC __attribute__ ((visibility ("default"))) #define INTERNAL __attribute__ ((visibility ("hidden"))) typedef struct { gsize len; gchar data[]; } Secret; typedef void(*SecretStorageCB)(Secret *secret, gpointer user_data); void secret_storage_init(void) PUBLIC; void secret_storage_deinit(void) PUBLIC; gboolean secret_storage_store_string(const gchar *key, gchar *secret) PUBLIC; gboolean secret_storage_store_secret(const gchar *key, gchar *secret, gsize len) PUBLIC; void secret_storage_wipe(gpointer s, gsize len) PUBLIC; void secret_storage_with_secret(const gchar *key, SecretStorageCB func, gpointer user_data) PUBLIC; Secret *secret_storage_get_secret_by_name(const gchar *key) PUBLIC; void secret_storage_put_secret(Secret *self) PUBLIC; Secret *secret_storage_clone_secret(Secret *self) PUBLIC; gboolean secret_storage_subscribe_for_key(const gchar *key, SecretStorageCB func, gpointer user_data) PUBLIC; void secret_storage_unsubscribe(const gchar *key, SecretStorageCB func, gpointer user_data) PUBLIC; typedef enum { SECRET_STORAGE_STATUS_PENDING = 0, SECRET_STORAGE_SUCCESS, SECRET_STORAGE_STATUS_FAILED, SECRET_STORAGE_STATUS_INVALID_PASSWORD } SecretStorageSecretState; void secret_storage_update_status(const gchar *key, SecretStorageSecretState state) PUBLIC; typedef struct { gchar *key; SecretStorageSecretState state; } SecretStatus; typedef gboolean (*SecretStatusCB)(SecretStatus *secret_status, gpointer user_data); void secret_storage_status_foreach(SecretStatusCB cb, gpointer user_data) PUBLIC; gboolean secret_storage_contains_key(const gchar *key) PUBLIC; #endif syslog-ng-syslog-ng-4.4.0/lib/secret-storage/tests/000077500000000000000000000000001450431004300222125ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/secret-storage/tests/CMakeLists.txt000066400000000000000000000002351450431004300247520ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_secret_storage DEPENDS secret-storage) add_unit_test(CRITERION TARGET test_nondumpable_allocator DEPENDS secret-storage) syslog-ng-syslog-ng-4.4.0/lib/secret-storage/tests/Makefile.am000066400000000000000000000014521450431004300242500ustar00rootroot00000000000000lib_secret_storage_tests_TESTS = \ lib/secret-storage/tests/test_secret_storage \ lib/secret-storage/tests/test_nondumpable_allocator EXTRA_DIST += lib/secret-storage/tests/CMakeLists.txt check_PROGRAMS += ${lib_secret_storage_tests_TESTS} lib_secret_storage_tests_test_secret_storage_CFLAGS = $(TEST_CFLAGS) \ -I$(top_srcdir)/lib/secret-storage lib_secret_storage_tests_test_secret_storage_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) -dlpreopen $(top_builddir)/lib/secret-storage/libsecret-storage.la lib_secret_storage_tests_test_nondumpable_allocator_CFLAGS = $(TEST_CFLAGS) \ -I$(top_srcdir)/lib/secret-storage lib_secret_storage_tests_test_nondumpable_allocator_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) -dlpreopen $(top_builddir)/lib/secret-storage/libsecret-storage.la syslog-ng-syslog-ng-4.4.0/lib/secret-storage/tests/test_nondumpable_allocator.c000066400000000000000000000047311450431004300277660ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "secret-storage/nondumpable-allocator.h" #include #include Test(nondumpableallocator, malloc_realloc_free) { char test_string[] = "test_string"; gpointer buffer = nondumpable_buffer_alloc(strlen(test_string)); strcpy(buffer, test_string); cr_assert_str_eq(buffer, test_string); const gsize pagesize = sysconf(_SC_PAGE_SIZE); gpointer buffer_realloc = nondumpable_buffer_realloc(buffer, 2*pagesize); cr_assert_str_eq(buffer_realloc, test_string); ((gchar *)buffer_realloc)[2*pagesize] = 'a'; nondumpable_buffer_free(buffer_realloc); } Test(nondumpableallocator, malloc_mem_zero) { const gsize buffer_len = 256; const guchar dummy_value = 0x44; guchar *buffer = nondumpable_buffer_alloc(buffer_len); memset(buffer, dummy_value, buffer_len); for (gsize i = 0; i < buffer_len; ++i) cr_assert_eq(buffer[i], dummy_value); nondumpable_mem_zero(buffer, buffer_len); for (gsize i = 0; i < buffer_len; ++i) cr_assert_eq(buffer[i], 0); nondumpable_buffer_free(buffer); } Test(nondumpableallocator, two_malloc) { char test_string1[] = "test_string2"; gpointer buffer1 = nondumpable_buffer_alloc(strlen(test_string1)); strcpy(buffer1, test_string1); char test_string2[] = "test_string2"; gpointer buffer2 = nondumpable_buffer_alloc(strlen(test_string2)); strcpy(buffer2, test_string2); cr_assert_str_eq(buffer1, test_string1); cr_assert_str_eq(buffer2, test_string2); nondumpable_buffer_free(buffer1); nondumpable_buffer_free(buffer2); } syslog-ng-syslog-ng-4.4.0/lib/secret-storage/tests/test_secret_storage.c000066400000000000000000000221441450431004300264310ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "secret-storage/secret-storage.h" #include "secret-storage/nondumpable-allocator.h" #include #include #include void logger(char *summary, char *reason) { fprintf(stderr, "%s : reason=%s", summary, reason); } void secret_storage_testsuite_init(void) { secret_storage_init(); nondumpable_setlogger(logger, logger); } void secret_storage_testsuite_deinit(void) { secret_storage_deinit(); } TestSuite(secretstorage, .init = secret_storage_testsuite_init, .fini = secret_storage_testsuite_deinit); Test(secretstorage, simple_store_get) { secret_storage_store_secret("key1", "value1", -1); Secret *secret = secret_storage_get_secret_by_name("key1"); cr_assert_str_eq(secret->data, "value1"); secret_storage_put_secret(secret); } void secret_checker(Secret *secret, gpointer expected) { cr_assert_str_eq(expected, secret->data); } Test(secretstorage, simple_store_with) { secret_storage_store_secret("key1", "value1", -1); secret_storage_with_secret("key1", secret_checker, "value1"); } Test(secretstorage, simple_store_single_string) { secret_storage_store_string("key1", "value1"); Secret *secret = secret_storage_get_secret_by_name("key1"); cr_assert_str_eq(secret->data, "value1"); secret_storage_put_secret(secret); } Test(secretstorage, store_multiple_secrets) { secret_storage_store_string("key1", "value1"); secret_storage_store_string("key2", "value2"); Secret *secret1 = secret_storage_get_secret_by_name("key1"); cr_assert_str_eq(secret1->data, "value1"); Secret *secret2 = secret_storage_get_secret_by_name("key2"); cr_assert_str_eq(secret2->data, "value2"); secret_storage_put_secret(secret1); secret_storage_put_secret(secret2); } Test(secretstorage, read_nonexistent_secret) { Secret *secret = secret_storage_get_secret_by_name("key"); cr_assert_eq(secret, NULL); } Test(secretstorage, store_secret_with_embedded_zero) { secret_storage_store_secret("key", "a\0b", 4); Secret *secret = secret_storage_get_secret_by_name("key"); gint result = memcmp(secret->data, "a\0b", 4); cr_assert_eq(result, 0); secret_storage_put_secret(secret); } void set_variable_to_true_cb(Secret *secret, gpointer user_data) { *((gboolean *)user_data) = TRUE; } Test(secretstorage, subscribe_before_store) { gboolean test_variable = FALSE; secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &test_variable); cr_assert_not(test_variable); secret_storage_store_string("key", "secret"); cr_assert(test_variable); } Test(secretstorage, subscribe_after_store) { gboolean test_variable = FALSE; secret_storage_store_string("key", "secret"); secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &test_variable); cr_assert(test_variable); } Test(secretstorage, subscriptions_per_keys) { gboolean key1_test_variable = FALSE; gboolean key2_test_variable = FALSE; secret_storage_subscribe_for_key("key1", set_variable_to_true_cb, &key1_test_variable); secret_storage_subscribe_for_key("key2", set_variable_to_true_cb, &key2_test_variable); cr_assert_not(key1_test_variable); cr_assert_not(key2_test_variable); secret_storage_store_string("key1", "secret"); cr_assert(key1_test_variable); cr_assert_not(key2_test_variable); secret_storage_store_string("key2", "secret"); cr_assert(key1_test_variable); cr_assert(key2_test_variable); } Test(secretstorage, two_subscribe_without_store) { gboolean test_variable = FALSE; secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &test_variable); secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &test_variable); cr_assert_not(test_variable); } void check_secret(Secret *secret, gpointer user_data) { cr_assert_str_eq(secret->data, user_data); } Test(secretstorage, subscribe_cb_check_secret) { secret_storage_subscribe_for_key("key", check_secret, "secret"); secret_storage_store_string("key", "secret"); } Test(secretstorage, multiple_subscriptions_for_same_key) { gboolean key1_test_variable = FALSE; gboolean key2_test_variable = FALSE; secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &key1_test_variable); secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &key2_test_variable); cr_assert_not(key1_test_variable); cr_assert_not(key2_test_variable); secret_storage_store_string("key", "secret"); cr_assert(key1_test_variable); cr_assert(key2_test_variable); } Test(secretstorage, subscription_reset_after_called) { gboolean key_test_variable = FALSE; secret_storage_subscribe_for_key("key", set_variable_to_true_cb, &key_test_variable); secret_storage_store_string("key", "secret"); cr_assert(key_test_variable); key_test_variable = FALSE; secret_storage_store_string("key", "secret"); cr_assert_not(key_test_variable); } typedef struct { gpointer user_data; gpointer evidence; } UserDataWithEvidence; gboolean check_status_callback(SecretStatus *secret_status, gpointer user_data) { cr_assert_str_eq(secret_status->key, ((UserDataWithEvidence *)user_data)->user_data); gboolean *evidence = ((UserDataWithEvidence *)user_data)->evidence; *evidence = TRUE; return TRUE; } Test(secretstorage, check_secret_status) { gboolean test_variable = FALSE; secret_storage_store_string("key", "secret"); UserDataWithEvidence user_data = {.user_data = "key", .evidence = &test_variable}; secret_storage_status_foreach(check_status_callback, &user_data); cr_assert(test_variable); } gboolean stop_in_the_middle_callback(SecretStatus *secret_status, gpointer user_data) { gint *test_variable = user_data; gboolean should_continue = (1 != *test_variable); (*test_variable)++; return should_continue; } Test(secretstorage, secret_status_can_stop_in_the_middle) { gint test_variable = 0; secret_storage_store_string("key1", "secret"); secret_storage_store_string("key2", "secret"); secret_storage_store_string("key3", "secret"); secret_storage_store_string("key4", "secret"); secret_storage_status_foreach(stop_in_the_middle_callback, &test_variable); cr_assert_eq(test_variable, 2); } void subscribe_until_success(Secret *secret, gpointer user_data) { if (strcmp(secret->data, "good_password")) { secret_storage_subscribe_for_key("key", subscribe_until_success, user_data); return; } *((gboolean *)user_data) = TRUE; } Test(secretstorage, subscribe_until_success) { gboolean test_variable = FALSE; secret_storage_subscribe_for_key("key", subscribe_until_success, &test_variable); secret_storage_store_string("key", "wrong_password"); cr_assert_not(test_variable); secret_storage_store_string("key", "good_password"); cr_assert(test_variable); } Test(secretstorage, test_rlimit) { struct rlimit locked_limit; cr_assert(!getrlimit(RLIMIT_MEMLOCK, &locked_limit)); locked_limit.rlim_cur = MIN(locked_limit.rlim_max, 64 * 1024); cr_assert(!setrlimit(RLIMIT_MEMLOCK, &locked_limit)); const gsize pagesize = sysconf(_SC_PAGE_SIZE); gchar *key_fmt = g_strdup("keyXXX"); int i = 0; int for_limit = locked_limit.rlim_cur/pagesize; for (; i < for_limit; i++) { sprintf(key_fmt, "key%03d", i); cr_assert(secret_storage_store_string(key_fmt, "value"), "offending_key: %s, for_limit: %d", key_fmt, for_limit); } g_free(key_fmt); } static void update_state_callback(Secret *secret, gpointer user_data) { secret_storage_update_status("key", SECRET_STORAGE_STATUS_INVALID_PASSWORD); } static gboolean assert_invalid_password_state(SecretStatus *secret_status, gpointer user_data) { cr_assert_eq(secret_status->state, SECRET_STORAGE_STATUS_INVALID_PASSWORD); return FALSE; } Test(secretstorage, test_state_update) { secret_storage_subscribe_for_key("key", update_state_callback, NULL); secret_storage_store_string("key", "wrong_password"); secret_storage_status_foreach(assert_invalid_password_state, NULL); } Test(secretstorage, simple_store_get_and_wipe) { secret_storage_store_secret("key1", "value1", -1); Secret *secret = secret_storage_get_secret_by_name("key1"); cr_assert_str_eq(secret->data, "value1"); secret_storage_wipe(secret->data, secret->len); for (gsize i = 0; i < secret->len; ++i) cr_assert_eq(secret->data[i], 0); secret_storage_put_secret(secret); } syslog-ng-syslog-ng-4.4.0/lib/seqnum.h000066400000000000000000000026511450431004300176060ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SEQNUM_H_INLCLUDED #define SEQNUM_H_INLCLUDED 1 #include "syslog-ng.h" static inline void init_sequence_number(gint32 *seqnum) { *seqnum = 1; } static inline gint32 step_sequence_number(gint32 *seqnum) { gint32 old_value = *seqnum; (*seqnum)++; if (*seqnum < 0) *seqnum = 1; return old_value; } static inline gint32 step_sequence_number_atomic(gint32 *seqnum) { return (gint32)g_atomic_int_add(seqnum, 1); } #endif syslog-ng-syslog-ng-4.4.0/lib/serialize.c000066400000000000000000000145541450431004300202650ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "serialize.h" #include "messages.h" #include #include #include typedef struct _SerializeFileArchive { SerializeArchive super; FILE *f; } SerializeFileArchive; typedef struct _SerializeStringArchive { SerializeArchive super; gsize pos; GString *string; } SerializeStringArchive; typedef struct _SerializeBufferArchive { SerializeArchive super; gsize pos; gsize len; gchar *buff; } SerializeBufferArchive; void _serialize_handle_errors(SerializeArchive *self, const gchar *error_desc, GError *error) { if (error) g_set_error(&self->error, G_FILE_ERROR, G_FILE_ERROR_IO, "%s: %s", error_desc, error->message); if (!self->silent) { msg_error(error_desc, evt_tag_str("error", error->message)); } g_error_free(error); } void serialize_archive_free(SerializeArchive *self) { g_clear_error(&self->error); g_slice_free1(self->len, self); } static gboolean serialize_file_archive_read_bytes(SerializeArchive *s, gchar *buf, gsize buflen, GError **error) { SerializeFileArchive *self = (SerializeFileArchive *) s; gssize bytes_read; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if (buflen == 0) { return TRUE; } bytes_read = fread(buf, 1, buflen, self->f); if (bytes_read < 0 || bytes_read != buflen) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error reading file (%s)", bytes_read < 0 ? g_strerror(errno) : "short read"); return FALSE; } return TRUE; } static gboolean serialize_file_archive_write_bytes(SerializeArchive *s, const gchar *buf, gsize buflen, GError **error) { SerializeFileArchive *self = (SerializeFileArchive *) s; gssize bytes_written; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); bytes_written = fwrite(buf, 1, buflen, self->f); if (bytes_written < 0 || bytes_written != buflen) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error writing file (%s)", bytes_written < 0 ? g_strerror(errno) : "short write"); return FALSE; } return TRUE; } SerializeArchive * serialize_file_archive_new(FILE *f) { SerializeFileArchive *self = g_slice_new0(SerializeFileArchive); self->super.read_bytes = serialize_file_archive_read_bytes; self->super.write_bytes = serialize_file_archive_write_bytes; self->super.len = sizeof(SerializeFileArchive); self->f = f; return &self->super; } void serialize_string_archive_reset(SerializeArchive *sa) { SerializeStringArchive *self = (SerializeStringArchive *) sa; self->pos = 0; } static gboolean serialize_string_archive_read_bytes(SerializeArchive *s, gchar *buf, gsize buflen, GError **error) { SerializeStringArchive *self = (SerializeStringArchive *) s; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if (buflen == 0) { return TRUE; } if ((gssize) self->pos + buflen > (gssize) self->string->len) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error reading from string, stored data too short"); return FALSE; } memcpy(buf, &self->string->str[self->pos], buflen); self->pos += buflen; return TRUE; } static gboolean serialize_string_archive_write_bytes(SerializeArchive *s, const gchar *buf, gsize buflen, GError **error) { SerializeStringArchive *self = (SerializeStringArchive *) s; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); g_string_append_len(self->string, buf, buflen); return TRUE; } SerializeArchive * serialize_string_archive_new(GString *str) { SerializeStringArchive *self = g_slice_new0(SerializeStringArchive); self->super.read_bytes = serialize_string_archive_read_bytes; self->super.write_bytes = serialize_string_archive_write_bytes; self->super.len = sizeof(SerializeStringArchive); self->string = str; return &self->super; } static gboolean serialize_buffer_archive_read_bytes(SerializeArchive *s, gchar *buf, gsize buflen, GError **error) { SerializeBufferArchive *self = (SerializeBufferArchive *) s; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if ((gssize) self->pos + buflen > (gssize) self->len) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error reading from buffer, stored data too short"); return FALSE; } memcpy(buf, &self->buff[self->pos], buflen); self->pos += buflen; return TRUE; } static gboolean serialize_buffer_archive_write_bytes(SerializeArchive *s, const gchar *buf, gsize buflen, GError **error) { SerializeBufferArchive *self = (SerializeBufferArchive *) s; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if (self->pos + buflen > self->len) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error writing to buffer, buffer is too small"); return FALSE; } memcpy(self->buff + self->pos, buf, buflen); self->pos += buflen; return TRUE; } gsize serialize_buffer_archive_get_pos(SerializeArchive *s) { SerializeBufferArchive *self = (SerializeBufferArchive *) s; return self->pos; } SerializeArchive * serialize_buffer_archive_new(gchar *buff, gsize len) { SerializeBufferArchive *self = g_slice_new0(SerializeBufferArchive); self->super.read_bytes = serialize_buffer_archive_read_bytes; self->super.write_bytes = serialize_buffer_archive_write_bytes; self->super.len = sizeof(SerializeBufferArchive); self->buff = buff; self->len = len; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/serialize.h000066400000000000000000000172231450431004300202660ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SERIALIZE_H_INCLUDED #define SERIALIZE_H_INCLUDED #include "syslog-ng.h" #include #include typedef struct _SerializeArchive SerializeArchive; struct _SerializeArchive { GError *error; guint16 len; guint16 silent:1; gboolean (*read_bytes)(SerializeArchive *archive, gchar *buf, gsize count, GError **error); gboolean (*write_bytes)(SerializeArchive *archive, const gchar *buf, gsize count, GError **error); }; /* this is private and is only published so that the inline functions below can invoke it */ void _serialize_handle_errors(SerializeArchive *self, const gchar *error_desc, GError *error); static inline gboolean serialize_archive_read_bytes(SerializeArchive *self, gchar *buf, gsize buflen) { GError *error = NULL; if ((self->error == NULL) && !self->read_bytes(self, buf, buflen, &error)) _serialize_handle_errors(self, "Error reading serialized data", error); return self->error == NULL; } static inline gboolean serialize_archive_write_bytes(SerializeArchive *self, const gchar *buf, gsize buflen) { GError *error = NULL; if ((self->error == NULL) && !self->write_bytes(self, buf, buflen, &error)) _serialize_handle_errors(self, "Error writing serialized data", error); return self->error == NULL; } static inline gboolean serialize_write_uint32(SerializeArchive *archive, guint32 value) { guint32 n; n = GUINT32_TO_BE(value); return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n)); } static inline gboolean serialize_read_uint32(SerializeArchive *archive, guint32 *value) { guint32 n; if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n))) { *value = GUINT32_FROM_BE(n); return TRUE; } return FALSE; } /* NOTE: this function writes to the array to convert it to big endian. It * is converted back to native byte order before returning */ static inline gboolean serialize_write_uint32_array(SerializeArchive *archive, guint32 *values, gsize elements) { const gsize buffer_size = 128; guint32 converted_values[buffer_size]; gsize converted_ndx; while (elements > 0) { for (converted_ndx = 0; converted_ndx < buffer_size && converted_ndx < elements; converted_ndx++) converted_values[converted_ndx] = GUINT32_TO_BE(values[converted_ndx]); if (!serialize_archive_write_bytes(archive, (const gchar *) converted_values, converted_ndx * sizeof(guint32))) return FALSE; values += converted_ndx; elements -= converted_ndx; } return TRUE; } static inline gboolean serialize_read_uint32_array(SerializeArchive *archive, guint32 *values, gsize elements) { if (serialize_archive_read_bytes(archive, (gchar *) values, elements * sizeof(guint32))) { for (gsize i = 0; i < elements; i++) values[i] = GUINT32_FROM_BE(values[i]); return TRUE; } return FALSE; } static inline gboolean serialize_read_uint16_array(SerializeArchive *archive, guint32 *values, gsize elements) { guint16 buffer[elements]; if (serialize_archive_read_bytes(archive, (gchar *) &buffer, elements * sizeof(guint16))) { for (gsize i = 0; i < elements; i++) values[i] = GUINT16_FROM_BE(buffer[i]); return TRUE; } return FALSE; } static inline gboolean serialize_write_uint64(SerializeArchive *archive, guint64 value) { guint64 n; n = GUINT64_TO_BE(value); return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n)); } static inline gboolean serialize_read_uint64(SerializeArchive *archive, guint64 *value) { guint64 n; if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n))) { *value = GUINT64_FROM_BE(n); return TRUE; } return FALSE; } static inline gboolean serialize_write_uint16(SerializeArchive *archive, guint16 value) { guint16 n; n = GUINT16_TO_BE(value); return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n)); } static inline gboolean serialize_read_uint16(SerializeArchive *archive, guint16 *value) { guint16 n; if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n))) { *value = GUINT16_FROM_BE(n); return TRUE; } return FALSE; } static inline gboolean serialize_write_uint8(SerializeArchive *archive, guint8 value) { guint8 n; n = value; return serialize_archive_write_bytes(archive, (gchar *) &n, sizeof(n)); } static inline gboolean serialize_read_uint8(SerializeArchive *archive, guint8 *value) { guint8 n; if (serialize_archive_read_bytes(archive, (gchar *) &n, sizeof(n))) { *value = n; return TRUE; } return FALSE; } static inline gboolean serialize_write_blob(SerializeArchive *archive, const void *blob, gsize len) { return serialize_archive_write_bytes(archive, (const gchar *) blob, len); } static inline gboolean serialize_read_blob(SerializeArchive *archive, void *blob, gsize len) { return serialize_archive_read_bytes(archive, (gchar *) blob, len); } static inline gboolean serialize_write_string(SerializeArchive *archive, GString *str) { return serialize_write_uint32(archive, str->len) && serialize_archive_write_bytes(archive, str->str, str->len); } static inline gboolean serialize_read_string(SerializeArchive *archive, GString *str) { guint32 len; if (serialize_read_uint32(archive, &len)) { if (len > str->allocated_len) { gchar *p; p = (gchar *) g_try_realloc(str->str, len + 1); if (!p) return FALSE; str->str = p; str->str[len] = 0; str->len = len; } else g_string_set_size(str, len); return serialize_archive_read_bytes(archive, str->str, len); } return FALSE; } static inline gboolean serialize_write_cstring(SerializeArchive *archive, const gchar *str, gssize len) { if (len < 0) len = strlen(str); return serialize_write_uint32(archive, len) && (len == 0 || serialize_archive_write_bytes(archive, str, len)); } static inline gboolean serialize_read_cstring(SerializeArchive *archive, gchar **str, gsize *str_len) { guint32 len; if (serialize_read_uint32(archive, &len)) { *str = (gchar *) g_try_malloc(len + 1); if (!(*str)) return FALSE; (*str)[len] = 0; if (str_len) *str_len = len; return serialize_archive_read_bytes(archive, *str, len); } return FALSE; } SerializeArchive *serialize_file_archive_new(FILE *f); SerializeArchive *serialize_string_archive_new(GString *str); void serialize_string_archive_reset(SerializeArchive *sa); SerializeArchive *serialize_buffer_archive_new(gchar *buff, gsize len); gsize serialize_buffer_archive_get_pos(SerializeArchive *self); void serialize_archive_free(SerializeArchive *self); #endif syslog-ng-syslog-ng-4.4.0/lib/service-management.c000066400000000000000000000076001450431004300220420ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "service-management.h" #include "messages.h" #if SYSLOG_NG_ENABLE_SYSTEMD #include #include #include #include #endif typedef struct _ServiceManagement ServiceManagement; struct _ServiceManagement { ServiceManagementType type; void (*publish_status)(const gchar *status); void (*clear_status)(void); void (*indicate_readiness)(void); gboolean (*is_active)(void); }; ServiceManagement *current_service_mgmt = NULL; #if SYSLOG_NG_ENABLE_SYSTEMD static inline void service_management_systemd_publish_status(const gchar *status) { gchar *status_buffer; time_t now = time(NULL); status_buffer = g_strdup_printf("STATUS=%s (%s)", status, ctime(&now)); sd_notify(0, status_buffer); g_free(status_buffer); } static inline void service_management_systemd_clear_status(void) { sd_notify(0, "STATUS="); } static inline void service_management_systemd_indicate_readiness(void) { sd_notify(0, "READY=1"); } static gboolean service_management_systemd_is_active(void) { struct stat st; if (lstat("/run/systemd/system/", &st) < 0 || !S_ISDIR(st.st_mode)) { msg_debug("Systemd is not detected as the running init system"); return FALSE; } else { msg_debug("Systemd is detected as the running init system"); return TRUE; } } #endif void service_management_publish_status(const gchar *status) { current_service_mgmt->publish_status(status); } void service_management_clear_status(void) { current_service_mgmt->clear_status(); } void service_management_indicate_readiness(void) { current_service_mgmt->indicate_readiness(); } ServiceManagementType service_management_get_type(void) { return current_service_mgmt->type; } static inline void service_management_dummy_publish_status(const gchar *status) { } static inline void service_management_dummy_clear_status(void) { } static inline void service_management_dummy_indicate_readiness(void) { } static gboolean service_management_dummy_is_active(void) { return TRUE; } ServiceManagement service_managements[] = { { .type = SMT_NONE, .publish_status = service_management_dummy_publish_status, .clear_status = service_management_dummy_clear_status, .indicate_readiness = service_management_dummy_indicate_readiness, .is_active = service_management_dummy_is_active }, #if SYSLOG_NG_ENABLE_SYSTEMD { .type = SMT_SYSTEMD, .publish_status = service_management_systemd_publish_status, .clear_status = service_management_systemd_clear_status, .indicate_readiness = service_management_systemd_indicate_readiness, .is_active = service_management_systemd_is_active } #endif }; void service_management_init(void) { gint i = 0; while (i < sizeof(service_managements) / sizeof(ServiceManagement)) { if (service_managements[i].is_active()) current_service_mgmt = &service_managements[i]; i++; } } syslog-ng-syslog-ng-4.4.0/lib/service-management.h000066400000000000000000000026621450431004300220520ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATUS_PUBLISHER_H_INCLUDED #define STATUS_PUBLISHER_H_INCLUDED #include "syslog-ng.h" typedef enum _ServiceManagementType { SMT_NONE, SMT_SYSTEMD, SMT_MAX } ServiceManagementType; void service_management_publish_status(const gchar *status); void service_management_clear_status(void); void service_management_indicate_readiness(void); ServiceManagementType service_management_get_type(void); void service_management_init(void); #endif syslog-ng-syslog-ng-4.4.0/lib/signal-handler.c000066400000000000000000000104111450431004300211520ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #include #include #if defined(NSIG) # define SIGNAL_HANDLER_ARRAY_SIZE NSIG #elif defined(_NSIG) # define SIGNAL_HANDLER_ARRAY_SIZE _NSIG #else # define SIGNAL_HANDLER_ARRAY_SIZE 128 #endif static struct sigaction external_sigactions[SIGNAL_HANDLER_ARRAY_SIZE]; static gboolean internal_sigaction_registered[SIGNAL_HANDLER_ARRAY_SIZE]; static const struct sigaction * _get_external_sigaction(gint signum) { g_assert(signum < SIGNAL_HANDLER_ARRAY_SIZE); return &external_sigactions[signum]; } static void _set_external_sigaction(gint signum, const struct sigaction *external_sigaction) { g_assert(signum < SIGNAL_HANDLER_ARRAY_SIZE); memcpy(&external_sigactions[signum], external_sigaction, sizeof(struct sigaction)); } static gboolean _is_internal_sigaction_registered(gint signum) { g_assert(signum < SIGNAL_HANDLER_ARRAY_SIZE); return internal_sigaction_registered[signum]; } static void _set_internal_sigaction_registered(gint signum) { g_assert(signum < SIGNAL_HANDLER_ARRAY_SIZE); internal_sigaction_registered[signum] = TRUE; } void signal_handler_exec_external_handler(gint signum) { const struct sigaction *external_sigaction = _get_external_sigaction(signum); if (external_sigaction->sa_handler == SIG_DFL || external_sigaction->sa_handler == SIG_IGN) return; external_sigaction->sa_handler(signum); } #if SYSLOG_NG_HAVE_DLFCN_H #include static int _original_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { #ifdef __NetBSD__ return __libc_sigaction14(signum, act, oldact); #else static int (*real_sa)(int, const struct sigaction *, struct sigaction *); if (real_sa == NULL) real_sa = dlsym(RTLD_NEXT, "sigaction"); return real_sa(signum, act, oldact); #endif } static gint _register_internal_sigaction(gint signum, const struct sigaction *act, struct sigaction *oldact) { gint result = _original_sigaction(signum, act, oldact); if (result == 0) _set_internal_sigaction_registered(signum); return result; } static gboolean _need_to_save_external_sigaction_handler(gint signum) { /* We need to save external sigaction handlers for signums we internally set a handler to. See lib/mainloop.c */ switch (signum) { case SIGCHLD: case SIGINT: return TRUE; default: return FALSE; } } static void _save_external_sigaction_handler(gint signum, const struct sigaction *external_sigaction) { if (!external_sigaction) return; _set_external_sigaction(signum, external_sigaction); } static void _fill_oldact_with_previous_external_sigaction_handler(gint signum, struct sigaction *oldact) { if (!oldact) return; memcpy(oldact, _get_external_sigaction(signum), sizeof(struct sigaction)); } /* This should be as defined in the */ int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { if (!_need_to_save_external_sigaction_handler(signum)) return _original_sigaction(signum, act, oldact); /* Internal sigactions are always the first one to arrive to this function. */ if (!_is_internal_sigaction_registered(signum)) return _register_internal_sigaction(signum, act, oldact); _fill_oldact_with_previous_external_sigaction_handler(signum, oldact); _save_external_sigaction_handler(signum, act); return 0; } #endif syslog-ng-syslog-ng-4.4.0/lib/signal-handler.h000066400000000000000000000020301450431004300211550ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * Copyright (c) 2020 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ void signal_handler_exec_external_handler(gint signal); syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/000077500000000000000000000000001450431004300223455ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/CMakeLists.txt000066400000000000000000000003551450431004300251100ustar00rootroot00000000000000set(SIGNAL_SLOT_CONNECTOR_HEADERS signal-slot-connector/signal-slot-connector.h PARENT_SCOPE) set(SIGNAL_SLOT_CONNECTOR_SOURCES signal-slot-connector/signal-slot-connector.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/Makefile.am000066400000000000000000000006441450431004300244050ustar00rootroot00000000000000signal_slot_connectorincludedir = ${pkgincludedir}/signal-slot-connector EXTRA_DIST += lib/signal-slot-connector/CMakeLists.txt \ lib/signal-slot-connector/tests/CMakeLists.txt signal_slot_connectorinclude_HEADERS = \ lib/signal-slot-connector/signal-slot-connector.h signal_slot_connector_sources = \ lib/signal-slot-connector/signal-slot-connector.c include lib/signal-slot-connector/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/signal-slot-connector.c000066400000000000000000000157651450431004300267530ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "signal-slot-connector.h" typedef struct _SlotFunctor SlotFunctor; struct _SlotFunctor { Slot slot; gpointer object; }; static SlotFunctor * _slot_functor_new(Slot slot, gpointer object) { SlotFunctor *self = g_new0(SlotFunctor, 1); self->slot = slot; self->object = object; return self; } static void _slot_functor_free(gpointer data) { SlotFunctor *self = (SlotFunctor *) data; g_free(self); } static gboolean _slot_functor_eq(const SlotFunctor *a, const SlotFunctor *b) { return ((a->slot == b->slot) && (a->object == b->object)); } static gint _slot_functor_cmp(gconstpointer a, gconstpointer b) { const SlotFunctor *slot_obj_a = (const SlotFunctor *)a; const SlotFunctor *slot_obj_b = (const SlotFunctor *)b; if (_slot_functor_eq(slot_obj_a, slot_obj_b)) return 0; return -1; } struct _SignalSlotConnector { // map> connections; GHashTable *connections; GMutex lock; // connect/disconnect guarded by lock, emit is not }; static GList * _slot_lookup_node(GList *slot_functors, Slot slot, gpointer object) { for (GList *it = slot_functors; it != NULL; it = it->next) { SlotFunctor *s = (SlotFunctor *) it->data; if (s->slot == slot && s->object == object) return it; } return NULL; } static SlotFunctor * _slot_lookup(GList *slot_functors, Slot slot, gpointer object) { GList *slot_node = _slot_lookup_node(slot_functors, slot, object); if (!slot_node) return NULL; return (SlotFunctor *) slot_node->data; } void signal_slot_connect(SignalSlotConnector *self, Signal signal, Slot slot, gpointer object) { g_assert(signal != NULL); g_assert(slot != NULL); g_mutex_lock(&self->lock); GList *slots = g_hash_table_lookup(self->connections, signal); gboolean signal_registered = (slots != NULL); if (_slot_lookup(slots, slot, object)) { msg_trace("SignalSlotConnector::connect", evt_tag_printf("already_connected", "connect(connector=%p,signal=%s,slot=%p, object=%p)", self, signal, slot, object)); goto exit_; } GList *new_slots = g_list_append(slots, _slot_functor_new(slot, object)); if (!signal_registered) { g_hash_table_insert(self->connections, (gpointer)signal, new_slots); } msg_trace("SignalSlotConnector::connect", evt_tag_printf("new connection registered", "connect(connector=%p,signal=%s,slot=%p,object=%p)", self, signal, slot, object)); exit_: g_mutex_unlock(&self->lock); } static void _hash_table_replace(GHashTable *hash_table, gpointer key, gpointer new_value) { g_hash_table_steal(hash_table, key); gboolean inserted_as_new = g_hash_table_insert(hash_table, key, new_value); g_assert(inserted_as_new); } void signal_slot_disconnect(SignalSlotConnector *self, Signal signal, Slot slot, gpointer object) { g_assert(signal != NULL); g_assert(slot != NULL); g_mutex_lock(&self->lock); GList *slots = g_hash_table_lookup(self->connections, signal); if (!slots) goto exit_; msg_trace("SignalSlotConnector::disconnect", evt_tag_printf("connector", "%p", self), evt_tag_str("signal", signal), evt_tag_printf("slot", "%p", slot), evt_tag_printf("object", "%p", object)); SlotFunctor slotfunctor = { .slot = slot, .object = object }; GList *slotfunctor_node = g_list_find_custom(slots, &slotfunctor, _slot_functor_cmp); if (!slotfunctor_node) { msg_trace("SignalSlotConnector::disconnect slot object not found", evt_tag_printf("connector", "%p", self), evt_tag_str("signal", signal), evt_tag_printf("slot", "%p", slot), evt_tag_printf("object", "%p", object)); goto exit_; } GList *new_slots = g_list_remove_link(slots, slotfunctor_node); if (!new_slots) { g_hash_table_remove(self->connections, signal); msg_trace("SignalSlotConnector::disconnect last slot is disconnected, unregister signal", evt_tag_printf("connector", "%p", self), evt_tag_str("signal", signal), evt_tag_printf("slot", "%p", slot), evt_tag_printf("object", "%p", object)); goto exit_; } if (new_slots != slots) { _hash_table_replace(self->connections, (gpointer)signal, new_slots); } g_list_free_full(slotfunctor_node, _slot_functor_free); exit_: g_mutex_unlock(&self->lock); } static void _run_slot(gpointer data, gpointer user_data) { g_assert(data); SlotFunctor *slotfunctor = (SlotFunctor *)data; slotfunctor->slot(slotfunctor->object, user_data); } void signal_slot_emit(SignalSlotConnector *self, Signal signal, gpointer user_data) { g_assert(signal != NULL); msg_trace("SignalSlotConnector::emit", evt_tag_printf("connector", "%p", self), evt_tag_str("signal", signal), evt_tag_printf("user_data", "%p", user_data)); GList *slots = g_hash_table_lookup(self->connections, signal); if (!slots) { msg_trace("SignalSlotConnector: unregistered signal emitted", evt_tag_printf("connector", "%p", self), evt_tag_str("signal", signal)); return; } g_list_foreach(slots, _run_slot, user_data); } static void _destroy_list_of_slots(gpointer data) { if (!data) return; GList *list = (GList *)data; g_list_free_full(list, _slot_functor_free); } SignalSlotConnector * signal_slot_connector_new(void) { SignalSlotConnector *self = g_new0(SignalSlotConnector, 1); self->connections = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _destroy_list_of_slots); g_mutex_init(&self->lock); return self; } void signal_slot_connector_free(SignalSlotConnector *self) { g_mutex_clear(&self->lock); g_hash_table_unref(self->connections); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/signal-slot-connector.h000066400000000000000000000042601450431004300267440ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SIGNAL_SLOT_CONNECTOR_H_INCLUDED #define SIGNAL_SLOT_CONNECTOR_H_INCLUDED #include "syslog-ng.h" #include "messages.h" typedef struct _SignalSlotConnector SignalSlotConnector; typedef const gchar *Signal; #define STR(x) #x #define SIGNAL(modul, signal, signal_param_type) \ STR(modul) "::signal_" STR(signal) "(" STR(signal_param_type) ")" #define CONNECT(connector, signal, slot, slot_obj) \ signal_slot_connect(connector, signal, (Slot) slot, (gpointer) slot_obj); #define DISCONNECT(connector, signal, slot, slot_obj) \ signal_slot_disconnect(connector, signal, (Slot) slot, (gpointer) slot_obj); #define EMIT(connector, signal, user_data) \ signal_slot_emit(connector, signal, (gpointer) user_data); typedef void (*Slot)(gpointer object, gpointer user_data); void signal_slot_connect(SignalSlotConnector *self, Signal signal, Slot slot, gpointer object); void signal_slot_disconnect(SignalSlotConnector *self, Signal signal, Slot slot, gpointer object); void signal_slot_emit(SignalSlotConnector *self, Signal signal, gpointer user_data); SignalSlotConnector *signal_slot_connector_new(void); void signal_slot_connector_free(SignalSlotConnector *self); #endif syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/tests/000077500000000000000000000000001450431004300235075ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/tests/CMakeLists.txt000066400000000000000000000000621450431004300262450ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_signal_slots) syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/tests/Makefile.am000066400000000000000000000004661450431004300255510ustar00rootroot00000000000000lib_signal_slot_connector_tests_TESTS = \ lib/signal-slot-connector/tests/test_signal_slots check_PROGRAMS += \ ${lib_signal_slot_connector_tests_TESTS} lib_signal_slot_connector_tests_test_signal_slots_LDADD = $(TEST_LDADD) lib_signal_slot_connector_tests_test_signal_slots_CFLAGS = $(TEST_CFLAGS) syslog-ng-syslog-ng-4.4.0/lib/signal-slot-connector/tests/test_signal_slots.c000066400000000000000000000205661450431004300274240ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "signal-slot-connector/signal-slot-connector.h" #define signal_test1 SIGNAL(test, 1, TestData *) #define signal_test2 SIGNAL(test, 2, TestData *) typedef struct _TestData TestData; struct _TestData { gint slot_ctr; }; typedef struct _SlotObj SlotObj; struct _SlotObj { gint ctr; }; void test_data_init(TestData *data) { data->slot_ctr = 0; } void slot_obj_init(SlotObj *obj) { obj->ctr = 0; } void test1_slot(gpointer obj, TestData *user_data) { if (obj) { SlotObj *slot_obj = (SlotObj *)obj; slot_obj->ctr++; } user_data->slot_ctr++; } void test2_slot(gpointer obj, TestData *user_data) { if (obj) { SlotObj *slot_obj = (SlotObj *)obj; slot_obj->ctr++; } user_data->slot_ctr++; } Test(basic_signal_slots, when_the_signal_is_emitted_then_the_connected_slot_is_executed) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); SlotObj slot_obj1, slot_obj2; slot_obj_init(&slot_obj1); slot_obj_init(&slot_obj2); CONNECT(ssc, signal_test1, test1_slot, &slot_obj1); CONNECT(ssc, signal_test2, test1_slot, &slot_obj2); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 1); cr_expect_eq(slot_obj1.ctr, 1); cr_expect_eq(slot_obj2.ctr, 0); EMIT(ssc, signal_test2, &test_data); cr_expect_eq(test_data.slot_ctr, 2); cr_expect_eq(slot_obj1.ctr, 1); cr_expect_eq(slot_obj2.ctr, 1); signal_slot_connector_free(ssc); } Test(basic_signal_slots, when_trying_to_connect_multiple_times_the_same_connection_then_connect_only_the_first) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); SlotObj slot_obj; slot_obj_init(&slot_obj); for (gint i = 0; i < 5; i++) CONNECT(ssc, signal_test1, test1_slot, &slot_obj); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 1); cr_expect_eq(slot_obj.ctr, 1); signal_slot_connector_free(ssc); } Test(basic_signal_slots, when_trying_to_disconnect_multiple_times_the_same_connection_disconnect_only_the_first) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); CONNECT(ssc, signal_test1, test1_slot, NULL); CONNECT(ssc, signal_test1, test2_slot, NULL); for (gint i = 0; i < 5; i++) DISCONNECT(ssc, signal_test1, test1_slot, NULL); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 1); signal_slot_connector_free(ssc); } Test(basic_signal_slots, when_slot_is_disconnected_from_a_signal_and_the_signal_is_emitted_then_the_slot_should_not_be_executed) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); SlotObj slot_obj; slot_obj_init(&slot_obj); CONNECT(ssc, signal_test1, test1_slot, &slot_obj); CONNECT(ssc, signal_test2, test1_slot, &slot_obj); DISCONNECT(ssc, signal_test1, test1_slot, &slot_obj); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 0); cr_expect_eq(slot_obj.ctr, 0); EMIT(ssc, signal_test2, &test_data); cr_expect_eq(test_data.slot_ctr, 1); cr_expect_eq(slot_obj.ctr, 1); DISCONNECT(ssc, signal_test2, test1_slot, &slot_obj); EMIT(ssc, signal_test2, &test_data); cr_expect_eq(test_data.slot_ctr, 1); cr_expect_eq(slot_obj.ctr, 1); signal_slot_connector_free(ssc); } Test(basic_signal_slots, when_disconnect_the_connected_slot_from_a_signal_then_the_signal_is_unregistered) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); SlotObj slot_obj; slot_obj_init(&slot_obj); CONNECT(ssc, signal_test1, test1_slot, &slot_obj); DISCONNECT(ssc, signal_test1, test1_slot, &slot_obj); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 0); cr_expect_eq(slot_obj.ctr, 0); signal_slot_connector_free(ssc); } Test(basic_signal_slots, when_trying_to_disconnect_a_connected_slot_with_different_slot_object_then_slot_is_not_disconnected) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); SlotObj slot_obj; slot_obj_init(&slot_obj); SlotObj slot_obj_another; slot_obj_init(&slot_obj_another); CONNECT(ssc, signal_test1, test1_slot, &slot_obj); DISCONNECT(ssc, signal_test1, test1_slot, &slot_obj_another); EMIT(ssc, signal_test1, &test_data); cr_expect_eq(test_data.slot_ctr, 1); cr_expect_eq(slot_obj.ctr, 1); cr_expect_eq(slot_obj_another.ctr, 0); signal_slot_connector_free(ssc); } #define DEFINE_TEST_SLOT(func_name) \ void func_name(gpointer obj, TestData *user_data) \ { \ if (obj) \ { \ SlotObj *slot_obj = (SlotObj *)obj; \ slot_obj->ctr++; \ } \ user_data->slot_ctr++; \ } DEFINE_TEST_SLOT(test_slot_0) DEFINE_TEST_SLOT(test_slot_1) DEFINE_TEST_SLOT(test_slot_2) DEFINE_TEST_SLOT(test_slot_3) #define test_signal_0 SIGNAL(test, func_0, TestData *) #define test_signal_1 SIGNAL(test, func_1, TestData *) #define test_signal_2 SIGNAL(test, func_2, TestData *) #define test_signal_3 SIGNAL(test, func_3, TestData *) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) Signal signals[4] = { test_signal_0 }; Slot slots[4] = { (Slot) test_slot_0, (Slot) test_slot_1, (Slot) test_slot_2, (Slot) test_slot_3 }; SlotObj slot_objects[4]; void _connect_a_signal_with_all_test_slots(SignalSlotConnector *ssc, Signal s) { for (gint i = 0; i < ARRAY_SIZE(slots); i++) CONNECT(ssc, s, slots[i], &slot_objects[i]); } void _disconnect_all_test_slots_from_a_signal(SignalSlotConnector *ssc, Signal s) { for (gint i = 0; i < ARRAY_SIZE(slots); i++) DISCONNECT(ssc, s, slots[i], &slot_objects[i]); } Test(multiple_signals_slots, given_one_signal_with_multiple_slots_when_the_signal_is_emitted_then_the_slots_are_executed) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); _connect_a_signal_with_all_test_slots(ssc, signals[0]); EMIT(ssc, signals[0], &test_data); cr_expect_eq(test_data.slot_ctr, ARRAY_SIZE(slots)); for (gsize i = 0; i < ARRAY_SIZE(slot_objects); i++) cr_expect_eq(slot_objects[i].ctr, 1); _disconnect_all_test_slots_from_a_signal(ssc, signals[0]); signal_slot_connector_free(ssc); } Test(multiple_signals_slots, given_a_signal_with_multiple_slots_when_slots_are_disconnected_1_by_1_then_remaining_slots_are_still_executed) { SignalSlotConnector *ssc = signal_slot_connector_new(); TestData test_data; test_data_init(&test_data); for (gint i = 0; i < 3; i++) CONNECT(ssc, signals[0], slots[i], &slot_objects[i]); DISCONNECT(ssc, signals[0], slots[0], &slot_objects[0]); EMIT(ssc, signals[0], &test_data); cr_expect_eq(test_data.slot_ctr, 2); cr_expect_eq(slot_objects[0].ctr, 0); cr_expect_eq(slot_objects[1].ctr, 1); cr_expect_eq(slot_objects[2].ctr, 1); DISCONNECT(ssc, signals[0], slots[1], &slot_objects[1]); EMIT(ssc, signals[0], &test_data); cr_expect_eq(test_data.slot_ctr, 3); cr_expect_eq(slot_objects[0].ctr, 0); cr_expect_eq(slot_objects[1].ctr, 1); cr_expect_eq(slot_objects[2].ctr, 2); DISCONNECT(ssc, signals[0], slots[2], &slot_objects[2]); EMIT(ssc, signals[0], &test_data); cr_expect_eq(test_data.slot_ctr, 3); cr_expect_eq(slot_objects[0].ctr, 0); cr_expect_eq(slot_objects[1].ctr, 1); cr_expect_eq(slot_objects[2].ctr, 2); signal_slot_connector_free(ssc); } syslog-ng-syslog-ng-4.4.0/lib/stats/000077500000000000000000000000001450431004300172575ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/stats/CMakeLists.txt000066400000000000000000000016201450431004300220160ustar00rootroot00000000000000add_subdirectory(aggregator) set(STATS_HEADERS stats/stats.h stats/stats-compat.h stats/stats-control.h stats/stats-counter.h stats/stats-cluster.h stats/stats-csv.h stats/stats-log.h stats/stats-prometheus.h stats/stats-registry.h stats/stats-query.h stats/stats-query-commands.h stats/stats-cluster-logpipe.h stats/stats-cluster-single.h stats/stats-cluster-key-builder.h ${STATS_AGGREGATOR_HEADERS} PARENT_SCOPE) set(STATS_SOURCES stats/stats.c stats/stats-control.c stats/stats-cluster.c stats/stats-csv.c stats/stats-log.c stats/stats-prometheus.c stats/stats-registry.c stats/stats-query.c stats/stats-query-commands.c stats/stats-cluster-logpipe.c stats/stats-cluster-single.c stats/stats-cluster-key-builder.c ${STATS_AGGREGATOR_SOURCES} PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/stats/Makefile.am000066400000000000000000000020311450431004300213070ustar00rootroot00000000000000statsincludedir = ${pkgincludedir}/stats EXTRA_DIST += lib/stats/CMakeLists.txt include lib/stats/aggregator/Makefile.am statsinclude_HEADERS = \ lib/stats/stats.h \ lib/stats/stats-compat.h \ lib/stats/stats-control.h \ lib/stats/stats-counter.h \ lib/stats/stats-cluster.h \ lib/stats/stats-csv.h \ lib/stats/stats-log.h \ lib/stats/stats-prometheus.h \ lib/stats/stats-registry.h \ lib/stats/stats-query.h \ lib/stats/stats-query-commands.h \ lib/stats/stats-cluster-logpipe.h \ lib/stats/stats-cluster-single.h \ lib/stats/stats-cluster-key-builder.h stats_sources = \ lib/stats/stats.c \ lib/stats/stats-control.c \ lib/stats/stats-cluster.c \ lib/stats/stats-csv.c \ lib/stats/stats-log.c \ lib/stats/stats-prometheus.c \ lib/stats/stats-registry.c \ lib/stats/stats-query.c \ lib/stats/stats-query-commands.c \ lib/stats/stats-cluster-logpipe.c \ lib/stats/stats-cluster-single.c \ lib/stats/stats-cluster-key-builder.c \ $(statsaggregator_sources) include lib/stats/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/000077500000000000000000000000001450431004300214015ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/CMakeLists.txt000066400000000000000000000006121450431004300241400ustar00rootroot00000000000000set(STATS_AGGREGATOR_HEADERS stats/aggregator/stats-aggregator.h stats/aggregator/stats-aggregator-registry.h PARENT_SCOPE) set(STATS_AGGREGATOR_SOURCES stats/aggregator/stats-aggregator.c stats/aggregator/stats-average.c stats/aggregator/stats-maximum.c stats/aggregator/stats-change-per-second.c stats/aggregator/stats-aggregator-registry.c PARENT_SCOPE) syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/Makefile.am000066400000000000000000000007641450431004300234440ustar00rootroot00000000000000statsaggregatorincludedir = ${pkgincludedir}/stats/aggregator EXTRA_DIST += lib/stats/aggregator/CMakeLists.txt statsaggregatorinclude_HEADERS = \ lib/stats/aggregator/stats-aggregator.h \ lib/stats/aggregator/stats-aggregator-registry.h statsaggregator_sources = \ lib/stats/aggregator/stats-aggregator.c \ lib/stats/aggregator/stats-average.c \ lib/stats/aggregator/stats-maximum.c \ lib/stats/aggregator/stats-change-per-second.c \ lib/stats/aggregator/stats-aggregator-registry.c syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-aggregator-registry.c000066400000000000000000000131201450431004300266660ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/aggregator/stats-aggregator-registry.h" #include "stats/stats-registry.h" #include "stats/stats-cluster.h" #include "stats/stats-query.h" #include "cfg.h" #include "iv.h" #include "timeutils/cache.h" #include "mainloop.h" #include "messages.h" #define FREQUENCY_OF_UPDATE 60 typedef struct { GHashTable *aggregators; } StatsAggregatorContainer; static StatsAggregatorContainer stats_container; static GMutex stats_aggregator_mutex; static gboolean stats_aggregator_locked; void stats_aggregator_lock(void) { g_mutex_lock(&stats_aggregator_mutex); stats_aggregator_locked = TRUE; } void stats_aggregator_unlock(void) { stats_aggregator_locked = FALSE; g_mutex_unlock(&stats_aggregator_mutex); } /* time based aggregation */ /* handle orphaned of aggregators */ static gboolean _remove_orphaned_helper(gpointer _key, gpointer _value, gpointer _user_data) { StatsAggregator *aggr = (StatsAggregator *) _value; if (stats_aggregator_is_orphaned(aggr)) { stats_aggregator_free(aggr); return TRUE; } return FALSE; } void stats_aggregator_remove_orphaned_stats(void) { g_assert(stats_aggregator_locked); g_hash_table_foreach_remove(stats_container.aggregators, _remove_orphaned_helper, NULL); } /* reset aggregators, i.e. syslog-ng-ctl stats --reset */ static void _reset_func (gpointer _key, gpointer _value, gpointer _user_data) { StatsAggregator *aggr = (StatsAggregator *) _value; stats_aggregator_reset(aggr); } void stats_aggregator_registry_reset(void) { g_assert(stats_aggregator_locked); main_loop_assert_main_thread(); g_hash_table_foreach(stats_container.aggregators, _reset_func, NULL); } /* aggregator cleanup */ static gboolean _cleanup_aggregator(gpointer _key, gpointer _value, gpointer _user_data) { StatsAggregator *aggr = (StatsAggregator *) _value; if (!stats_aggregator_is_orphaned(aggr)) stats_aggregator_unregister(aggr); stats_aggregator_free(aggr); return TRUE; } static void stats_aggregator_cleanup(void) { g_assert(stats_aggregator_locked); g_hash_table_foreach_remove(stats_container.aggregators, _cleanup_aggregator, NULL); } /* module init/deinit */ void stats_aggregator_registry_init(void) { g_mutex_init(&stats_aggregator_mutex); stats_container.aggregators = g_hash_table_new_full((GHashFunc) stats_cluster_key_hash, (GEqualFunc) stats_cluster_key_equal, NULL, NULL); } void stats_aggregator_registry_deinit(void) { stats_aggregator_lock(); stats_aggregator_cleanup(); stats_aggregator_unlock(); g_hash_table_destroy(stats_container.aggregators); stats_container.aggregators = NULL; g_mutex_clear(&stats_aggregator_mutex); } /* type specific registration helpers */ static void _insert_to_table(StatsAggregator *aggr) { g_hash_table_insert(stats_container.aggregators, &aggr->key, aggr); } static gboolean _is_in_table(StatsClusterKey *sc_key) { return g_hash_table_lookup(stats_container.aggregators, sc_key) != NULL; } static StatsAggregator * _get_from_table(StatsClusterKey *sc_key) { return g_hash_table_lookup(stats_container.aggregators, sc_key); } void stats_register_aggregator_maximum(gint level, StatsClusterKey *sc_key, StatsAggregator **aggr) { g_assert(stats_aggregator_locked); if (!stats_check_level(level)) { *aggr = NULL; return; } if (!_is_in_table(sc_key)) { *aggr = stats_aggregator_maximum_new(level, sc_key); _insert_to_table(*aggr); } else { *aggr = _get_from_table(sc_key); } stats_aggregator_start(*aggr); } void stats_register_aggregator_average(gint level, StatsClusterKey *sc_key, StatsAggregator **aggr) { g_assert(stats_aggregator_locked); if (!stats_check_level(level)) { *aggr = NULL; return; } if (!_is_in_table(sc_key)) { *aggr = stats_aggregator_average_new(level, sc_key); _insert_to_table(*aggr); } else { *aggr = _get_from_table(sc_key); } stats_aggregator_start(*aggr); } void stats_register_aggregator_cps(gint level, StatsClusterKey *sc_key, StatsClusterKey *sc_key_input, gint stats_type, StatsAggregator **aggr) { g_assert(stats_aggregator_locked); if (!stats_check_level(level)) { *aggr = NULL; return; } if (!_is_in_table(sc_key)) { *aggr = stats_aggregator_cps_new(level, sc_key, sc_key_input, stats_type); _insert_to_table(*aggr); } else { *aggr = _get_from_table(sc_key); } stats_aggregator_start(*aggr); } void stats_unregister_aggregator(StatsAggregator **aggr) { g_assert(stats_aggregator_locked); stats_aggregator_stop(*aggr); *aggr = NULL; } syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-aggregator-registry.h000066400000000000000000000035621450431004300267040ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_AGGREGATOR_REGISTRY_H #define STATS_AGGREGATOR_REGISTRY_H #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-registry.h" #include "syslog-ng.h" void stats_aggregator_registry_reset(void); void stats_aggregator_remove_orphaned_stats(void); void stats_aggregator_lock(void); void stats_aggregator_unlock(void); void stats_aggregator_registry_init(void); void stats_aggregator_registry_deinit(void); /* type specific helpers */ void stats_register_aggregator_maximum(gint level, StatsClusterKey *sc_key, StatsAggregator **aggr); void stats_register_aggregator_average(gint level, StatsClusterKey *sc_key, StatsAggregator **aggr); void stats_register_aggregator_cps(gint level, StatsClusterKey *sc_key, StatsClusterKey *sc_key_input, gint stats_type, StatsAggregator **aggr); void stats_unregister_aggregator(StatsAggregator **aggr); #endif /* STATS_AGGREGATOR_REGISTRY_H */ syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-aggregator.c000066400000000000000000000112421450431004300250230ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "mainloop.h" static void _restart_timer(StatsAggregator *self) { main_loop_assert_main_thread(); if (self->timer_period < 0) return; /* NOTE: our timer may still be registered if _restart_timer() is called * after _reset(): in this case stats_aggregator_start() will find an * orphaned counter whose timer is still running as the 0 value is caused * by reset and not by reaching zero due to aggregate. * * I hate the orphaned lifecycle model implemented in aggregators: we are * keeping counters active if they are non-zero (see the _is_orphaned() * method below). I understand it is nicer that the counter is listed as * active, but the hoops we needed to jump just for this is insane. We * should have just kept updating those counters even if the related * connection is not active at the moment, who would have cared? */ if (iv_timer_registered(&self->update_timer)) return; iv_validate_now(); self->update_timer.expires = iv_now; self->update_timer.expires.tv_sec += self->timer_period; iv_timer_register(&self->update_timer); } static void _stop_timer(StatsAggregator *self) { main_loop_assert_main_thread(); if (iv_timer_registered(&self->update_timer)) iv_timer_unregister(&self->update_timer); } static void _timer_callback(void *cookie) { StatsAggregator *self = (StatsAggregator *) cookie; if (!stats_aggregator_is_orphaned(self)) stats_aggregator_aggregate(self); /* we might become orphaned only after the aggregated value reaches 0 */ if (stats_aggregator_is_orphaned(self)) stats_aggregator_unregister(self); else _restart_timer(self); } void stats_aggregator_register(StatsAggregator *self) { if (self->register_aggr) self->register_aggr(self); _restart_timer(self); } void stats_aggregator_unregister(StatsAggregator *self) { if (self->unregister_aggr) self->unregister_aggr(self); _stop_timer(self); } /* start/stop aggregation */ void stats_aggregator_start(StatsAggregator *self) { main_loop_assert_main_thread(); if (!self) return; if (stats_aggregator_is_orphaned(self)) stats_aggregator_register(self); ++self->use_count; } void stats_aggregator_stop(StatsAggregator *self) { main_loop_assert_main_thread(); if (!self) return; if (self->use_count > 0) --self->use_count; if (self->use_count == 0) stats_aggregator_aggregate(self); if (stats_aggregator_is_orphaned(self)) stats_aggregator_unregister(self); } static gboolean _is_orphaned(StatsAggregator *self) { return self->use_count == 0; } static void _register(StatsAggregator *self) { stats_lock(); stats_register_counter(self->stats_level, &self->key, SC_TYPE_SINGLE_VALUE, &self->output_counter); stats_unlock(); } static void _unregister(StatsAggregator *self) { stats_lock(); stats_unregister_counter(&self->key, SC_TYPE_SINGLE_VALUE, &self->output_counter); stats_unlock(); } static void _set_virtual_functions(StatsAggregator *self) { self->is_orphaned = _is_orphaned; self->register_aggr = _register; self->unregister_aggr = _unregister; } void stats_aggregator_init_instance(StatsAggregator *self, StatsClusterKey *sc_key, gint stats_level) { self->use_count = 0; self->stats_level = stats_level; stats_cluster_key_clone(&self->key, sc_key); _set_virtual_functions(self); IV_TIMER_INIT(&self->update_timer); self->update_timer.cookie = self; self->update_timer.handler = _timer_callback; self->timer_period = -1; } void stats_aggregator_free(StatsAggregator *self) { stats_cluster_key_cloned_free(&self->key); if (self && self->free_fn) self->free_fn(self); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-aggregator.h000066400000000000000000000062601450431004300250340ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_AGGREGATOR_H #define STATS_AGGREGATOR_H #include "stats/stats-counter.h" #include "stats/stats-cluster.h" #include typedef struct _StatsAggregator StatsAggregator; struct _StatsAggregator { void (*add_data_point)(StatsAggregator *self, gsize value); void (*aggregate)(StatsAggregator *self); void (*reset)(StatsAggregator *self); void (*free_fn)(StatsAggregator *self); gboolean (*is_orphaned)(StatsAggregator *self); void (*register_aggr)(StatsAggregator *self); void (*unregister_aggr)(StatsAggregator *self); gssize use_count; StatsClusterKey key; StatsCounterItem *output_counter; gint stats_level; gint timer_period; struct iv_timer update_timer; }; static inline void stats_aggregator_add_data_point(StatsAggregator *self, gsize value) { if (self && self->add_data_point) self->add_data_point(self, value); } static inline void stats_aggregator_aggregate(StatsAggregator *self) { if (self && self->aggregate) self->aggregate(self); } static inline void stats_aggregator_reset(StatsAggregator *self) { if (self && self->reset) self->reset(self); } static inline gboolean stats_aggregator_is_orphaned(StatsAggregator *self) { if (self && self->is_orphaned) return self->is_orphaned(self); return TRUE; } void stats_aggregator_register(StatsAggregator *self); void stats_aggregator_unregister(StatsAggregator *self); /* public */ void stats_aggregator_add_data_point(StatsAggregator *self, gsize value); void stats_aggregator_aggregate(StatsAggregator *self); void stats_aggregator_reset(StatsAggregator *self); /* stats-internals */ void stats_aggregator_start(StatsAggregator *self); void stats_aggregator_stop(StatsAggregator *self); void stats_aggregator_init_instance(StatsAggregator *self, StatsClusterKey *sc_key, gint stats_level); void stats_aggregator_free(StatsAggregator *self); /* type specific constructors */ StatsAggregator *stats_aggregator_maximum_new(gint level, StatsClusterKey *sc_key); StatsAggregator *stats_aggregator_average_new(gint level, StatsClusterKey *sc_key); StatsAggregator *stats_aggregator_cps_new(gint level, StatsClusterKey *sc_key, StatsClusterKey *sc_key_input, gint stats_type); #endif /* STATS_AGGREGATOR_H */ syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-average.c000066400000000000000000000052531450431004300243200ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" typedef struct { StatsAggregator super; atomic_gssize count; atomic_gssize sum; } StatsAggregatorAverage; static inline void _inc_count(StatsAggregatorAverage *self) { atomic_gssize_inc(&self->count); } static inline void _add_sum(StatsAggregatorAverage *self, gsize value) { atomic_gssize_add(&self->sum, value); } static inline gsize _get_sum(StatsAggregatorAverage *self) { return atomic_gssize_get_unsigned(&self->sum); } static inline gsize _get_count(StatsAggregatorAverage *self) { return atomic_gssize_get_unsigned(&self->count); } static void _add_data_point(StatsAggregator *s, gsize value) { StatsAggregatorAverage *self = (StatsAggregatorAverage *)s; /* * this function isn't truely atomic, reset might set count to zero * and we want to avoid zero division */ gsize sum = _get_sum(self) + value; gsize divisor = _get_count(self) + 1; stats_counter_set(self->super.output_counter, sum/divisor); _add_sum(self, value); _inc_count(self); } static void _reset(StatsAggregator *s) { StatsAggregatorAverage *self = (StatsAggregatorAverage *)s; atomic_gssize_set(&self->count, 0); atomic_gssize_set(&self->sum, 0); stats_counter_set(self->super.output_counter, 0); } static void _set_virtual_function(StatsAggregatorAverage *self ) { self->super.add_data_point = _add_data_point; self->super.reset = _reset; } StatsAggregator * stats_aggregator_average_new(gint level, StatsClusterKey *sc_key) { StatsAggregatorAverage *self = g_new0(StatsAggregatorAverage, 1); stats_aggregator_init_instance(&self->super, sc_key, level); _set_virtual_function(self); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-change-per-second.c000066400000000000000000000231651450431004300261720ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/aggregator/stats-aggregator.h" #include "timeutils/cache.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "timeutils/cache.h" #include "stats/stats-cluster.h" #include #include "messages.h" #define HOUR_IN_SEC 3600 /* 60*60 */ #define DAY_IN_SEC 86400 /* 60*60*24 */ typedef struct { StatsCounterItem *output_counter; gsize average; gsize sum; gsize last_count; gssize duration; /* if the duration equals -1, thats mean, it count since syslog start */ gchar *name; } CPSLogic; /* CPS == Change Per Second */ typedef struct { StatsAggregator super; time_t init_time; time_t last_add_time; gboolean registered; StatsCluster *sc_input; gint stats_type_input; StatsCounterItem *input_counter; CPSLogic hour; CPSLogic day; CPSLogic start; } StatsAggregatorCPS; static void _reset_CPS_logic_values(CPSLogic *self) { /* Both aggregate() and reset() is running in the main thread */ self->average = 0; self->sum = 0; self->last_count = 0; stats_counter_set(self->output_counter, 0); } static void _track_input_counter(StatsAggregatorCPS *self) { StatsCounterItem *input_counter = stats_cluster_get_counter(self->sc_input, self->stats_type_input); self->input_counter = input_counter; g_assert(self->input_counter != NULL); stats_cluster_track_counter(self->sc_input, self->stats_type_input); } static void _untrack_input_counter(StatsAggregatorCPS *self) { stats_cluster_untrack_counter(self->sc_input, self->stats_type_input, &self->input_counter); self->input_counter = NULL; } static void _register_CPS(CPSLogic *self, StatsClusterKey *sc_key, gint level, gint type) { if(!self->output_counter) stats_register_counter(level, sc_key, type, &self->output_counter); } static void _register_CPSs(StatsAggregatorCPS *self) { stats_lock(); StatsClusterKey sc_key; self->hour.name = g_strconcat(self->super.key.counter_group_init.counter.name, "_last_1h", NULL); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->hour.name); _register_CPS(&self->hour, &sc_key, self->super.stats_level, SC_TYPE_SINGLE_VALUE); self->day.name = g_strconcat(self->super.key.counter_group_init.counter.name, "_last_24h", NULL); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->day.name); _register_CPS(&self->day, &sc_key, self->super.stats_level, SC_TYPE_SINGLE_VALUE); self->start.name = g_strconcat(self->super.key.counter_group_init.counter.name, "_since_start", NULL); stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->start.name); _register_CPS(&self->start, &sc_key, self->super.stats_level, SC_TYPE_SINGLE_VALUE); stats_unlock(); } static void _register(StatsAggregator *s) { StatsAggregatorCPS *self = (StatsAggregatorCPS *)s; if (self->registered) return; _register_CPSs(self); _track_input_counter(self); self->registered = TRUE; } static void _unregister_CPS(CPSLogic *self, StatsClusterKey *sc_key, gint type) { stats_unregister_counter(sc_key, type, &self->output_counter); self->output_counter = NULL; } static void _unregister_CPSs(StatsAggregatorCPS *self) { stats_lock(); StatsClusterKey sc_key; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->hour.name); _unregister_CPS(&self->hour, &sc_key, SC_TYPE_SINGLE_VALUE); g_free(self->hour.name); self->hour.name = NULL; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->day.name); _unregister_CPS(&self->day, &sc_key, SC_TYPE_SINGLE_VALUE); g_free(self->day.name); self->day.name = NULL; stats_cluster_single_key_legacy_set_with_name(&sc_key, self->super.key.legacy.component, self->super.key.legacy.id, self->super.key.legacy.instance, self->start.name); _unregister_CPS(&self->start, &sc_key, SC_TYPE_SINGLE_VALUE); g_free(self->start.name); self->start.name = NULL; stats_unlock(); } static void _unregister(StatsAggregator *s) { StatsAggregatorCPS *self = (StatsAggregatorCPS *)s; /* unregister() needs to be idempotent, so we can unregister it only after it reaches 0 CPS */ if (!self->registered) return; _unregister_CPSs(self); _untrack_input_counter(self); self->registered = FALSE; } static inline time_t _calc_sec_between_time(time_t *start, time_t *end) { gdouble diff = difftime(*end, *start); return (time_t)diff; } static gboolean _is_less_then_duration(StatsAggregatorCPS *self, CPSLogic *logic, time_t *now) { if (logic->duration == -1) return TRUE; return _calc_sec_between_time(&self->init_time, now) <= logic->duration; } static void _calc_sum(StatsAggregatorCPS *self, CPSLogic *logic, time_t *now) { gsize count = stats_counter_get(self->input_counter); gsize diff = count - logic->last_count; logic->last_count = count; if (!_is_less_then_duration(self, logic, now)) { diff -= logic->average * _calc_sec_between_time(&self->last_add_time, now); } logic->sum += diff; self->last_add_time = *now; } static void _calc_average(StatsAggregatorCPS *self, CPSLogic *logic, time_t *now) { time_t elapsed_time; gsize divisor; elapsed_time = _calc_sec_between_time(&self->init_time, now); divisor = (_is_less_then_duration(self, logic, now)) ? elapsed_time : logic->duration; if (divisor <= 0) divisor = 1; gsize sum = logic->sum; logic->average = (sum / divisor); msg_trace("stats-aggregator-cps", evt_tag_printf("name", "%s_%s", self->super.key.legacy.id, logic->name), evt_tag_long("sum", sum), evt_tag_long("divisor", divisor), evt_tag_long("cps", (sum/divisor)), evt_tag_long("delta_time_since_start", elapsed_time)); } static void _aggregate_CPS_logic(StatsAggregatorCPS *self, CPSLogic *logic, time_t *now) { _calc_sum(self, logic, now); _calc_average(self, logic, now); stats_counter_set(logic->output_counter, logic->average); } static void _aggregate(StatsAggregator *s) { StatsAggregatorCPS *self = (StatsAggregatorCPS *)s; time_t now = cached_g_current_time_sec(); _aggregate_CPS_logic(self, &self->hour, &now); _aggregate_CPS_logic(self, &self->day, &now); _aggregate_CPS_logic(self, &self->start, &now); } static void _reset_time(StatsAggregatorCPS *self) { self->init_time = cached_g_current_time_sec(); self->last_add_time = 0; } static void _reset(StatsAggregator *s) { StatsAggregatorCPS *self = (StatsAggregatorCPS *)s; _reset_time(self); _reset_CPS_logic_values(&self->hour); _reset_CPS_logic_values(&self->day); _reset_CPS_logic_values(&self->start); } static gboolean _is_orphaned_CPSLogic(CPSLogic *self) { return stats_counter_get(self->output_counter) == 0; } static gboolean _is_orphaned(StatsAggregator *s) { StatsAggregatorCPS *self = (StatsAggregatorCPS *)s; return s->use_count == 0 && _is_orphaned_CPSLogic(&self->day) && _is_orphaned_CPSLogic(&self->hour) && _is_orphaned_CPSLogic(&self->start); } static void _set_virtual_function(StatsAggregatorCPS *self ) { self->super.aggregate = _aggregate; self->super.reset = _reset; self->super.is_orphaned = _is_orphaned; self->super.register_aggr = _register; self->super.unregister_aggr = _unregister; } StatsAggregator * stats_aggregator_cps_new(gint level, StatsClusterKey *sc_key, StatsClusterKey *sc_key_input, gint stats_type) { StatsAggregatorCPS *self = g_new0(StatsAggregatorCPS, 1); stats_aggregator_init_instance(&self->super, sc_key, level); _set_virtual_function(self); stats_lock(); self->sc_input = stats_get_cluster(sc_key_input); g_assert(self->sc_input != NULL); stats_unlock(); self->stats_type_input = stats_type; _reset_time(self); self->hour.duration = HOUR_IN_SEC; self->day.duration = DAY_IN_SEC; self->start.duration = -1; self->super.timer_period = 60; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/stats/aggregator/stats-maximum.c000066400000000000000000000036131450431004300243610ustar00rootroot00000000000000/* * Copyright (c) 2021 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/aggregator/stats-aggregator.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" typedef struct { StatsAggregator super; } StatsAggregatorMaximum; static void _add_data_point(StatsAggregator *s, gsize value) { StatsAggregatorMaximum *self = (StatsAggregatorMaximum *)s; gsize current_max = 0; do { current_max = stats_counter_get(self->super.output_counter); if (current_max >= value) break; } while(!atomic_gssize_compare_and_exchange(&self->super.output_counter->value, current_max, value)); } static void _set_virtual_function(StatsAggregatorMaximum *self) { self->super.add_data_point = _add_data_point; } StatsAggregator * stats_aggregator_maximum_new(gint level, StatsClusterKey *sc_key) { StatsAggregatorMaximum *self = g_new0(StatsAggregatorMaximum, 1); stats_aggregator_init_instance(&self->super, sc_key, level); _set_virtual_function(self); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-key-builder.c000066400000000000000000000353361450431004300244640ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-cluster-key-builder.h" #include "stats/stats-cluster-single.h" #include "stats/stats-cluster-logpipe.h" #include #include #define LEGACY_COMPONENT_UNSET (G_MAXUINT16) typedef struct _BuilderOptions { gchar *name; gchar *name_prefix; gchar *name_suffix; GArray *labels; GArray *legacy_labels; StatsClusterUnit unit; StatsClusterFrameOfReference frame_of_reference; struct { guint16 component; gchar *id; gchar *instance; gchar *name; } legacy; } BuilderOptions; struct _StatsClusterKeyBuilder { GList *options_stack; }; static void _label_free(StatsClusterLabel *label) { g_free((gchar *) label->name); g_free((gchar *) label->value); } static BuilderOptions * _options_new(void) { BuilderOptions *self = g_new0(BuilderOptions, 1); self->labels = g_array_sized_new(FALSE, FALSE, sizeof(StatsClusterLabel), 4); g_array_set_clear_func(self->labels, (GDestroyNotify) _label_free); self->legacy.component = LEGACY_COMPONENT_UNSET; return self; } static void _options_free(BuilderOptions *self) { g_free(self->name); g_free(self->name_prefix); g_free(self->name_suffix); g_free(self->legacy.id); g_free(self->legacy.instance); g_free(self->legacy.name); g_array_free(self->labels, TRUE); if (self->legacy_labels) g_array_free(self->legacy_labels, TRUE); g_free(self); } StatsClusterKeyBuilder * stats_cluster_key_builder_new(void) { StatsClusterKeyBuilder *self = g_new0(StatsClusterKeyBuilder, 1); stats_cluster_key_builder_push(self); return self; } void stats_cluster_key_builder_push(StatsClusterKeyBuilder *self) { self->options_stack = g_list_append(self->options_stack, _options_new()); } void stats_cluster_key_builder_pop(StatsClusterKeyBuilder *self) { GList *last_link = g_list_last(self->options_stack); BuilderOptions *options = (BuilderOptions *) last_link->data; self->options_stack = g_list_delete_link(self->options_stack, last_link); _options_free(options); } void stats_cluster_key_builder_free(StatsClusterKeyBuilder *self) { g_list_free_full(self->options_stack, (GDestroyNotify) _options_free); g_free(self); } static BuilderOptions * _get_last_options(StatsClusterKeyBuilder *self) { return (BuilderOptions *) g_list_last(self->options_stack)->data; } void stats_cluster_key_builder_set_name(StatsClusterKeyBuilder *self, const gchar *name) { BuilderOptions *options = _get_last_options(self); g_free(options->name); options->name = g_strdup(name); } void stats_cluster_key_builder_set_name_prefix(StatsClusterKeyBuilder *self, const gchar *name_prefix) { BuilderOptions *options = _get_last_options(self); g_free(options->name_prefix); options->name_prefix = g_strdup(name_prefix); } void stats_cluster_key_builder_set_name_suffix(StatsClusterKeyBuilder *self, const gchar *name_suffix) { BuilderOptions *options = _get_last_options(self); g_free(options->name_suffix); options->name_suffix = g_strdup(name_suffix); } void stats_cluster_key_builder_add_label(StatsClusterKeyBuilder *self, const StatsClusterLabel label) { BuilderOptions *options = _get_last_options(self); StatsClusterLabel own_label = stats_cluster_label(g_strdup(label.name), g_strdup(label.value)); options->labels = g_array_append_vals(options->labels, &own_label, 1); } void stats_cluster_key_builder_set_unit(StatsClusterKeyBuilder *self, StatsClusterUnit unit) { BuilderOptions *options = _get_last_options(self); options->unit = unit; } void stats_cluster_key_builder_set_frame_of_reference(StatsClusterKeyBuilder *self, StatsClusterFrameOfReference frame_of_reference) { BuilderOptions *options = _get_last_options(self); options->frame_of_reference = frame_of_reference; } void stats_cluster_key_builder_set_legacy_alias(StatsClusterKeyBuilder *self, guint16 component, const gchar *id, const gchar *instance) { BuilderOptions *options = _get_last_options(self); options->legacy.component = component; g_free(options->legacy.id); options->legacy.id = g_strdup(id); g_free(options->legacy.instance); options->legacy.instance = g_strdup(instance); } void stats_cluster_key_builder_set_legacy_alias_name(StatsClusterKeyBuilder *self, const gchar *name) { BuilderOptions *options = _get_last_options(self); g_free(options->legacy.name); options->legacy.name = g_strdup(name); } static gint _labels_sort(const StatsClusterLabel *a, const StatsClusterLabel *b) { return strcmp(a->name, b->name); } static gchar * _format_name(const StatsClusterKeyBuilder *self) { const gchar *name_prefix = NULL; const gchar *name = NULL; const gchar *name_suffix = NULL; for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (!name_prefix && options->name_prefix) name_prefix = options->name_prefix; if (!name && options->name) name = options->name; if (!name_suffix && options->name_suffix) name_suffix = options->name_suffix; if (name_prefix && name && name_suffix) break; } return g_strdup_printf("%s%s%s", name_prefix ? : "", name ? : "", name_suffix ? : ""); } static gboolean _has_new_style_values(const StatsClusterKeyBuilder *self) { for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->name) return strlen(options->name) > 0; } return FALSE; } static gboolean _has_legacy_values(const StatsClusterKeyBuilder *self) { const gchar *name = NULL; const gchar *id = NULL; for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (!name && options->legacy.name) name = options->legacy.name; if (!id && options->legacy.id) id = options->legacy.id; if (name && id) break; } return (name && strlen(name) > 0) || (id && strlen(id) > 0); } static GArray * _construct_merged_labels(const StatsClusterKeyBuilder *self) { GArray *merged_labels = g_array_sized_new(FALSE, FALSE, sizeof(StatsClusterLabel), 4); for (const GList *link = g_list_first(self->options_stack); link; link = link->next) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->legacy_labels) merged_labels = g_array_append_vals(merged_labels, options->legacy_labels->data, options->legacy_labels->len); } GArray *merged_unsorted_labels = g_array_sized_new(FALSE, FALSE, sizeof(StatsClusterLabel), 4); for (const GList *link = g_list_first(self->options_stack); link; link = link->next) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->labels) merged_unsorted_labels = g_array_append_vals(merged_unsorted_labels, options->labels->data, options->labels->len); } g_array_sort(merged_unsorted_labels, (GCompareFunc) _labels_sort); merged_labels = g_array_append_vals(merged_labels, merged_unsorted_labels->data, merged_unsorted_labels->len); g_array_free(merged_unsorted_labels, TRUE); return merged_labels; } static GArray * _construct_merged_legacy_labels(const StatsClusterKeyBuilder *self) { GArray *merged_labels = g_array_sized_new(FALSE, FALSE, sizeof(StatsClusterLabel), 4); for (const GList *link = g_list_first(self->options_stack); link; link = link->next) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->legacy_labels) merged_labels = g_array_append_vals(merged_labels, options->legacy_labels->data, options->legacy_labels->len); } return merged_labels; } static void _get_legacy_options(const StatsClusterKeyBuilder *self, guint16 *component, const gchar **id, const gchar **instance, const gchar **name) { *component = LEGACY_COMPONENT_UNSET; *id = *instance = *name = NULL; for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (*component == LEGACY_COMPONENT_UNSET && options->legacy.component != LEGACY_COMPONENT_UNSET) *component = options->legacy.component; if (!*id && options->legacy.id) *id = options->legacy.id; if (!*instance && options->legacy.instance) *instance = options->legacy.instance; if (!*name && options->legacy.name) *name = options->legacy.name; if (*component != G_MAXUINT16 && *id && *instance && *name) break; } } StatsClusterUnit _get_unit(const StatsClusterKeyBuilder *self) { for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->unit != SCU_NONE) return options->unit; } return SCU_NONE; } StatsClusterFrameOfReference _get_frame_of_reference(const StatsClusterKeyBuilder *self) { for (const GList *link = g_list_last(self->options_stack); link; link = link->prev) { const BuilderOptions *options = (const BuilderOptions *) link->data; if (options->frame_of_reference != SCFOR_NONE) return options->frame_of_reference; } return SCFOR_NONE; } StatsClusterKey * stats_cluster_key_builder_build_single(const StatsClusterKeyBuilder *self) { StatsClusterKey *sc_key = g_new0(StatsClusterKey, 1); StatsClusterKey temp_key; gchar *name = NULL; gboolean has_new_style_values = _has_new_style_values(self); gboolean has_legacy_values = _has_legacy_values(self); GArray *merged_labels = _construct_merged_labels(self); if (has_new_style_values) { name = _format_name(self); stats_cluster_single_key_set(&temp_key, name, (StatsClusterLabel *) merged_labels->data, merged_labels->len); stats_cluster_single_key_add_unit(&temp_key, _get_unit(self)); stats_cluster_single_key_add_frame_of_reference(&temp_key, _get_frame_of_reference(self)); } if (has_legacy_values) { guint16 legacy_component; const gchar *legacy_id, *legacy_instance, *legacy_name; _get_legacy_options(self, &legacy_component, &legacy_id, &legacy_instance, &legacy_name); if (has_new_style_values) { if (legacy_name && strlen(legacy_name) > 0) stats_cluster_single_key_add_legacy_alias_with_name(&temp_key, legacy_component, legacy_id, legacy_instance, legacy_name); else stats_cluster_single_key_add_legacy_alias(&temp_key, legacy_component, legacy_id, legacy_instance); } else { if (legacy_name && strlen(legacy_name) > 0) stats_cluster_single_key_legacy_set_with_name(&temp_key, legacy_component, legacy_id, legacy_instance, legacy_name); else stats_cluster_single_key_legacy_set(&temp_key, legacy_component, legacy_id, legacy_instance); } } stats_cluster_key_clone(sc_key, &temp_key); g_array_free(merged_labels, TRUE); g_free(name); return sc_key; } StatsClusterKey * stats_cluster_key_builder_build_logpipe(const StatsClusterKeyBuilder *self) { StatsClusterKey *sc_key = g_new0(StatsClusterKey, 1); StatsClusterKey temp_key; gchar *name = NULL; gboolean has_new_style_values = _has_new_style_values(self); gboolean has_legacy_values = _has_legacy_values(self); GArray *merged_labels = _construct_merged_labels(self); if (has_new_style_values) { name = _format_name(self); stats_cluster_logpipe_key_set(&temp_key, name, (StatsClusterLabel *) merged_labels->data, merged_labels->len); } if (has_legacy_values) { guint16 legacy_component; const gchar *legacy_id, *legacy_instance, *legacy_name; _get_legacy_options(self, &legacy_component, &legacy_id, &legacy_instance, &legacy_name); g_assert(!legacy_name || strlen(legacy_name) == 0); if (has_new_style_values) stats_cluster_logpipe_key_add_legacy_alias(&temp_key, legacy_component, legacy_id, legacy_instance); else stats_cluster_logpipe_key_legacy_set(&temp_key, legacy_component, legacy_id, legacy_instance); } stats_cluster_key_clone(sc_key, &temp_key); g_array_free(merged_labels, TRUE); g_free(name); return sc_key; } void stats_cluster_key_builder_add_legacy_label(StatsClusterKeyBuilder *self, const StatsClusterLabel label) { BuilderOptions *options = _get_last_options(self); if (!options->legacy_labels) { options->legacy_labels = g_array_sized_new(FALSE, FALSE, sizeof(StatsClusterLabel), 4); g_array_set_clear_func(options->legacy_labels, (GDestroyNotify) _label_free); } StatsClusterLabel own_label = stats_cluster_label(g_strdup(label.name), g_strdup(label.value)); options->legacy_labels = g_array_append_vals(options->legacy_labels, &own_label, 1); } const gchar * stats_cluster_key_builder_format_legacy_stats_instance(const StatsClusterKeyBuilder *self, gchar *buf, gsize buf_size) { GArray *merged_legacy_labels = _construct_merged_legacy_labels(self); if (merged_legacy_labels->len == 0) { buf[0] = '\0'; goto exit; } gboolean comma_needed = FALSE; gsize pos = 0; for (guint i = 0; i < merged_legacy_labels->len; ++i) { StatsClusterLabel *l = &g_array_index(merged_legacy_labels, StatsClusterLabel, i); pos += g_snprintf(buf + pos, buf_size - pos, "%s%s", comma_needed ? "," : "", l->value); pos = MIN(buf_size, pos); if (i == 0) comma_needed = TRUE; } exit: g_array_free(merged_legacy_labels, TRUE); return buf; } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-key-builder.h000066400000000000000000000055721450431004300244700ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CLUSTER_KEY_BUILDER_H_INCLUDED #define STATS_CLUSTER_KEY_BUILDER_H_INCLUDED #include "syslog-ng.h" #include "stats-cluster.h" typedef struct _StatsClusterKeyBuilder StatsClusterKeyBuilder; StatsClusterKeyBuilder *stats_cluster_key_builder_new(void); void stats_cluster_key_builder_push(StatsClusterKeyBuilder *self); void stats_cluster_key_builder_pop(StatsClusterKeyBuilder *self); void stats_cluster_key_builder_free(StatsClusterKeyBuilder *self); void stats_cluster_key_builder_set_name(StatsClusterKeyBuilder *self, const gchar *name); void stats_cluster_key_builder_set_name_prefix(StatsClusterKeyBuilder *self, const gchar *name_prefix); void stats_cluster_key_builder_set_name_suffix(StatsClusterKeyBuilder *self, const gchar *name_suffix); void stats_cluster_key_builder_add_label(StatsClusterKeyBuilder *self, const StatsClusterLabel label); void stats_cluster_key_builder_set_unit(StatsClusterKeyBuilder *self, StatsClusterUnit unit); void stats_cluster_key_builder_set_frame_of_reference(StatsClusterKeyBuilder *self, StatsClusterFrameOfReference frame_of_reference); void stats_cluster_key_builder_set_legacy_alias(StatsClusterKeyBuilder *self, guint16 component, const gchar *id, const gchar *instance); void stats_cluster_key_builder_set_legacy_alias_name(StatsClusterKeyBuilder *self, const gchar *name); StatsClusterKey *stats_cluster_key_builder_build_single(const StatsClusterKeyBuilder *self); StatsClusterKey *stats_cluster_key_builder_build_logpipe(const StatsClusterKeyBuilder *self); /* Compatibility functions for reproducing stats_instance names based on unsorted labels */ void stats_cluster_key_builder_add_legacy_label(StatsClusterKeyBuilder *self, const StatsClusterLabel label); const gchar *stats_cluster_key_builder_format_legacy_stats_instance(const StatsClusterKeyBuilder *self, gchar *buf, gsize buf_size); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-logpipe.c000066400000000000000000000063621450431004300237040ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 2017 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-cluster-logpipe.h" #include "stats/stats-cluster.h" static const gchar *tag_names[SC_TYPE_MAX] = { /* [SC_TYPE_DROPPED] = */ "dropped", /* [SC_TYPE_PROCESSED] = */ "processed", /* [SC_TYPE_QUEUED] = */ "queued", /* [SC_TYPE_SUPPRESSED] = */ "suppressed", /* [SC_TYPE_STAMP] = */ "stamp", /* [SC_TYPE_DISCARDED] = */ "discarded", /* [SC_TYPE_MATCHED] = */ "matched", /* [SC_TYPE_NOT_MATCHED] = */ "not_matched", /* [SC_TYPE_WRITTEN] = */ "written", }; static void _counter_group_logpipe_free(StatsCounterGroup *counter_group) { g_free(counter_group->counters); } static gboolean _counter_group_logpipe_get_type_label(StatsCounterGroup *self, gint type, StatsClusterLabel *label) { if (type >= SC_TYPE_MAX) return FALSE; const gchar *type_name = tag_names[type]; if (type == SC_TYPE_WRITTEN) type_name = "delivered"; *label = stats_cluster_label("result", type_name); return TRUE; } static void _counter_group_logpipe_init(StatsCounterGroupInit *self, StatsCounterGroup *counter_group) { counter_group->counters = g_new0(StatsCounterItem, SC_TYPE_MAX); counter_group->capacity = SC_TYPE_MAX; counter_group->counter_names = self->counter.names; counter_group->get_type_label = _counter_group_logpipe_get_type_label; counter_group->free_fn = _counter_group_logpipe_free; } void stats_cluster_logpipe_key_set(StatsClusterKey *key, const gchar *name, StatsClusterLabel *labels, gsize labels_len) { stats_cluster_key_set(key, name, labels, labels_len, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_logpipe_init, .equals = NULL }); } void stats_cluster_logpipe_key_legacy_set(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance) { stats_cluster_key_legacy_set(key, component, id, instance, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_logpipe_init, .equals = NULL }); } void stats_cluster_logpipe_key_add_legacy_alias(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance) { stats_cluster_key_add_legacy_alias(key, component, id, instance, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_logpipe_init, .equals = NULL }); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-logpipe.h000066400000000000000000000044321450431004300237050ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 2017 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CLUSTER_LOGPIPE_H_INCLUDED #define STATS_CLUSTER_LOGPIPE_H_INCLUDED #include "syslog-ng.h" typedef enum { SC_TYPE_DROPPED=0, /* number of messages dropped */ SC_TYPE_PROCESSED, /* number of messages processed */ SC_TYPE_QUEUED, /* number of messages on disk */ SC_TYPE_SUPPRESSED,/* number of messages suppressed */ SC_TYPE_STAMP, /* timestamp */ SC_TYPE_DISCARDED, /* discarded messages of filter */ SC_TYPE_MATCHED, /* discarded messages of filter */ SC_TYPE_NOT_MATCHED, /* discarded messages of filter */ SC_TYPE_WRITTEN, /* number of sent messages */ SC_TYPE_MAX } StatsCounterGroupLogPipe; void stats_cluster_logpipe_key_set(StatsClusterKey *key, const gchar *name, StatsClusterLabel *labels, gsize labels_len); /* * The legacy functions should not be used for new code. * When transforming a legacy stats key to a new metric key, aliases should be specified consistently at all call sites. */ void stats_cluster_logpipe_key_legacy_set(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance); void stats_cluster_logpipe_key_add_legacy_alias(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-single.c000066400000000000000000000123261450431004300235230ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-cluster-single.h" #include "stats/stats-cluster.h" static const gchar *tag_names[SC_TYPE_SINGLE_MAX] = { /* [SC_TYPE_SINGLE_VALUE] = */ "value", }; static void _counter_group_free(StatsCounterGroup *counter_group) { g_free(counter_group->counters); } static void _counter_group_init(StatsCounterGroupInit *self, StatsCounterGroup *counter_group) { counter_group->counters = g_new0(StatsCounterItem, SC_TYPE_SINGLE_MAX); counter_group->capacity = SC_TYPE_SINGLE_MAX; counter_group->counter_names = self->counter.names; counter_group->free_fn = _counter_group_free; } void stats_cluster_single_key_legacy_set(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance) { stats_cluster_key_legacy_set(key, component, id, instance, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_init, .equals = NULL }); } void stats_cluster_single_key_add_legacy_alias(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance) { stats_cluster_key_add_legacy_alias(key, component, id, instance, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_init, .equals = NULL }); } static void _counter_group_with_name_free(StatsCounterGroup *counter_group) { g_free((gchar *)counter_group->counter_names[0]); g_free(counter_group->counter_names); _counter_group_free(counter_group); } static void _counter_group_init_with_name(StatsCounterGroupInit *self, StatsCounterGroup *counter_group) { counter_group->counters = g_new0(StatsCounterItem, SC_TYPE_SINGLE_MAX); counter_group->capacity = SC_TYPE_SINGLE_MAX; const gchar **counter_names = g_new0(const gchar *, 1); counter_names[0] = g_strdup(self->counter.name); counter_group->counter_names = counter_names; counter_group->free_fn = _counter_group_with_name_free; } static void _clone_with_name(StatsCounterGroupInit *dst, const StatsCounterGroupInit *src) { dst->counter.name = g_strdup(src->counter.name); dst->init = src->init; dst->equals = src->equals; dst->clone = src->clone; dst->cloned_free = src->cloned_free; } static void _cloned_free_with_name(StatsCounterGroupInit *self) { g_free((gchar *)self->counter.name); } static gboolean _group_init_equals(const StatsCounterGroupInit *self, const StatsCounterGroupInit *other) { g_assert(self != NULL && other != NULL && self->counter.name != NULL && other->counter.name != NULL); return (self->init == other->init) && (g_strcmp0(self->counter.name, other->counter.name) == 0); } void stats_cluster_single_key_legacy_set_with_name(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance, const gchar *name) { stats_cluster_key_legacy_set(key, component, id, instance, (StatsCounterGroupInit) { .counter.name = name, .init = _counter_group_init_with_name, .equals = _group_init_equals, .clone = _clone_with_name, .cloned_free = _cloned_free_with_name }); } void stats_cluster_single_key_add_legacy_alias_with_name(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance, const gchar *name) { stats_cluster_key_add_legacy_alias(key, component, id, instance, (StatsCounterGroupInit) { .counter.name = name, .init = _counter_group_init_with_name, .equals = _group_init_equals, .clone = _clone_with_name, .cloned_free = _cloned_free_with_name }); } void stats_cluster_single_key_set(StatsClusterKey *key, const gchar *name, StatsClusterLabel *labels, gsize labels_len) { stats_cluster_key_set(key, name, labels, labels_len, (StatsCounterGroupInit) { .counter.names = tag_names, .init = _counter_group_init, .equals = NULL }); } void stats_cluster_single_key_add_unit(StatsClusterKey *key, StatsClusterUnit stored_unit) { key->formatting.stored_unit = stored_unit; } void stats_cluster_single_key_add_frame_of_reference(StatsClusterKey *key, StatsClusterFrameOfReference frame_of_reference) { key->formatting.frame_of_reference = frame_of_reference; } StatsCounterItem * stats_cluster_single_get_counter(StatsCluster *self) { return self ? &self->counter_group.counters[0] : NULL; } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster-single.h000066400000000000000000000051051450431004300235250ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CLUSTER_SINGLE_H_INCLUDED #define STATS_CLUSTER_SINGLE_H_INCLUDED #include "syslog-ng.h" #include "stats-cluster.h" typedef enum { SC_TYPE_SINGLE_VALUE, SC_TYPE_SINGLE_MAX } StatsCounterGroupSingle; void stats_cluster_single_key_set(StatsClusterKey *key, const gchar *name, StatsClusterLabel *labels, gsize labels_len); /* * The legacy functions should not be used for new code. * When transforming a legacy stats key to a new metric key, aliases should be specified consistently at all call sites. */ void stats_cluster_single_key_legacy_set(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance); void stats_cluster_single_key_add_legacy_alias(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance); void stats_cluster_single_key_legacy_set_with_name(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance, const gchar *name); void stats_cluster_single_key_add_legacy_alias_with_name(StatsClusterKey *key, guint16 component, const gchar *id, const gchar *instance, const gchar *name); void stats_cluster_single_key_add_unit(StatsClusterKey *key, StatsClusterUnit stored_unit); void stats_cluster_single_key_add_frame_of_reference(StatsClusterKey *key, StatsClusterFrameOfReference frame_of_reference); StatsCounterItem *stats_cluster_single_get_counter(StatsCluster *self); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster.c000066400000000000000000000300021450431004300222330ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-cluster.h" #include "mainloop.h" #include #include GPtrArray *stats_types; void stats_cluster_init(void) { g_assert(!stats_types); stats_types = g_ptr_array_new_with_free_func(g_free); g_assert(stats_register_type("none") == 0); g_assert(stats_register_type("group") == SCS_GROUP); g_assert(stats_register_type("global") == SCS_GLOBAL); g_assert(stats_register_type("center") == SCS_CENTER); g_assert(stats_register_type("host") == SCS_HOST); g_assert(stats_register_type("sender") == SCS_SENDER); g_assert(stats_register_type("program") == SCS_PROGRAM); g_assert(stats_register_type("severity") == SCS_SEVERITY); g_assert(stats_register_type("facility") == SCS_FACILITY); g_assert(stats_register_type("tag") == SCS_TAG); g_assert(stats_register_type("filter") == SCS_FILTER); g_assert(stats_register_type("parser") == SCS_PARSER); } gboolean _types_equal(const gchar *a, const gchar *b) { return !strcmp(a, b); }; guint stats_register_type(const gchar *type_name) { main_loop_assert_main_thread(); guint index_ = 0; gboolean result = g_ptr_array_find_with_equal_func(stats_types, type_name, (GEqualFunc)_types_equal, &index_); if (result) return index_; g_ptr_array_add(stats_types, g_strdup(type_name)); guint registered_number = stats_types->len - 1; g_assert(registered_number <= SCS_SOURCE_MASK); return registered_number; }; void stats_cluster_deinit(void) { g_ptr_array_free(stats_types, TRUE); stats_types = NULL; } gboolean stats_cluster_key_labels_equal(StatsClusterLabel *l1, gsize l1_len, StatsClusterLabel *l2, gsize l2_len) { if (l1_len != l2_len) return FALSE; for (gsize i = 0; i < l1_len; ++i) { if (strcmp(l1[i].name, l2[i].name) != 0 || g_strcmp0(l1[i].value, l2[i].value) != 0) return FALSE; } return TRUE; } guint stats_cluster_key_labels_hash(StatsClusterLabel *labels, gsize labels_len) { guint hash = 0; for (gsize i = 0; i < labels_len; ++i) { StatsClusterLabel *label = &labels[i]; hash += g_str_hash(label->name); if (label->value) hash += g_str_hash(label->value); } return hash; } StatsClusterLabel * stats_cluster_key_labels_clone(StatsClusterLabel *labels, gsize labels_len) { StatsClusterLabel *cloned = g_new(StatsClusterLabel, labels_len); for (gsize i = 0; i < labels_len; ++i) { StatsClusterLabel *label = &labels[i]; g_assert(label->name); cloned[i] = stats_cluster_label(g_strdup(label->name), g_strdup(label->value)); } return cloned; } void stats_cluster_key_labels_free(StatsClusterLabel *labels, gsize labels_len) { for (gsize i = 0; i < labels_len; ++i) { g_free((gchar *) labels[i].name); g_free((gchar *) labels[i].value); } g_free(labels); } StatsClusterKey * stats_cluster_key_clone(StatsClusterKey *dst, const StatsClusterKey *src) { dst->name = g_strdup(src->name); dst->labels = stats_cluster_key_labels_clone(src->labels, src->labels_len); dst->labels_len = src->labels_len; dst->formatting = src->formatting; dst->legacy.id = g_strdup(src->legacy.id ? : ""); dst->legacy.component = src->legacy.component; dst->legacy.instance = g_strdup(src->legacy.instance ? : ""); dst->legacy.set = src->legacy.set; if (src->counter_group_init.clone) src->counter_group_init.clone(&dst->counter_group_init, &src->counter_group_init); else dst->counter_group_init = src->counter_group_init; return dst; } void stats_cluster_key_set(StatsClusterKey *self, const gchar *name, StatsClusterLabel *labels, gsize labels_len, StatsCounterGroupInit counter_group_init) { *self = (StatsClusterKey) { 0 }; self->name = name; self->labels = labels; self->labels_len = labels_len; self->counter_group_init = counter_group_init; } static inline void _legacy_set(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance, StatsCounterGroupInit counter_group_init) { self->legacy.id = (id?id:""); self->legacy.component = component; self->legacy.instance = (instance?instance:""); self->legacy.set = 1; self->counter_group_init = counter_group_init; } void stats_cluster_key_legacy_set(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance, StatsCounterGroupInit counter_group_ctor) { *self = (StatsClusterKey) { 0 }; _legacy_set(self, component, id, instance, counter_group_ctor); } void stats_cluster_key_add_legacy_alias(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance, StatsCounterGroupInit counter_group_ctor) { _legacy_set(self, component, id, instance, counter_group_ctor); } void stats_cluster_key_cloned_free(StatsClusterKey *self) { g_free((gchar *)(self->name)); stats_cluster_key_labels_free(self->labels, self->labels_len); g_free((gchar *)(self->legacy.id)); g_free((gchar *)(self->legacy.instance)); if (self->counter_group_init.cloned_free) self->counter_group_init.cloned_free(&self->counter_group_init); } void stats_cluster_key_free(StatsClusterKey *self) { stats_cluster_key_cloned_free(self); g_free(self); } void stats_cluster_foreach_counter(StatsCluster *self, StatsForeachCounterFunc func, gpointer user_data) { gint type; for (type = 0; type < self->counter_group.capacity; type++) { if (self->live_mask & (1 << type)) { func(self, type, &self->counter_group.counters[type], user_data); } } } const gchar * stats_cluster_get_type_name(StatsCluster *self, gint type) { if (type < self->counter_group.capacity) return self->counter_group.counter_names[type]; return ""; } static const gchar * _get_module_name(gint source) { gint type = source & SCS_SOURCE_MASK; g_assert(type < stats_types->len); return g_ptr_array_index(stats_types, type); } static const gchar * _get_component_prefix(gint source) { return (source & SCS_SOURCE ? "src." : (source & SCS_DESTINATION ? "dst." : "")); } /* buf is a scratch area which is not always used, the return value is * either a locally managed string or points to @buf. */ const gchar * stats_cluster_get_component_name(StatsCluster *self, gchar *buf, gsize buf_len) { if ((self->key.legacy.component & SCS_SOURCE_MASK) == SCS_GROUP) { if (self->key.legacy.component & SCS_SOURCE) return "source"; else if (self->key.legacy.component & SCS_DESTINATION) return "destination"; else g_assert_not_reached(); } else { g_snprintf(buf, buf_len, "%s%s", _get_component_prefix(self->key.legacy.component), _get_module_name(self->key.legacy.component)); return buf; } } gboolean stats_counter_group_init_equals(const StatsCounterGroupInit *self, const StatsCounterGroupInit *other) { if (!self || !other) return FALSE; if (self == other) return TRUE; if (self->equals) return self->equals(self, other); return (self->init == other->init) && (self->counter.names == other->counter.names); } gboolean stats_cluster_key_equal(const StatsClusterKey *key1, const StatsClusterKey *key2) { if (stats_cluster_key_is_legacy(key1) != stats_cluster_key_is_legacy(key2)) return FALSE; if (stats_cluster_key_is_legacy(key1)) { return key1->legacy.component == key2->legacy.component && strcmp(key1->legacy.id, key2->legacy.id) == 0 && strcmp(key1->legacy.instance, key2->legacy.instance) == 0 && stats_counter_group_init_equals(&key1->counter_group_init, &key2->counter_group_init); } return strcmp(key1->name, key2->name) == 0 && stats_cluster_key_labels_equal(key1->labels, key1->labels_len, key2->labels, key2->labels_len) && stats_counter_group_init_equals(&key1->counter_group_init, &key2->counter_group_init); } guint stats_cluster_key_hash(const StatsClusterKey *self) { if (stats_cluster_key_is_legacy(self)) return g_str_hash(self->legacy.id) + g_str_hash(self->legacy.instance) + self->legacy.component; return g_str_hash(self->name) + stats_cluster_key_labels_hash(self->labels, self->labels_len); } StatsCounterItem * stats_cluster_track_counter(StatsCluster *self, gint type) { gint type_mask = 1 << type; g_assert(type < self->counter_group.capacity); self->live_mask |= type_mask; self->use_count++; return &self->counter_group.counters[type]; } StatsCounterItem * stats_cluster_get_counter(StatsCluster *self, gint type) { gint type_mask = 1 << type; g_assert(type < self->counter_group.capacity); if (!(self->live_mask & type_mask)) return NULL; return &self->counter_group.counters[type]; } void stats_cluster_untrack_counter(StatsCluster *self, gint type, StatsCounterItem **counter) { g_assert(self && (self->live_mask & (1 << type)) && &self->counter_group.counters[type] == (*counter)); g_assert(self->use_count > 0); self->use_count--; if (self->use_count == 0 && (*counter)->external) { (*counter)->external = FALSE; (*counter)->value_ref = NULL; gint type_mask = 1 << type; self->live_mask &= ~type_mask; } *counter = NULL; } static gchar * _stats_build_query_key(StatsCluster *self) { GString *key = g_string_new(""); gchar buffer[64] = {0}; const gchar *component_name = stats_cluster_get_component_name(self, buffer, sizeof(buffer)); g_string_append(key, component_name); if (self->key.legacy.id && self->key.legacy.id[0]) { g_string_append_printf(key, ".%s", self->key.legacy.id); } if (self->key.legacy.instance && self->key.legacy.instance[0]) { g_string_append_printf(key, ".%s", self->key.legacy.instance); } return g_string_free(key, FALSE); } gboolean stats_cluster_is_alive(StatsCluster *self, gint type) { g_assert(type < self->counter_group.capacity); return !!((1<live_mask); } gboolean stats_cluster_is_indexed(StatsCluster *self, gint type) { g_assert(type < self->counter_group.capacity); return !!((1<indexed_mask); } StatsCluster * stats_cluster_new(const StatsClusterKey *key) { StatsCluster *self = g_new0(StatsCluster, 1); stats_cluster_key_clone(&self->key, key); self->use_count = 0; self->query_key = _stats_build_query_key(self); key->counter_group_init.init(&self->key.counter_group_init, &self->counter_group); g_assert(self->counter_group.capacity <= sizeof(self->live_mask)*8); return self; } StatsCluster * stats_cluster_dynamic_new(const StatsClusterKey *key) { StatsCluster *sc = stats_cluster_new(key); sc->dynamic = TRUE; return sc; } void stats_counter_group_free(StatsCounterGroup *self) { if (self->free_fn) self->free_fn(self); } static void stats_cluster_free_counter(StatsCluster *self, gint type, StatsCounterItem *item, gpointer user_data) { stats_counter_free(item); } void stats_cluster_free(StatsCluster *self) { stats_cluster_foreach_counter(self, stats_cluster_free_counter, NULL); stats_cluster_key_cloned_free(&self->key); g_free(self->query_key); stats_counter_group_free(&self->counter_group); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-cluster.h000066400000000000000000000154131450431004300222510ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CLUSTER_H_INCLUDED #define STATS_CLUSTER_H_INCLUDED 1 #include "stats/stats-counter.h" #include "stats/stats-cluster-logpipe.h" enum { /* direction bits, used to distinguish between source/destination drivers */ SCS_SOURCE = 0x0100, SCS_DESTINATION = 0x0200, SCS_GROUP = 1, SCS_GLOBAL, SCS_CENTER, SCS_HOST, SCS_SENDER, SCS_PROGRAM, SCS_SEVERITY, SCS_FACILITY, SCS_TAG, SCS_FILTER, SCS_PARSER, SCS_SOURCE_MASK = 0xff }; typedef enum _StatsClusterUnit { SCU_NONE = 0, SCU_SECONDS, SCU_MINUTES, SCU_HOURS, SCU_MILLISECONDS, SCU_NANOSECONDS, SCU_BYTES, SCU_KIB, SCU_MIB, SCU_GIB, } StatsClusterUnit; typedef enum _StatsClusterFrameOfReference { SCFOR_NONE = 0, SCFOR_ABSOLUTE, /* * Only applicable for counters with seconds, minutes or hours unit. * Has a 1 second precision. * Results in a positive value for timestamps older than the time of query. */ SCFOR_RELATIVE_TO_TIME_OF_QUERY, } StatsClusterFrameOfReference; typedef struct _StatsCounterGroup StatsCounterGroup; typedef struct _StatsCounterGroupInit StatsCounterGroupInit; struct _StatsCounterGroup { StatsCounterItem *counters; const gchar **counter_names; guint16 capacity; gboolean (*get_type_label)(StatsCounterGroup *self, gint type, StatsClusterLabel *label); void (*free_fn)(StatsCounterGroup *self); }; struct _StatsCounterGroupInit { union { const gchar **names; const gchar *name; } counter; void (*init)(StatsCounterGroupInit *self, StatsCounterGroup *counter_group); gboolean (*equals)(const StatsCounterGroupInit *self, const StatsCounterGroupInit *other); void (*clone)(StatsCounterGroupInit *dst, const StatsCounterGroupInit *src); void (*cloned_free)(StatsCounterGroupInit *self); }; gboolean stats_counter_group_init_equals(const StatsCounterGroupInit *self, const StatsCounterGroupInit *other); void stats_counter_group_free(StatsCounterGroup *self); struct _StatsClusterLabel { const gchar *name; const gchar *value; }; static inline StatsClusterLabel stats_cluster_label(const gchar *name, const gchar *value) { return (StatsClusterLabel) { .name = name, .value = value }; } struct _StatsClusterKey { const gchar *name; StatsClusterLabel *labels; gsize labels_len; struct { StatsClusterUnit stored_unit; StatsClusterFrameOfReference frame_of_reference; } formatting; struct { const gchar *id; /* syslog-ng component/driver/subsystem that registered this cluster */ guint16 component; const gchar *instance; guint set:1; } legacy; StatsCounterGroupInit counter_group_init; }; /* NOTE: This struct can only be used by the stats implementation and not by client code. */ /* StatsCluster encapsulates a set of related counters that are registered * to the same stats source. In a lot of cases, the same stats source uses * multiple counters, so keeping them at the same location makes sense. * * This also improves performance for dynamic counters that relate to * information found in the log stream. In that case multiple counters can * be registered with a single hash lookup */ typedef struct _StatsCluster { StatsClusterKey key; StatsCounterGroup counter_group; guint16 use_count; guint16 live_mask; guint16 indexed_mask; guint16 dynamic:1; gchar *query_key; } StatsCluster; typedef void (*StatsForeachCounterFunc)(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data); void stats_cluster_init(void); void stats_cluster_deinit(void); guint stats_register_type(const gchar *type_name); const gchar *stats_cluster_get_type_name(StatsCluster *self, gint type); const gchar *stats_cluster_get_component_name(StatsCluster *self, gchar *buf, gsize buf_len); void stats_cluster_foreach_counter(StatsCluster *self, StatsForeachCounterFunc func, gpointer user_data); StatsClusterKey *stats_cluster_key_clone(StatsClusterKey *dst, const StatsClusterKey *src); void stats_cluster_key_cloned_free(StatsClusterKey *self); void stats_cluster_key_free(StatsClusterKey *self); gboolean stats_cluster_key_equal(const StatsClusterKey *key1, const StatsClusterKey *key2); guint stats_cluster_key_hash(const StatsClusterKey *self); StatsCounterItem *stats_cluster_track_counter(StatsCluster *self, gint type); StatsCounterItem *stats_cluster_get_counter(StatsCluster *self, gint type); void stats_cluster_untrack_counter(StatsCluster *self, gint type, StatsCounterItem **counter); gboolean stats_cluster_is_alive(StatsCluster *self, gint type); gboolean stats_cluster_is_indexed(StatsCluster *self, gint type); static inline gboolean stats_cluster_is_orphaned(StatsCluster *self) { return self->use_count == 0; } static inline gboolean stats_cluster_get_type_label(StatsCluster *self, gint type, StatsClusterLabel *label) { if (!self->counter_group.get_type_label) return FALSE; return self->counter_group.get_type_label(&self->counter_group, type, label); } StatsCluster *stats_cluster_new(const StatsClusterKey *key); StatsCluster *stats_cluster_dynamic_new(const StatsClusterKey *key); void stats_cluster_free(StatsCluster *self); void stats_cluster_key_set(StatsClusterKey *self, const gchar *name, StatsClusterLabel *labels, gsize labels_len, StatsCounterGroupInit counter_group_ctor); void stats_cluster_key_legacy_set(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance, StatsCounterGroupInit counter_group_ctor); void stats_cluster_key_add_legacy_alias(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance, StatsCounterGroupInit counter_group_ctor); static inline gboolean stats_cluster_key_is_legacy(const StatsClusterKey *self) { return self->legacy.set; } #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-compat.h000066400000000000000000000065531450431004300220600ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_COMPAT_H #define STATS_COMPAT_H #include "syslog-ng.h" #include "stats-counter.h" #include "stats-cluster.h" #include "stats-cluster-single.h" #include "stats-registry.h" #include "atomic-gssize.h" #include /* * StatsByteCounter allows representing "big" accumulating byte-based metrics * even on 32-bit architectures, where a simple stats-counter would overflow * after 4 GiB. * * When 64-bit counters are available, they will be used. * If not, the counters lose precision but are able to represent larger values. * * The current implementation is not thread-safe, reimplement it using a CAS * loop when needed. */ typedef enum _StatsByteCounterPrecision { SBCP_KIB, SBCP_MIB, SBCP_GIB, } StatsByteCounterPrecision; typedef struct _StatsByteCounter { StatsCounterItem *counter; #if STATS_COUNTER_MAX_VALUE < UINT64_MAX atomic_gssize counter_cache; gsize precision; #endif } StatsByteCounter; static inline void stats_byte_counter_init(StatsByteCounter *self, StatsClusterKey *key, gint stats_level, StatsByteCounterPrecision min_precision) { *self = (StatsByteCounter) { 0 }; #if STATS_COUNTER_MAX_VALUE < UINT64_MAX StatsClusterUnit unit = SCU_BYTES; switch (min_precision) { case SBCP_KIB: self->precision = 1024; unit = SCU_KIB; break; case SBCP_MIB: self->precision = 1024 * 1024; unit = SCU_MIB; break; case SBCP_GIB: self->precision = 1024 * 1024 * 1024; unit = SCU_GIB; break; default: g_assert_not_reached(); } stats_cluster_single_key_add_unit(key, unit); #endif stats_lock(); stats_register_counter(stats_level, key, SC_TYPE_SINGLE_VALUE, &self->counter); stats_unlock(); } static inline void stats_byte_counter_deinit(StatsByteCounter *self, StatsClusterKey *key) { stats_lock(); stats_unregister_counter(key, SC_TYPE_SINGLE_VALUE, &self->counter); stats_unlock(); } /* this is currently NOT thread-safe */ static inline void stats_byte_counter_add(StatsByteCounter *self, gsize add) { #if STATS_COUNTER_MAX_VALUE < UINT64_MAX if (!self->counter) return; self->counter_cache.value += add; if (self->counter_cache.value > self->precision) { stats_counter_add(self->counter, self->counter_cache.value / self->precision); self->counter_cache.value %= self->precision; } #else stats_counter_add(self->counter, add); #endif } #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-control.c000066400000000000000000000110631450431004300222400ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-control.h" #include "stats/stats-csv.h" #include "stats/stats-prometheus.h" #include "stats/stats-counter.h" #include "stats/stats-registry.h" #include "stats/stats-cluster.h" #include "stats/aggregator/stats-aggregator-registry.h" #include "stats/stats-query-commands.h" #include "control/control-commands.h" #include "control/control-server.h" #include "control/control-connection.h" #include static void _reset_counter(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { stats_counter_set(counter, 0); } static inline void _reset_counter_if_needed(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { if (stats_counter_read_only(counter)) return; if (strcmp(stats_cluster_get_type_name(sc, type), "memory_usage") == 0) return; switch (type) { case SC_TYPE_QUEUED: return; default: _reset_counter(sc, type, counter, user_data); } } static void _reset_counters(void) { stats_lock(); stats_foreach_counter(_reset_counter_if_needed, NULL, NULL); stats_unlock(); stats_aggregator_lock(); stats_aggregator_registry_reset(); stats_aggregator_unlock(); } static void _send_batched_response(const gchar *record, gpointer user_data) { static const gsize BATCH_LEN = 2048; gpointer *args = (gpointer *) user_data; ControlConnection *cc = (ControlConnection *) args[0]; GString **batch = (GString **) args[1]; if (!*batch) *batch = g_string_sized_new(512); g_string_append_printf(*batch, "%s", record); if ((*batch)->len > BATCH_LEN) { control_connection_send_batched_reply(cc, *batch); *batch = NULL; } } static void control_connection_send_stats(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { gchar **cmds = g_strsplit(command->str, " ", 3); g_assert(g_str_equal(cmds[0], "STATS")); GString *response = NULL; gpointer args[] = {cc, &response}; if (g_strcmp0(cmds[1], "PROMETHEUS") == 0) { gboolean with_legacy = g_strcmp0(cmds[2], "WITH_LEGACY") == 0; stats_generate_prometheus(_send_batched_response, args, with_legacy, cancelled); } else stats_generate_csv(_send_batched_response, args, cancelled); if (response != NULL) control_connection_send_batched_reply(cc, response); control_connection_send_close_batch(cc); g_strfreev(cmds); } static void control_connection_reset_stats(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GString *result = g_string_new("OK The statistics of syslog-ng have been reset to 0."); _reset_counters(); control_connection_send_reply(cc, result); } static gboolean _is_cluster_orphaned(StatsCluster *sc, gpointer user_data) { return stats_cluster_is_orphaned(sc); } static void control_connection_remove_orphans(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GString *result = g_string_new("OK Orphaned statistics have been removed."); stats_aggregator_lock(); stats_aggregator_remove_orphaned_stats(); stats_aggregator_unlock(); stats_lock(); stats_foreach_cluster_remove(_is_cluster_orphaned, NULL); stats_unlock(); control_connection_send_reply(cc, result); } void stats_register_control_commands(void) { control_register_command("STATS", control_connection_send_stats, NULL, TRUE); control_register_command("RESET_STATS", control_connection_reset_stats, NULL, FALSE); control_register_command("REMOVE_ORPHANED_STATS", control_connection_remove_orphans, NULL, FALSE); control_register_command("QUERY", process_query_command, NULL, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-control.h000066400000000000000000000021751450431004300222510ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CONTROL_H_INCLUDED #define STATS_CONTROL_H_INCLUDED 1 #include "syslog-ng.h" void stats_register_control_commands(void); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-counter.h000066400000000000000000000062121450431004300222440ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_COUNTER_H_INCLUDED #define STATS_COUNTER_H_INCLUDED 1 #include "syslog-ng.h" #include "atomic-gssize.h" #define STATS_COUNTER_MAX_VALUE G_MAXSIZE typedef struct _StatsCounterItem { union { atomic_gssize value; atomic_gssize *value_ref; }; gchar *name; gint type; gboolean external; } StatsCounterItem; static gboolean stats_counter_read_only(StatsCounterItem *counter) { return counter->external; } static inline void stats_counter_add(StatsCounterItem *counter, gssize add) { if (counter) { g_assert(!stats_counter_read_only(counter)); atomic_gssize_add(&counter->value, add); } } static inline void stats_counter_sub(StatsCounterItem *counter, gssize sub) { if (counter) { g_assert(!stats_counter_read_only(counter)); atomic_gssize_sub(&counter->value, sub); } } static inline void stats_counter_inc(StatsCounterItem *counter) { if (counter) { g_assert(!stats_counter_read_only(counter)); atomic_gssize_inc(&counter->value); } } static inline void stats_counter_dec(StatsCounterItem *counter) { if (counter) { g_assert(!stats_counter_read_only(counter)); atomic_gssize_dec(&counter->value); } } static inline void stats_counter_set(StatsCounterItem *counter, gsize value) { if (counter && !stats_counter_read_only(counter)) { atomic_gssize_set(&counter->value, value); } } static inline gsize stats_counter_get(StatsCounterItem *counter) { gsize result = 0; if (counter) { if (!counter->external) result = atomic_gssize_get_unsigned(&counter->value); else result = atomic_gssize_get_unsigned(counter->value_ref); } return result; } /* Can only store positive values. Fixes overflow on 32 bit machines until 2106 if using seconds. */ static inline void stats_counter_set_time(StatsCounterItem *counter, gint64 value) { stats_counter_set(counter, (gsize) MAX(0, value)); } static inline gchar * stats_counter_get_name(StatsCounterItem *counter) { if (counter) return counter->name; return NULL; } static inline void stats_counter_free(StatsCounterItem *counter) { g_free(counter->name); } #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-csv.c000066400000000000000000000064511450431004300213600ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-csv.h" #include "stats/stats-registry.h" #include "stats/stats-cluster.h" #include "utf8utils.h" #include static gboolean has_csv_special_character(const gchar *var) { if (strchr(var, ';')) return TRUE; if (strchr(var, '\"')) return TRUE; return FALSE; } static gchar * stats_format_csv_escapevar(const gchar *var) { gchar *escaped_result; if (var[0] && has_csv_special_character(var)) { gchar *result; /* quote */ result = convert_unsafe_utf8_to_escaped_binary(var, -1, "\""); escaped_result = g_strdup_printf("\"%s\"", result); g_free(result); } else { escaped_result = convert_unsafe_utf8_to_escaped_binary(var, -1, NULL); } return escaped_result; } static void stats_format_csv(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { gpointer *args = (gpointer *) user_data; StatsCSVRecordFunc process_record = (StatsCSVRecordFunc) args[0]; gpointer process_record_arg = args[1]; gchar *s_id, *s_instance, *tag_name; gchar buf[32]; gchar state; GString *csv = g_string_sized_new(512); s_id = stats_format_csv_escapevar(sc->key.legacy.id); s_instance = stats_format_csv_escapevar(sc->key.legacy.instance); if (sc->dynamic) state = 'd'; else if (stats_cluster_is_orphaned(sc)) state = 'o'; else state = 'a'; tag_name = stats_format_csv_escapevar(stats_cluster_get_type_name(sc, type)); g_string_printf(csv, "%s;%s;%s;%c;%s;%"G_GSIZE_FORMAT"\n", stats_cluster_get_component_name(sc, buf, sizeof(buf)), s_id, s_instance, state, tag_name, stats_counter_get(&sc->counter_group.counters[type])); process_record(csv->str, process_record_arg); g_string_free(csv, TRUE); g_free(tag_name); g_free(s_id); g_free(s_instance); } void stats_generate_csv(StatsCSVRecordFunc process_record, gpointer user_data, gboolean *cancelled) { GString *csv = g_string_sized_new(512); g_string_printf(csv, "%s;%s;%s;%s;%s;%s\n", "SourceName", "SourceId", "SourceInstance", "State", "Type", "Number"); process_record(csv->str, user_data); g_string_free(csv, TRUE); gpointer format_csv_args[] = {process_record, user_data}; stats_lock(); stats_foreach_legacy_counter(stats_format_csv, format_csv_args, cancelled); stats_unlock(); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-csv.h000066400000000000000000000023731450431004300213640ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_CSV_H_INCLUDED #define STATS_CSV_H_INCLUDED 1 #include "syslog-ng.h" typedef void (*StatsCSVRecordFunc)(const char *record, gpointer user_data); void stats_generate_csv(StatsCSVRecordFunc process_record, gpointer user_data, gboolean *cancelled); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-log.c000066400000000000000000000035221450431004300213420ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-log.h" #include "stats/stats.h" static void stats_log_format_counter(StatsCluster *sc, gint type, StatsCounterItem *item, gpointer user_data) { EVTREC *e = (EVTREC *) user_data; EVTTAG *tag; gchar buf[32]; tag = evt_tag_printf(stats_cluster_get_type_name(sc, type), "%s(%s%s%s)=%"G_GSIZE_FORMAT, stats_cluster_get_component_name(sc, buf, sizeof(buf)), sc->key.legacy.id, (sc->key.legacy.id[0] && sc->key.legacy.instance[0]) ? "," : "", sc->key.legacy.instance, stats_counter_get(&sc->counter_group.counters[type])); evt_rec_add_tag(e, tag); } void stats_log_format_cluster(StatsCluster *sc, EVTREC *e) { if (stats_cluster_key_is_legacy(&sc->key)) stats_cluster_foreach_counter(sc, stats_log_format_counter, e); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-log.h000066400000000000000000000022441450431004300213470ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_LOG_H_INCLUDED #define STATS_LOG_H_INCLUDED #include "stats/stats-cluster.h" #include "messages.h" void stats_log_format_cluster(StatsCluster *sc, EVTREC *e); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-prometheus.c000066400000000000000000000203671450431004300227620ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-prometheus.h" #include "stats/stats-registry.h" #include "stats/stats-cluster.h" #include "stats/stats-counter.h" #include "timeutils/unixtime.h" #include "utf8utils.h" #include "scratch-buffers.h" #include static gchar * stats_format_prometheus_sanitize_label_value(const gchar *value) { GString *sanitized_value = scratch_buffers_alloc(); append_unsafe_utf8_as_escaped_binary(sanitized_value, value, -1, "\""); return sanitized_value->str; } static inline gboolean _is_valid_name_char(gchar c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9'); } static inline gboolean _is_str_empty(const gchar *str) { return !str || strcmp(str, "") == 0; } static gchar * stats_format_prometheus_sanitize_name(const gchar *name) { GString *sanitized_name = scratch_buffers_alloc(); for (const gchar *c = name; *c; ++c) { if (_is_valid_name_char(*c)) g_string_append_c(sanitized_name, *c); else if (*c == '.' || *c == '-') g_string_append_c(sanitized_name, '_'); /* remove otherwise */ } return sanitized_name->str; } gchar * stats_format_prometheus_format_value(const StatsClusterKey *key, StatsCounterItem *counter) { GString *value = scratch_buffers_alloc(); gsize stored_value = stats_counter_get(counter); guint64 converted_int = stored_value; gdouble converted_double = stored_value; gchar double_buf[G_ASCII_DTOSTR_BUF_SIZE]; switch (key->formatting.stored_unit) { case SCU_GIB: converted_int *= 1024; case SCU_MIB: converted_int *= 1024; case SCU_KIB: converted_int *= 1024; g_string_printf(value, "%"G_GUINT64_FORMAT, converted_int); break; case SCU_HOURS: converted_int *= 60; case SCU_MINUTES: converted_int *= 60; case SCU_SECONDS: if (key->formatting.frame_of_reference == SCFOR_RELATIVE_TO_TIME_OF_QUERY) { UnixTime now; unix_time_set_now(&now); converted_int = now.ut_sec - converted_int; } g_string_printf(value, "%"G_GUINT64_FORMAT, converted_int); break; case SCU_NANOSECONDS: converted_double /= 1e9; g_string_assign(value, g_ascii_dtostr(double_buf, G_N_ELEMENTS(double_buf), converted_double)); break; case SCU_MILLISECONDS: converted_double /= 1e3; g_string_assign(value, g_ascii_dtostr(double_buf, G_N_ELEMENTS(double_buf), converted_double)); break; default: /* no conversion */ g_string_printf(value, "%"G_GSIZE_FORMAT, stored_value); break; } return value->str; } static inline void _append_formatted_label(GString *serialized_labels, const StatsClusterLabel *label) { if (!label->value) return; g_string_append_printf(serialized_labels, "%s=\"%s\"", stats_format_prometheus_sanitize_name(label->name), stats_format_prometheus_sanitize_label_value(label->value)); } static inline gboolean _is_timestamp(StatsCluster *sc, gint type) { return strcmp(stats_cluster_get_type_name(sc, type), "stamp") == 0; } static const gchar * _format_labels(StatsCluster *sc, gint type) { StatsClusterLabel type_label; gboolean needs_type_label = stats_cluster_get_type_label(sc, type, &type_label); if (!sc->key.labels_len && !needs_type_label) return NULL; GString *serialized_labels = scratch_buffers_alloc(); gboolean comma_needed = FALSE; for (gsize i = 0; i < sc->key.labels_len; ++i) { const StatsClusterLabel *label = &sc->key.labels[i]; if (_is_str_empty(label->value)) continue; if (comma_needed) g_string_append_c(serialized_labels, ','); else comma_needed = TRUE; _append_formatted_label(serialized_labels, label); } if (needs_type_label) { if (comma_needed) g_string_append_c(serialized_labels, ','); _append_formatted_label(serialized_labels, &type_label); } if (serialized_labels->len == 0) return NULL; return serialized_labels->str; } static GString * _format_legacy(StatsCluster *sc, gint type, StatsCounterItem *counter) { GString *record = scratch_buffers_alloc(); GString *labels = scratch_buffers_alloc(); gchar component[64]; g_string_append_printf(record, PROMETHEUS_METRIC_PREFIX "%s", stats_format_prometheus_sanitize_name(stats_cluster_get_component_name(sc, component, sizeof(component)))); if (!sc->key.legacy.component || sc->key.legacy.component == SCS_GLOBAL) { if (!_is_str_empty(sc->key.legacy.id)) g_string_append_printf(record, "_%s", stats_format_prometheus_sanitize_name(sc->key.legacy.id)); } else { gboolean has_id = !_is_str_empty(sc->key.legacy.id); if (has_id) g_string_append_printf(labels, "%s=\"%s\"", "id", stats_format_prometheus_sanitize_label_value(sc->key.legacy.id)); if (!_is_str_empty(sc->key.legacy.instance)) { if (has_id) g_string_append_c(labels, ','); g_string_append_printf(labels, "%s=\"%s\"", "stat_instance", stats_format_prometheus_sanitize_label_value(sc->key.legacy.instance)); } } const gchar *type_name = stats_cluster_get_type_name(sc, type); if (g_strcmp0(type_name, "value") != 0) g_string_append_printf(record, "_%s", stats_format_prometheus_sanitize_name(type_name)); if (labels->len != 0) g_string_append_printf(record, "{%s}", labels->str); const gchar *metric_value = stats_format_prometheus_format_value(&sc->key, &sc->counter_group.counters[type]); g_string_append_printf(record, " %s\n", metric_value); return record; } GString * stats_prometheus_format_counter(StatsCluster *sc, gint type, StatsCounterItem *counter) { if (_is_timestamp(sc, type)) return NULL; if (!sc->key.name) return _format_legacy(sc, type, counter); GString *record = scratch_buffers_alloc(); g_string_append_printf(record, PROMETHEUS_METRIC_PREFIX "%s", stats_format_prometheus_sanitize_name(sc->key.name)); const gchar *labels = _format_labels(sc, type); if (labels) g_string_append_printf(record, "{%s}", labels); const gchar *metric_value = stats_format_prometheus_format_value(&sc->key, &sc->counter_group.counters[type]); g_string_append_printf(record, " %s\n", metric_value); return record; } static void stats_format_prometheus(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { gpointer *args = (gpointer *) user_data; StatsPrometheusRecordFunc process_record = (StatsPrometheusRecordFunc) args[0]; gpointer process_record_arg = args[1]; gboolean with_legacy = GPOINTER_TO_INT(args[2]); if (!sc->key.name && !with_legacy) return; ScratchBuffersMarker marker; scratch_buffers_mark(&marker); GString *record = stats_prometheus_format_counter(sc, type, counter); if (!record) return; process_record(record->str, process_record_arg); scratch_buffers_reclaim_marked(marker); } void stats_generate_prometheus(StatsPrometheusRecordFunc process_record, gpointer user_data, gboolean with_legacy, gboolean *cancelled) { gpointer format_prometheus_args[] = {process_record, user_data, GINT_TO_POINTER(with_legacy)}; stats_lock(); stats_foreach_counter(stats_format_prometheus, format_prometheus_args, cancelled); stats_unlock(); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-prometheus.h000066400000000000000000000027261450431004300227660ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_PROMETHEUS_H_INCLUDED #define STATS_PROMETHEUS_H_INCLUDED 1 #include "syslog-ng.h" #include "stats-cluster.h" #define PROMETHEUS_METRIC_PREFIX "syslogng_" typedef void (*StatsPrometheusRecordFunc)(const char *record, gpointer user_data); GString *stats_prometheus_format_counter(StatsCluster *sc, gint type, StatsCounterItem *counter); void stats_generate_prometheus(StatsPrometheusRecordFunc process_record, gpointer user_data, gboolean with_legacy, gboolean *cancelled); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-query-commands.c000066400000000000000000000123121450431004300235220ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "messages.h" #include "stats-query-commands.h" #include "stats/stats-query.h" #include "control/control-connection.h" typedef enum _QueryCommand { QUERY_GET = 0, QUERY_GET_RESET, QUERY_GET_SUM, QUERY_GET_SUM_RESET, QUERY_LIST, QUERY_LIST_RESET, QUERY_CMD_MAX } QueryCommand; typedef gboolean (*query_cmd)(const gchar *filter_expr, GString *result); const gint CMD_STR = 0; const gint QUERY_CMD_STR = 1; const gint QUERY_FILTER_STR = 2; static void _append_reset_msg_if_found_matching_counters(gboolean found_match, GString *result) { if (found_match) { g_string_append_printf(result, "\n%s", "The selected counters of syslog-ng have been reset to 0."); } } static gboolean _ctl_format_get(StatsCounterItem *ctr, gpointer user_data) { GString *str = (GString *)user_data; g_string_append_printf(str, "%s=%"G_GSIZE_FORMAT"\n", stats_counter_get_name(ctr), stats_counter_get(ctr)); return TRUE; } static gboolean _ctl_format_name_without_value(StatsCounterItem *ctr, gpointer user_data) { GString *str = (GString *)user_data; g_string_append_printf(str, "%s\n", stats_counter_get_name(ctr)); return TRUE; } static gboolean _ctl_format_get_sum(gpointer user_data) { gpointer *args = (gpointer *) user_data; GString *result = (GString *) args[0]; gint64 *sum = (gint64 *) args[1]; g_string_printf(result, "%" G_GINT64_FORMAT "\n", *sum); return TRUE; } static gboolean _query_get(const gchar *filter_expr, GString *result) { return stats_query_get(filter_expr, _ctl_format_get, (gpointer)result); } static gboolean _query_get_and_reset(const gchar *filter_expr, GString *result) { gboolean found_match; found_match = stats_query_get_and_reset_counters(filter_expr, _ctl_format_get, (gpointer)result); _append_reset_msg_if_found_matching_counters(found_match, result); return found_match; } static gboolean _query_list(const gchar *filter_expr, GString *result) { return stats_query_list(filter_expr, _ctl_format_name_without_value, (gpointer)result); } static gboolean _query_list_and_reset(const gchar *filter_expr, GString *result) { gboolean found_match; found_match = stats_query_list_and_reset_counters(filter_expr, _ctl_format_name_without_value, (gpointer)result); _append_reset_msg_if_found_matching_counters(found_match, result); return found_match; } static gboolean _query_get_sum(const gchar *filter_expr, GString *result) { return stats_query_get_sum(filter_expr, _ctl_format_get_sum, (gpointer)result); } static gboolean _query_get_sum_and_reset(const gchar *filter_expr, GString *result) { gboolean found_match; found_match = stats_query_get_sum_and_reset_counters(filter_expr, _ctl_format_get_sum, (gpointer)result); _append_reset_msg_if_found_matching_counters(found_match, result); return found_match; } static QueryCommand _command_str_to_id(const gchar *cmd) { if (g_str_equal(cmd, "GET_SUM")) return QUERY_GET_SUM; if (g_str_equal(cmd, "GET_SUM_RESET")) return QUERY_GET_SUM_RESET; if (g_str_equal(cmd, "GET")) return QUERY_GET; if (g_str_equal(cmd, "GET_RESET")) return QUERY_GET_RESET; if (g_str_equal(cmd, "LIST")) return QUERY_LIST; if (g_str_equal(cmd, "LIST_RESET")) return QUERY_LIST_RESET; msg_error("Unknown query command", evt_tag_str("command", cmd)); return QUERY_CMD_MAX; } static query_cmd QUERY_CMDS[] = { _query_get, _query_get_and_reset, _query_get_sum, _query_get_sum_and_reset, _query_list, _query_list_and_reset }; static gboolean _dispatch_query(gint cmd_id, const gchar *filter_expr, GString *result) { if (cmd_id < QUERY_GET || cmd_id >= QUERY_CMD_MAX) { msg_error("Invalid query command", evt_tag_int("cmd_id", cmd_id), evt_tag_str("query", filter_expr)); return FALSE; } return QUERY_CMDS[cmd_id](filter_expr, result); } void process_query_command(ControlConnection *cc, GString *command, gpointer user_data, gboolean *cancelled) { GString *result = g_string_new(""); gchar **cmds = g_strsplit(command->str, " ", 3); g_assert(g_str_equal(cmds[CMD_STR], "QUERY")); _dispatch_query(_command_str_to_id(cmds[QUERY_CMD_STR]), cmds[QUERY_FILTER_STR], result); g_strfreev(cmds); if (result->len == 0) g_string_assign(result, "\n"); control_connection_send_reply(cc, result); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-query-commands.h000066400000000000000000000022341450431004300235310ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_QUERY_COMMANDS_H_INCLUDED #define STATS_QUERY_COMMANDS_H_INCLUDED #include "control/control.h" void process_query_command(ControlConnection *cc, GString *cmd, gpointer user_data, gboolean *cancelled); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-query.c000066400000000000000000000204621450431004300217300ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "messages.h" #include "stats-query.h" #include "stats-registry.h" #include "stats.h" #include static GHashTable *counter_index; static GMutex stats_query_mutex; static const gchar * _setup_filter_expression(const gchar *expr) { if (!expr || g_str_equal(expr, "")) return "*"; else return expr; } static gchar * _construct_counter_item_name(StatsCluster *sc, gint type) { return g_strdup_printf("%s.%s", sc->query_key, stats_cluster_get_type_name(sc, type)); } /* stats_query_mutex must be held */ static void _add_counter_to_index(StatsCluster *sc, gint type) { StatsCounterItem *counter = &sc->counter_group.counters[type]; gchar *counter_full_name = stats_counter_get_name(counter); if (counter_full_name == NULL) { counter_full_name = _construct_counter_item_name(sc, type); counter->name = counter_full_name; } g_hash_table_insert(counter_index, counter_full_name, counter); sc->indexed_mask |= (1 << type); } /* stats_query_mutex must be held */ static void _remove_counter_from_index(StatsCluster *sc, gint type) { gchar *key = stats_counter_get_name(&sc->counter_group.counters[type]); g_hash_table_remove(counter_index, key); sc->indexed_mask &= ~(1 << type); } /* stats_query_mutex must be held */ static void _index_counter(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { if (!stats_cluster_is_indexed(sc, type) && stats_cluster_is_alive(sc, type)) { _add_counter_to_index(sc, type); } else if (stats_cluster_is_indexed(sc, type) && !stats_cluster_is_alive(sc, type)) { _remove_counter_from_index(sc, type); } } /* stats_query_mutex must be held */ static void _update_indexes_of_cluster_if_needed(StatsCluster *sc, gpointer user_data) { stats_cluster_foreach_counter(sc, _index_counter, NULL); } static void _update_index(void) { g_mutex_lock(&stats_query_mutex); stats_lock(); stats_foreach_cluster(_update_indexes_of_cluster_if_needed, NULL, NULL); stats_unlock(); g_mutex_unlock(&stats_query_mutex); } static gboolean _is_pattern_matches_key(GPatternSpec *pattern, gpointer key) { gchar *counter_name = (gchar *) key; return g_pattern_match_string(pattern, counter_name); } static gboolean _is_single_match(const gchar *key_str) { return !strpbrk(key_str, "*?"); } static GList * _query_counter_hash(const gchar *key_str) { GPatternSpec *pattern = g_pattern_spec_new(key_str); GList *counters = NULL; gpointer key, value; GHashTableIter iter; gboolean single_match; _update_index(); single_match = _is_single_match(key_str); g_mutex_lock(&stats_query_mutex); g_hash_table_iter_init(&iter, counter_index); while (g_hash_table_iter_next(&iter, &key, &value)) { if (_is_pattern_matches_key(pattern, key)) { StatsCounterItem *counter = (StatsCounterItem *) value; counters = g_list_prepend(counters, counter); if (single_match) break; } } g_mutex_unlock(&stats_query_mutex); g_pattern_spec_free(pattern); return g_list_reverse(counters); } static GList * _get_counters(const gchar *key_str) { return _query_counter_hash(key_str); } static void _format_selected_counters(GList *counters, StatsFormatCb format_cb, gpointer result) { for (GList *counter = counters; counter; counter = counter->next) { StatsCounterItem *c = counter->data; format_cb(c, result); } } static void _reset_selected_counters(GList *counters) { GList *c; for (c = counters; c; c = c->next) { StatsCounterItem *counter = c->data; stats_counter_set(counter, 0); } } gboolean _stats_query_get(const gchar *expr, StatsFormatCb format_cb, gpointer result, gboolean must_reset) { if (!expr) return FALSE; gboolean found_match = FALSE; const gchar *key_str = _setup_filter_expression(expr); GList *counters = _get_counters(key_str); _format_selected_counters(counters, format_cb, result); if (must_reset) _reset_selected_counters(counters); if (g_list_length(counters) > 0) found_match = TRUE; g_list_free(counters); return found_match; } gboolean stats_query_get(const gchar *expr, StatsFormatCb format_cb, gpointer result) { return _stats_query_get(expr, format_cb, result, FALSE); } gboolean stats_query_get_and_reset_counters(const gchar *expr, StatsFormatCb format_cb, gpointer result) { return _stats_query_get(expr, format_cb, result, TRUE); } static gboolean _is_timestamp(gchar *counter_name) { gchar *last_dot = strrchr(counter_name, '.'); return (g_strcmp0(last_dot, ".stamp") == 0); } void _sum_selected_counters(GList *counters, gpointer user_data) { GList *c; gpointer *args = (gpointer *) user_data; gint64 *sum = (gint64 *) args[1]; for (c = counters; c; c = c->next) { StatsCounterItem *counter = c->data; if (!_is_timestamp(stats_counter_get_name(counter))) *sum += stats_counter_get(counter); } } gboolean _stats_query_get_sum(const gchar *expr, StatsSumFormatCb format_cb, gpointer result, gboolean must_reset) { if (!expr) return FALSE; gboolean found_match = FALSE; gint64 sum = 0; gpointer args[] = {result, &sum}; const gchar *key_str = _setup_filter_expression(expr); GList *counters = _get_counters(key_str); _sum_selected_counters(counters, (gpointer)args); if (counters) format_cb(args); if (must_reset) _reset_selected_counters(counters); if (g_list_length(counters) > 0) found_match = TRUE; g_list_free(counters); return found_match; } gboolean stats_query_get_sum(const gchar *expr, StatsSumFormatCb format_cb, gpointer result) { return _stats_query_get_sum(expr, format_cb, result, FALSE); } gboolean stats_query_get_sum_and_reset_counters(const gchar *expr, StatsSumFormatCb format_cb, gpointer result) { return _stats_query_get_sum(expr, format_cb, result, TRUE); } gboolean _stats_query_list(const gchar *expr, StatsFormatCb format_cb, gpointer result, gboolean must_reset) { gboolean found_match = FALSE; const gchar *key_str = _setup_filter_expression(expr); GList *counters = _get_counters(key_str); _format_selected_counters(counters, format_cb, result); if (must_reset) _reset_selected_counters(counters); if (g_list_length(counters) > 0) found_match = TRUE; g_list_free(counters); return found_match; } gboolean stats_query_list(const gchar *expr, StatsFormatCb format_cb, gpointer result) { return _stats_query_list(expr, format_cb, result, FALSE); } gboolean stats_query_list_and_reset_counters(const gchar *expr, StatsFormatCb format_cb, gpointer result) { return _stats_query_list(expr, format_cb, result, TRUE); } void stats_query_init(void) { counter_index = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); } void stats_query_deinit(void) { g_hash_table_destroy(counter_index); counter_index = NULL; } void stats_query_index_counter(StatsCluster *cluster, gint type) { g_mutex_lock(&stats_query_mutex); _add_counter_to_index(cluster, type); g_mutex_unlock(&stats_query_mutex); } static void _deindex_cluster_helper(StatsCluster *cluster, gint type, StatsCounterItem *item, gpointer user_data) { if (stats_cluster_is_indexed(cluster, type)) _remove_counter_from_index(cluster, type); } void stats_query_deindex_cluster(StatsCluster *cluster) { g_mutex_lock(&stats_query_mutex); stats_cluster_foreach_counter(cluster, _deindex_cluster_helper, NULL); g_mutex_unlock(&stats_query_mutex); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-query.h000066400000000000000000000037111450431004300217330ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_QUERY_H_INCLUDED #define STATS_QUERY_H_INCLUDED #include "stats-cluster.h" #include "syslog-ng.h" typedef gboolean (*StatsFormatCb)(StatsCounterItem *ctr, gpointer user_data); typedef gboolean (*StatsSumFormatCb)(gpointer user_data); gboolean stats_query_list(const gchar *expr, StatsFormatCb format_cb, gpointer result); gboolean stats_query_list_and_reset_counters(const gchar *expr, StatsFormatCb format_cb, gpointer result); gboolean stats_query_get(const gchar *expr, StatsFormatCb format_cb, gpointer result); gboolean stats_query_get_and_reset_counters(const gchar *expr, StatsFormatCb format_cb, gpointer result); gboolean stats_query_get_sum(const gchar *expr, StatsSumFormatCb format_cb, gpointer result); gboolean stats_query_get_sum_and_reset_counters(const gchar *expr, StatsSumFormatCb format_cb, gpointer result); void stats_query_init(void); void stats_query_deinit(void); void stats_query_index_counter(StatsCluster *cluster, gint type); void stats_query_deindex_cluster(StatsCluster *cluster); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats-registry.c000066400000000000000000000350031450431004300224300ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-registry.h" #include "stats/stats-query.h" #include "cfg.h" #include typedef struct _StatsClusterContainer { GHashTable *static_clusters; GHashTable *dynamic_clusters; } StatsClusterContainer; static StatsClusterContainer stats_cluster_container; static guint _number_of_dynamic_clusters(void) { return g_hash_table_size(stats_cluster_container.dynamic_clusters); } static GMutex stats_mutex; gboolean stats_locked; static void _insert_cluster(StatsCluster *sc) { if (sc->dynamic) g_hash_table_insert(stats_cluster_container.dynamic_clusters, &sc->key, sc); else g_hash_table_insert(stats_cluster_container.static_clusters, &sc->key, sc); } void stats_lock(void) { g_mutex_lock(&stats_mutex); stats_locked = TRUE; } void stats_unlock(void) { stats_locked = FALSE; g_mutex_unlock(&stats_mutex); } static StatsCluster * _grab_dynamic_cluster(const StatsClusterKey *sc_key) { StatsCluster *sc; sc = g_hash_table_lookup(stats_cluster_container.dynamic_clusters, sc_key); if (!sc) { if (!stats_check_dynamic_clusters_limit(_number_of_dynamic_clusters())) return NULL; sc = stats_cluster_dynamic_new(sc_key); _insert_cluster(sc); if ( !stats_check_dynamic_clusters_limit(_number_of_dynamic_clusters())) { msg_warning("Number of dynamic cluster limit has been reached.", evt_tag_int("allowed_clusters", stats_number_of_dynamic_clusters_limit())); } } return sc; } static StatsCluster * _grab_static_cluster(const StatsClusterKey *sc_key) { StatsCluster *sc; sc = g_hash_table_lookup(stats_cluster_container.static_clusters, sc_key); if (!sc) { sc = stats_cluster_new(sc_key); _insert_cluster(sc); } return sc; } static StatsCluster * _grab_cluster(gint stats_level, const StatsClusterKey *sc_key, gboolean dynamic) { if (!stats_check_level(stats_level)) return NULL; StatsCluster *sc = NULL; if (dynamic) sc = _grab_dynamic_cluster(sc_key); else sc = _grab_static_cluster(sc_key); if (!sc) return NULL; /* check that we are not overwriting a dynamic counter with a * non-dynamic one or vica versa. This could only happen if the same * key is used for both a dynamic counter and a non-dynamic one, which * is a programming error */ g_assert(sc->dynamic == dynamic); return sc; } static StatsCluster * _register_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, gboolean dynamic, StatsCounterItem **counter) { StatsCluster *sc; g_assert(stats_locked); sc = _grab_cluster(stats_level, sc_key, dynamic); if (sc) { StatsCounterItem *ctr = stats_cluster_get_counter(sc, type); *counter = stats_cluster_track_counter(sc, type); if (ctr && ctr->external) return sc; (*counter)->type = type; (*counter)->external = FALSE; } else { *counter = NULL; } return sc; } static void _assert_when_internal_or_stores_different_ref(StatsCluster *sc, gint type, atomic_gssize *external_counter) { StatsCounterItem *counter = stats_cluster_get_counter(sc, type); if (counter) { g_assert(counter->external && counter->value_ref == external_counter); } } static StatsCluster * _register_external_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, gboolean dynamic, atomic_gssize *external_counter) { StatsCluster *sc; if (!external_counter) return NULL; g_assert(stats_locked); sc = _grab_cluster(stats_level, sc_key, dynamic); if (sc) { _assert_when_internal_or_stores_different_ref(sc, type, external_counter); StatsCounterItem *ctr = stats_cluster_track_counter(sc, type); ctr->external = TRUE; ctr->value_ref = external_counter; ctr->type = type; } return sc; } /** * stats_register_counter: * @stats_level: the required statistics level to make this counter available * @component: a reference to the syslog-ng component that this counter belongs to (SCS_*) * @id: the unique identifier of the configuration item that this counter belongs to * @instance: if a given configuration item manages multiple similar counters * this makes those unique (like destination filename in case macros are used) * @type: the counter type (processed, dropped, etc) * @counter: returned pointer to the counter * * This function registers a general purpose counter. Whenever multiple * objects touch the same counter all of these should register the counter * with the same name. Internally the stats subsystem counts the number of * users of the same counter in this case, thus the counter will only be * freed when all of these uses are unregistered. **/ StatsCluster * stats_register_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter) { return _register_counter(stats_level, sc_key, type, FALSE, counter); } StatsCluster * stats_register_external_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, atomic_gssize *external_counter) { return _register_external_counter(stats_level, sc_key, type, FALSE, external_counter); } StatsCluster * stats_register_alias_counter(gint level, const StatsClusterKey *sc_key, gint type, StatsCounterItem *aliased_counter) { return stats_register_external_counter(level, sc_key, type, &aliased_counter->value); } StatsCluster * stats_register_counter_and_index(gint stats_level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter) { StatsCluster *cluster = _register_counter(stats_level, sc_key, type, FALSE, counter); if (cluster) stats_query_index_counter(cluster, type); return cluster; } StatsCluster * stats_register_dynamic_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter) { return _register_counter(stats_level, sc_key, type, TRUE, counter); } /* * stats_instant_inc_dynamic_counter * @timestamp: if non-negative, an associated timestamp will be created and set * * Instantly create (if not exists) and increment a dynamic counter. */ void stats_register_and_increment_dynamic_counter(gint stats_level, const StatsClusterKey *sc_key, time_t timestamp) { StatsCounterItem *counter, *stamp; StatsCluster *handle; g_assert(stats_locked); handle = stats_register_dynamic_counter(stats_level, sc_key, SC_TYPE_PROCESSED, &counter); if (!handle) return; stats_counter_inc(counter); if (timestamp >= 0) { stats_register_associated_counter(handle, SC_TYPE_STAMP, &stamp); stats_counter_set(stamp, timestamp); stats_unregister_dynamic_counter(handle, SC_TYPE_STAMP, &stamp); } stats_unregister_dynamic_counter(handle, SC_TYPE_PROCESSED, &counter); } /** * stats_register_associated_counter: * @sc: the dynamic counter that was registered with stats_register_dynamic_counter * @type: the type that we want to use in the same StatsCluster instance * @counter: the returned pointer to the counter itself * * This function registers another counter type in the same StatsCounter * instance in order to avoid an unnecessary lookup. **/ void stats_register_associated_counter(StatsCluster *sc, gint type, StatsCounterItem **counter) { g_assert(stats_locked); *counter = NULL; if (!sc) return; g_assert(sc->dynamic); *counter = stats_cluster_track_counter(sc, type); } void stats_unregister_counter(const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter) { StatsCluster *sc; g_assert(stats_locked); if (*counter == NULL) return; sc = g_hash_table_lookup(stats_cluster_container.static_clusters, sc_key); stats_cluster_untrack_counter(sc, type, counter); } void stats_unregister_external_counter(const StatsClusterKey *sc_key, gint type, atomic_gssize *external_counter) { StatsCluster *sc; if (!external_counter) return; g_assert(stats_locked); sc = g_hash_table_lookup(stats_cluster_container.static_clusters, sc_key); StatsCounterItem *ctr = stats_cluster_get_counter(sc, type); g_assert(ctr->value_ref == external_counter); stats_cluster_untrack_counter(sc, type, &ctr); } void stats_unregister_alias_counter(const StatsClusterKey *sc_key, gint type, StatsCounterItem *aliased_counter) { stats_unregister_external_counter(sc_key, type, &aliased_counter->value); } void stats_unregister_dynamic_counter(StatsCluster *sc, gint type, StatsCounterItem **counter) { g_assert(stats_locked); if (!sc) return; stats_cluster_untrack_counter(sc, type, counter); } StatsCluster * stats_get_cluster(const StatsClusterKey *sc_key) { g_assert(stats_locked); StatsCluster *sc = g_hash_table_lookup(stats_cluster_container.static_clusters, sc_key); if (!sc) sc = g_hash_table_lookup(stats_cluster_container.dynamic_clusters, sc_key); return sc; } gboolean stats_remove_cluster(const StatsClusterKey *sc_key) { g_assert(stats_locked); StatsCluster *sc; sc = g_hash_table_lookup(stats_cluster_container.dynamic_clusters, sc_key); if (sc) { if (stats_cluster_is_orphaned(sc)) return g_hash_table_remove(stats_cluster_container.dynamic_clusters, sc_key); return FALSE; } sc = g_hash_table_lookup(stats_cluster_container.static_clusters, sc_key); if (sc) { if (stats_cluster_is_orphaned(sc)) return g_hash_table_remove(stats_cluster_container.static_clusters, sc_key); return FALSE; } return FALSE; } gboolean stats_contains_counter(const StatsClusterKey *sc_key, gint type) { g_assert(stats_locked); StatsCluster *sc = stats_get_cluster(sc_key); if (!sc) { return FALSE; } return stats_cluster_is_alive(sc, type); } StatsCounterItem * stats_get_counter(const StatsClusterKey *sc_key, gint type) { g_assert(stats_locked); StatsCluster *sc = stats_get_cluster(sc_key); if (!sc) return NULL; return stats_cluster_get_counter(sc, type); } static void _foreach_cluster_helper(gpointer key, gpointer value, gpointer user_data) { gpointer *args = (gpointer *) user_data; StatsForeachClusterFunc func = args[0]; gpointer func_data = args[1]; StatsCluster *sc = (StatsCluster *) value; func(sc, func_data); } static void _foreach_cluster(GHashTable *clusters, gpointer *args, gboolean *cancelled) { GHashTableIter iter; g_hash_table_iter_init(&iter, clusters); gpointer key, value; while (g_hash_table_iter_next(&iter, &key, &value)) { if (cancelled && *cancelled) break; _foreach_cluster_helper(key, value, args); } } void stats_foreach_cluster(StatsForeachClusterFunc func, gpointer user_data, gboolean *cancelled) { gpointer args[] = { func, user_data }; g_assert(stats_locked); _foreach_cluster(stats_cluster_container.static_clusters, args, cancelled); _foreach_cluster(stats_cluster_container.dynamic_clusters, args, cancelled); } static gboolean _foreach_cluster_remove_helper(gpointer key, gpointer value, gpointer user_data) { gpointer *args = (gpointer *) user_data; StatsForeachClusterRemoveFunc func = args[0]; gpointer func_data = args[1]; StatsCluster *sc = (StatsCluster *) value; gboolean should_be_removed = func(sc, func_data) && stats_cluster_is_orphaned(sc); if (should_be_removed) stats_query_deindex_cluster(sc); return should_be_removed; } void stats_foreach_cluster_remove(StatsForeachClusterRemoveFunc func, gpointer user_data) { gpointer args[] = { func, user_data }; g_hash_table_foreach_remove(stats_cluster_container.static_clusters, _foreach_cluster_remove_helper, args); g_hash_table_foreach_remove(stats_cluster_container.dynamic_clusters, _foreach_cluster_remove_helper, args); } static void _foreach_counter_helper(StatsCluster *sc, gpointer user_data) { gpointer *args = (gpointer *) user_data; StatsForeachCounterFunc func = args[0]; gpointer func_data = args[1]; stats_cluster_foreach_counter(sc, func, func_data); } static void _foreach_legacy_counter_helper(StatsCluster *sc, gpointer user_data) { if (stats_cluster_key_is_legacy(&sc->key)) _foreach_counter_helper(sc, user_data); } void stats_foreach_counter(StatsForeachCounterFunc func, gpointer user_data, gboolean *cancelled) { gpointer args[] = { func, user_data }; g_assert(stats_locked); stats_foreach_cluster(_foreach_counter_helper, args, cancelled); } void stats_foreach_legacy_counter(StatsForeachCounterFunc func, gpointer user_data, gboolean *cancelled) { gpointer args[] = { func, user_data }; g_assert(stats_locked); stats_foreach_cluster(_foreach_legacy_counter_helper, args, cancelled); } void stats_registry_init(void) { stats_cluster_container.static_clusters = g_hash_table_new_full((GHashFunc) stats_cluster_key_hash, (GEqualFunc) stats_cluster_key_equal, NULL, (GDestroyNotify) stats_cluster_free); stats_cluster_container.dynamic_clusters = g_hash_table_new_full((GHashFunc) stats_cluster_key_hash, (GEqualFunc) stats_cluster_key_equal, NULL, (GDestroyNotify) stats_cluster_free); g_mutex_init(&stats_mutex); } void stats_registry_deinit(void) { g_hash_table_destroy(stats_cluster_container.static_clusters); g_hash_table_destroy(stats_cluster_container.dynamic_clusters); stats_cluster_container.static_clusters = NULL; stats_cluster_container.dynamic_clusters = NULL; g_mutex_clear(&stats_mutex); } syslog-ng-syslog-ng-4.4.0/lib/stats/stats-registry.h000066400000000000000000000073641450431004300224460ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_REGISTRY_H_INCLUDED #define STATS_REGISTRY_H_INCLUDED 1 #include "stats/stats.h" #include "stats/stats-cluster.h" typedef void (*StatsForeachClusterFunc)(StatsCluster *sc, gpointer user_data); typedef gboolean (*StatsForeachClusterRemoveFunc)(StatsCluster *sc, gpointer user_data); void stats_lock(void); void stats_unlock(void); gboolean stats_check_level(gint level); StatsCluster *stats_register_counter(gint level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter); StatsCluster *stats_register_external_counter(gint level, const StatsClusterKey *sc_key, gint type, atomic_gssize *external_counter); StatsCluster *stats_register_alias_counter(gint level, const StatsClusterKey *sc_key, gint type, StatsCounterItem *aliased_counter); StatsCluster *stats_register_counter_and_index(gint level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter); StatsCluster *stats_register_dynamic_counter(gint stats_level, const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter); void stats_register_and_increment_dynamic_counter(gint stats_level, const StatsClusterKey *sc_key, time_t timestamp); void stats_register_associated_counter(StatsCluster *handle, gint type, StatsCounterItem **counter); void stats_unregister_counter(const StatsClusterKey *sc_key, gint type, StatsCounterItem **counter); void stats_unregister_external_counter(const StatsClusterKey *sc_key, gint type, atomic_gssize *external_counter); void stats_unregister_alias_counter(const StatsClusterKey *sc_key, gint type, StatsCounterItem *aliased_counter); void stats_unregister_dynamic_counter(StatsCluster *handle, gint type, StatsCounterItem **counter); gboolean stats_contains_counter(const StatsClusterKey *sc_key, gint type); StatsCounterItem *stats_get_counter(const StatsClusterKey *sc_key, gint type); StatsCluster *stats_get_cluster(const StatsClusterKey *sc_key); gboolean stats_remove_cluster(const StatsClusterKey *sc_key); void stats_foreach_counter(StatsForeachCounterFunc func, gpointer user_data, gboolean *cancelled); void stats_foreach_legacy_counter(StatsForeachCounterFunc func, gpointer user_data, gboolean *cancelled); void stats_foreach_cluster(StatsForeachClusterFunc func, gpointer user_data, gboolean *cancelled); void stats_foreach_cluster_remove(StatsForeachClusterRemoveFunc func, gpointer user_data); void stats_registry_init(void); void stats_registry_deinit(void); gboolean stats_check_dynamic_clusters_limit(guint number_of_clusters); gint stats_number_of_dynamic_clusters_limit(void); CfgYesNoAuto stats_syslog_stats(void); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/stats.c000066400000000000000000000200531450431004300205610ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stats/stats-control.h" #include "stats/stats-log.h" #include "stats/stats-query.h" #include "stats/stats-registry.h" #include "stats/aggregator/stats-aggregator-registry.h" #include "stats/stats.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include "cfg-parser.h" #include #include /* * The statistics module * * Various components of syslog-ng require counters to keep track of various * metrics, such as number of messages processed, dropped or stored in a * queue. For this purpose, this module provides an easy to use API to * register and keep track these counters, and also to publish them to * external programs via a UNIX domain socket. * * Counters are organized into clusters, as the same syslog-ng component * usually uses a set of related counters. Each counter is typed (see * SC_TYPE_XXX enums), the most common is SC_TYPE_PROCESSED, which is merely * counts the number of messages being processed by a source/destination/etc. * * Each cluster has the following properties: * * source component: enumerable type, that specifies the syslog-ng * component that the given counter belongs to, examples: * src.file, dst.file, center, src.socket, etc. * * * id: the unique identifier of the syslog-ng configuration item that * this counter belongs to. Named configuration elements (source, * destination, etc) use their "name" here. Other components without a * name use either an autogenerated ID (that can change when the * configuration file changes), or an explicit ID configured by the * administrator. * * * instance: each configuration element may track several sets of * counters. This field specifies an identifier that makes a group of * counters unique. For instance: * - source TCP drivers use the IP address of the client here * - destination file writers use the expanded filename * - for those which have no notion for instance, NULL is used * * * state: dynamic, active or orphaned, this indicates whether the given * counter is in use or in orphaned state * * * type: counter type (processed, dropped, stored, etc) * * Threading * * Registration and unregistration must be protected expicitly by invoking * stats_lock()/unlock(). Once registered, counters can be manipulated * without acquiring stats_lock(). * * Counters are updated atomically by the use of the stats_counter_inc/dec() * methods. */ static gboolean stats_cluster_is_expired(StatsOptions *options, StatsCluster *sc, time_t now) { time_t tstamp; /* check if dynamic entry, non-dynamic entries cannot be too large in * numbers, those are never pruned */ if (!sc->dynamic) return FALSE; /* this entry is being updated, cannot be too old */ if (!stats_cluster_is_orphaned(sc)) return FALSE; /* check if timestamp is stored, no timestamp means we can't expire it. * All dynamic entries should have a timestamp. */ if ((sc->live_mask & (1 << SC_TYPE_STAMP)) == 0) return FALSE; tstamp = atomic_gssize_racy_get(&(sc->counter_group.counters[SC_TYPE_STAMP].value)); return (tstamp <= now - options->lifetime); } typedef struct _StatsTimerState { GTimeVal now; time_t oldest_counter; gint dropped_counters; EVTREC *stats_event; StatsOptions *options; } StatsTimerState; static gboolean stats_prune_cluster(StatsCluster *sc, StatsTimerState *st) { gboolean expired; expired = stats_cluster_is_expired(st->options, sc, st->now.tv_sec); if (expired) { time_t tstamp = atomic_gssize_racy_get(&(sc->counter_group.counters[SC_TYPE_STAMP].value)); if ((st->oldest_counter) == 0 || st->oldest_counter > tstamp) st->oldest_counter = tstamp; st->dropped_counters++; } return expired; } static gboolean stats_format_and_prune_cluster(StatsCluster *sc, gpointer user_data) { StatsTimerState *st = (StatsTimerState *) user_data; if (st->stats_event) stats_log_format_cluster(sc, st->stats_event); return stats_prune_cluster(sc, st); } void stats_publish_and_prune_counters(StatsOptions *options) { StatsTimerState st; gboolean publish = (options->log_freq > 0); st.oldest_counter = 0; st.dropped_counters = 0; st.stats_event = NULL; st.options = options; cached_g_current_time(&st.now); if (publish) st.stats_event = msg_event_create(EVT_PRI_INFO, "Log statistics", NULL); stats_lock(); stats_foreach_cluster_remove(stats_format_and_prune_cluster, &st); stats_unlock(); if (publish) msg_event_send(st.stats_event); if (st.dropped_counters > 0) { msg_notice("Pruning stats-counters have finished", evt_tag_int("dropped", st.dropped_counters), evt_tag_long("oldest-timestamp", (long) st.oldest_counter)); } } static void stats_timer_rearm(StatsOptions *options, struct iv_timer *timer) { glong freq = options->log_freq; if (!freq) freq = options->lifetime <= 1 ? 1 : options->lifetime / 2; if (freq > 0) { /* arm the timer */ iv_validate_now(); timer->expires = iv_now; timespec_add_msec(&timer->expires, freq * 1000); iv_timer_register(timer); } } static void stats_timer_init(struct iv_timer *timer, void (*handler)(void *), StatsOptions *options) { IV_TIMER_INIT(timer); timer->handler = handler; timer->cookie = options; } static void stats_timer_kill(struct iv_timer *timer) { if (!timer->handler) return; if (iv_timer_registered(timer)) iv_timer_unregister(timer); } static struct iv_timer stats_timer; static void stats_timer_elapsed(gpointer st) { StatsOptions *options = (StatsOptions *) st; stats_publish_and_prune_counters(options); stats_timer_rearm(options, &stats_timer); } void stats_timer_reinit(StatsOptions *options) { stats_timer_kill(&stats_timer); stats_timer_init(&stats_timer, stats_timer_elapsed, options); stats_timer_rearm(options, &stats_timer); } static StatsOptions *stats_options; void stats_reinit(StatsOptions *options) { stats_options = options; stats_timer_reinit(options); } void stats_init(void) { stats_cluster_init(); stats_registry_init(); stats_aggregator_registry_init(); stats_query_init(); } void stats_destroy(void) { stats_query_deinit(); stats_aggregator_registry_deinit(); stats_registry_deinit(); stats_cluster_deinit(); } void stats_options_defaults(StatsOptions *options) { options->level = 0; options->log_freq = 600; options->lifetime = 600; options->max_dynamic = -1; options->syslog_stats = CYNA_AUTO; } gboolean stats_check_level(gint level) { if (stats_options) return (stats_options->level >= level); else return level == 0; } gboolean stats_check_dynamic_clusters_limit(guint number_of_clusters) { if (!stats_options) return TRUE; if (stats_options->max_dynamic == -1) return TRUE; return (stats_options->max_dynamic > number_of_clusters); } gint stats_number_of_dynamic_clusters_limit(void) { if (!stats_options) return -1; return stats_options->max_dynamic; } CfgYesNoAuto stats_syslog_stats(void) { if (stats_options) return (stats_options->syslog_stats); return CYNA_AUTO; } syslog-ng-syslog-ng-4.4.0/lib/stats/stats.h000066400000000000000000000027511450431004300205730ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STATS_H_INCLUDED #define STATS_H_INCLUDED #include "syslog-ng.h" #include "stats/stats-cluster.h" #include "cfg-parser.h" typedef struct _StatsOptions { gint log_freq; gint level; gint lifetime; gint max_dynamic; CfgYesNoAuto syslog_stats; } StatsOptions; enum { STATS_LEVEL0 = 0, STATS_LEVEL1, STATS_LEVEL2, STATS_LEVEL3 }; void stats_reinit(StatsOptions *options); void stats_init(void); void stats_destroy(void); void stats_options_defaults(StatsOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/stats/tests/000077500000000000000000000000001450431004300204215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/stats/tests/CMakeLists.txt000066400000000000000000000005771450431004300231720ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_stats_cluster) add_unit_test(CRITERION TARGET test_stats_query) add_unit_test(CRITERION TARGET test_dynamic_ctr_reg) add_unit_test(CRITERION TARGET test_external_ctr_reg) add_unit_test(CRITERION TARGET test_alias_ctr_reg) add_unit_test(LIBTEST CRITERION TARGET test_stats_prometheus) add_unit_test(CRITERION TARGET test_stats_cluster_key_builder) syslog-ng-syslog-ng-4.4.0/lib/stats/tests/Makefile.am000066400000000000000000000031621450431004300224570ustar00rootroot00000000000000lib_stats_tests_TESTS = \ lib/stats/tests/test_stats_cluster EXTRA_DIST += lib/stats/tests/CMakeLists.txt check_PROGRAMS += ${lib_stats_tests_TESTS} lib_stats_tests_test_stats_cluster_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/stats/tests lib_stats_tests_test_stats_cluster_LDADD = $(TEST_LDADD) lib_stats_tests_test_stats_cluster_SOURCES = \ lib/stats/tests/test_stats_cluster.c stats_test_extra_modules = \ $(PREOPEN_SYSLOGFORMAT) lib_stats_tests_TESTS += \ lib/stats/tests/test_stats_query \ lib/stats/tests/test_dynamic_ctr_reg \ lib/stats/tests/test_external_ctr_reg \ lib/stats/tests/test_alias_ctr_reg \ lib/stats/tests/test_stats_prometheus \ lib/stats/tests/test_stats_cluster_key_builder lib_stats_tests_test_stats_query_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_stats_query_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) lib_stats_tests_test_dynamic_ctr_reg_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_dynamic_ctr_reg_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) lib_stats_tests_test_external_ctr_reg_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_external_ctr_reg_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) lib_stats_tests_test_alias_ctr_reg_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_alias_ctr_reg_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) lib_stats_tests_test_stats_prometheus_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_stats_prometheus_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) lib_stats_tests_test_stats_cluster_key_builder_CFLAGS = $(TEST_CFLAGS) lib_stats_tests_test_stats_cluster_key_builder_LDADD = \ $(TEST_LDADD) $(stats_test_extra_modules) syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_alias_ctr_reg.c000066400000000000000000000061061450431004300244250ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" #include "logmsg/logmsg.h" #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "stats/stats-counter.h" #include "stats/stats-query.h" #include "stats/stats-registry.h" #include #include TestSuite(stats_alias_counter, .init = app_startup, .fini = app_shutdown); Test(stats_alias_counter, register_ctr) { StatsCounterItem *counter = NULL; StatsCounterItem *alias_counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr.alias", NULL); StatsCluster *sc = stats_register_alias_counter(0, &sc_key, SC_TYPE_PROCESSED, counter); cr_assert_not_null(sc); alias_counter = stats_cluster_get_counter(sc, SC_TYPE_PROCESSED); } stats_unlock(); cr_expect(alias_counter->external); cr_expect_eq(&counter->value, alias_counter->value_ref); stats_counter_set(counter, 12); cr_expect_eq(stats_counter_get(alias_counter), 12); stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr.alias", NULL); stats_unregister_alias_counter(&sc_key, SC_TYPE_PROCESSED, counter); stats_counter_dec(counter); cr_expect_eq(stats_counter_get(counter), 11); StatsCluster *sc = stats_register_alias_counter(0, &sc_key, SC_TYPE_PROCESSED, counter); alias_counter = stats_cluster_get_counter(sc, SC_TYPE_PROCESSED); cr_expect(alias_counter->external); cr_expect_eq(&counter->value, alias_counter->value_ref); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &counter); cr_expect_eq(stats_counter_get(alias_counter), 11); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); stats_counter_inc(counter); cr_expect_eq(stats_counter_get(alias_counter), 12); } stats_unlock(); } syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_dynamic_ctr_reg.c000066400000000000000000000061101450431004300247530ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "apphook.h" #include "logmsg/logmsg.h" #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "stats/stats-counter.h" #include "stats/stats-query.h" #include "stats/stats-registry.h" #include #include TestSuite(stats_dynamic_clusters, .init = app_startup, .fini = app_shutdown); Test(stats_dynamic_clusters, unlimited_by_default) { StatsOptions stats_opts; stats_options_defaults(&stats_opts); stats_reinit(&stats_opts); cr_assert_eq(stats_check_dynamic_clusters_limit(0), TRUE); cr_assert_eq(stats_check_dynamic_clusters_limit(UINT_MAX), TRUE); } Test(stats_dynamic_clusters, limited) { StatsOptions stats_opts; stats_options_defaults(&stats_opts); stats_opts.max_dynamic = 2; stats_reinit(&stats_opts); cr_assert_eq(stats_check_dynamic_clusters_limit(0), TRUE); cr_assert_eq(stats_check_dynamic_clusters_limit(1), TRUE); cr_assert_eq(stats_check_dynamic_clusters_limit(2), FALSE); } Test(stats_dynamic_clusters, register_limited) { StatsOptions stats_opts; stats_options_defaults(&stats_opts); stats_opts.level = 3; stats_opts.max_dynamic = 2; stats_reinit(&stats_opts); stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_HOST | SCS_SENDER, NULL, "testhost1"); StatsCounterItem *counter = NULL; StatsCluster *sc = stats_register_dynamic_counter(1, &sc_key, SC_TYPE_PROCESSED, &counter); cr_assert_not_null(sc); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_HOST | SCS_SENDER, NULL, "testhost2"); sc = stats_register_dynamic_counter(1, &sc_key, SC_TYPE_PROCESSED, &counter); cr_assert_not_null(sc); cr_assert_eq(stats_contains_counter(&sc_key, SC_TYPE_PROCESSED), TRUE); cr_assert_eq(counter, stats_get_counter(&sc_key, SC_TYPE_PROCESSED)); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_HOST | SCS_SENDER, NULL, "testhost3"); sc = stats_register_dynamic_counter(1, &sc_key, SC_TYPE_PROCESSED, &counter); cr_assert_null(sc); cr_expect_not(stats_contains_counter(&sc_key, SC_TYPE_PROCESSED)); } stats_unlock(); } syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_external_ctr_reg.c000066400000000000000000000226431450431004300251620ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * Copyright (c) 2019 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" #include "logmsg/logmsg.h" #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "stats/stats-counter.h" #include "stats/stats-query.h" #include "stats/stats-registry.h" #include #include TestSuite(stats_external_counter, .init = app_startup, .fini = app_shutdown); Test(stats_external_counter, register_logpipe_cluster_ctr) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); StatsCluster *sc = stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); cr_assert_not_null(sc); counter = stats_cluster_get_counter(sc, SC_TYPE_PROCESSED); } stats_unlock(); cr_expect_eq(atomic_gssize_get(&test_ctr), 11); cr_expect_eq(&test_ctr, counter->value_ref); cr_expect_eq(stats_counter_get(counter), 11); } static StatsCounterItem * _register_external_stats_counter(atomic_gssize *ctr, gssize initial_value) { StatsCounterItem *counter = NULL; atomic_gssize_set(ctr, initial_value); stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); StatsCluster *sc = stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, ctr); counter = stats_cluster_get_counter(sc, SC_TYPE_PROCESSED); cr_assert_not_null(sc); } stats_unlock(); return counter; } Test(stats_external_counter, external_ctr_is_read_only_for_stats_set) { atomic_gssize test_ctr; StatsCounterItem *stats_ctr = _register_external_stats_counter(&test_ctr, 11); stats_counter_set(stats_ctr, 1); cr_expect_eq(stats_counter_get(stats_ctr), 11); }; Test(stats_external_counter, external_ctr_is_read_only_for_stats_inc, .signal=SIGABRT) { atomic_gssize test_ctr; StatsCounterItem *stats_ctr = _register_external_stats_counter(&test_ctr, 11); stats_counter_inc(stats_ctr); }; Test(stats_external_counter, external_ctr_is_read_only_for_stats_dec, .signal=SIGABRT) { atomic_gssize test_ctr; StatsCounterItem *stats_ctr = _register_external_stats_counter(&test_ctr, 11); stats_counter_dec(stats_ctr); }; Test(stats_external_counter, external_ctr_is_read_only_for_stats_add, .signal=SIGABRT) { atomic_gssize test_ctr; StatsCounterItem *stats_ctr = _register_external_stats_counter(&test_ctr, 11); stats_counter_add(stats_ctr, 1); }; Test(stats_external_counter, external_ctr_is_read_only_for_stats_sub, .signal=SIGABRT) { atomic_gssize test_ctr; StatsCounterItem *stats_ctr = _register_external_stats_counter(&test_ctr, 11); stats_counter_sub(stats_ctr, 1); }; Test(stats_external_counter, reset_counter_is_disabled_for_external_counters) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); StatsCluster *sc = stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); counter = stats_cluster_get_counter(sc, SC_TYPE_PROCESSED); cr_expect_eq(&sc->counter_group.counters[SC_TYPE_PROCESSED], counter); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &counter); cr_expect_null(counter); cr_expect_neq(sc->counter_group.counters[SC_TYPE_PROCESSED].value_ref, &test_ctr); atomic_gssize *embedded_ctr = &(sc->counter_group.counters[SC_TYPE_PROCESSED].value); cr_expect_eq(atomic_gssize_get(embedded_ctr), 0); cr_expect_eq(atomic_gssize_get(&test_ctr), 11); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); cr_expect_eq(counter->value_ref, &test_ctr); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); cr_expect_eq(&test_ctr, counter->value_ref); } stats_unlock(); } Test(stats_external_counter, register_same_ctr_as_internal_after_external_unregistered) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &counter); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); cr_expect_neq(counter->value_ref, &test_ctr); stats_counter_inc(counter); cr_expect_eq(stats_counter_get(counter), 1); } stats_unlock(); } Test(stats_external_counter, register_same_ctr_as_external_after_internal_unregistered, .signal = SIGABRT) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &counter); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &counter); // assert, SIGABRT: stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); // this is because we are not unset the live mask even when the use_ctr is 0... // I'm not sure if it is correct, but we have other unit tests, where we expect the same behaviour /* counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); cr_expect_eq(counter->value_ref, &test_ctr); stats_counter_inc(counter); cr_expect_eq(stats_counter_get(counter), 11); atomic_gssize_inc(&test_ctr); cr_expect_eq(stats_counter_get(counter), 12);*/ } stats_unlock(); } Test(stats_external_counter, re_register_internal_ctr_as_external, .signal = SIGABRT) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *internal_counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &internal_counter); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &internal_counter); cr_expect_null(internal_counter); // assert, SIGABRT: stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); } stats_unlock(); } Test(stats_external_counter, re_register_external_ctr_as_internal) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *external_counter = NULL, *internal_counter = NULL, *tmp_counter = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", "counter"); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); tmp_counter = external_counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &internal_counter); cr_expect_eq(internal_counter, external_counter); stats_unregister_external_counter(&sc_key, SC_TYPE_PROCESSED, &test_ctr); external_counter = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); cr_expect_not_null(external_counter); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &internal_counter); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &internal_counter); stats_unregister_counter(&sc_key, SC_TYPE_PROCESSED, &tmp_counter); stats_register_counter(0, &sc_key, SC_TYPE_PROCESSED, &internal_counter); stats_counter_inc(internal_counter); cr_expect_eq(stats_counter_get(internal_counter), 1); } stats_unlock(); } Test(stats_external_counter, re_register_external_ctr) { atomic_gssize test_ctr; atomic_gssize_set(&test_ctr, 11); StatsCounterItem *counter1 = NULL, *counter2 = NULL; stats_lock(); { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_GLOBAL, "test_ctr", NULL); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); stats_register_external_counter(0, &sc_key, SC_TYPE_PROCESSED, &test_ctr); counter1 = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); counter2 = stats_get_counter(&sc_key, SC_TYPE_PROCESSED); cr_expect_eq(counter1, counter2); cr_expect_eq(counter1->value_ref, &test_ctr); } stats_unlock(); } syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_stats_cluster.c000066400000000000000000000325101450431004300245240ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "apphook.h" guint SCS_FILE; static void setup(void) { app_startup(); SCS_FILE = stats_register_type("file"); } Test(stats_cluster, test_stats_cluster_single) { StatsCluster *sc; StatsClusterKey sc_key; stats_cluster_single_key_legacy_set(&sc_key, SCS_GLOBAL, "logmsg_allocated_bytes", NULL); sc = stats_cluster_new(&sc_key); cr_assert_str_eq(sc->query_key, "global.logmsg_allocated_bytes", "Unexpected query key"); cr_assert_eq(sc->counter_group.capacity, 1, "Invalid group capacity"); stats_cluster_free(sc); } Test(stats_cluster, test_stats_cluster_single_with_name_with_heap_allocated_string) { const gchar *string_literal_name = "test_name"; StatsCluster *sc; StatsClusterKey sc_key; GString *heap_allocated_name = g_string_new(string_literal_name); stats_cluster_single_key_legacy_set_with_name(&sc_key, SCS_GLOBAL, "id", "instance", heap_allocated_name->str); sc = stats_cluster_new(&sc_key); g_string_truncate(heap_allocated_name, 0); g_string_free(heap_allocated_name, TRUE); cr_assert_str_eq(sc->counter_group.counter_names[0], string_literal_name, "Unexpected counter name: %s", sc->counter_group.counter_names[0]); stats_cluster_free(sc); } Test(stats_cluster, test_stats_cluster_new_replaces_NULL_with_an_empty_string) { StatsCluster *sc; StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, NULL, NULL ); sc = stats_cluster_new(&sc_key); cr_assert_str_eq(sc->key.legacy.id, "", "StatsCluster->id is not properly defaulted to an empty string"); cr_assert_str_eq(sc->key.legacy.instance, "", "StatsCluster->instance is not properly defaulted to an empty string"); stats_cluster_free(sc); } static void assert_stats_cluster_equals(StatsCluster *sc1, StatsCluster *sc2) { cr_assert(stats_cluster_key_equal(&sc1->key, &sc2->key), "unexpected unequal StatsClusters"); } static void assert_stats_cluster_mismatches(StatsCluster *sc1, StatsCluster *sc2) { cr_assert_not(stats_cluster_key_equal(&sc1->key, &sc2->key), "unexpected equal StatsClusters"); } static void assert_stats_cluster_equals_and_free(StatsCluster *sc1, StatsCluster *sc2) { assert_stats_cluster_equals(sc1, sc2); stats_cluster_free(sc1); stats_cluster_free(sc2); } static void assert_stats_cluster_mismatches_and_free(StatsCluster *sc1, StatsCluster *sc2) { assert_stats_cluster_mismatches(sc1, sc2); stats_cluster_free(sc1); stats_cluster_free(sc2); } Test(stats_cluster, test_stats_cluster_equal_if_component_id_and_instance_are_the_same) { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance" ); assert_stats_cluster_equals_and_free(stats_cluster_new(&sc_key), stats_cluster_new(&sc_key)); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance1" ); StatsClusterKey sc_key2; stats_cluster_logpipe_key_legacy_set(&sc_key2, SCS_SOURCE | SCS_FILE, "id", "instance2" ); assert_stats_cluster_mismatches_and_free(stats_cluster_new(&sc_key), stats_cluster_new(&sc_key2)); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id1", "instance" ); stats_cluster_logpipe_key_legacy_set(&sc_key2, SCS_SOURCE | SCS_FILE, "id2", "instance" ); assert_stats_cluster_mismatches_and_free(stats_cluster_new(&sc_key), stats_cluster_new(&sc_key2)); stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance" ); stats_cluster_logpipe_key_legacy_set(&sc_key2, SCS_DESTINATION | SCS_FILE, "id", "instance" ); assert_stats_cluster_mismatches_and_free(stats_cluster_new(&sc_key), stats_cluster_new(&sc_key2)); } Test(stats_cluster, test_stats_cluster_key_not_equal_when_custom_tags_are_different) { StatsClusterKey sc_key1; StatsClusterKey sc_key2; stats_cluster_single_key_legacy_set_with_name(&sc_key1, SCS_SOURCE | SCS_FILE, "id", "instance", "name1"); stats_cluster_single_key_legacy_set_with_name(&sc_key2, SCS_SOURCE | SCS_FILE, "id", "instance", "name2"); StatsCluster *sc1 = stats_cluster_new(&sc_key1); StatsCluster *sc2 = stats_cluster_new(&sc_key2); cr_assert_not(stats_cluster_key_equal(&sc_key1, &sc_key2), "%s", __FUNCTION__); stats_cluster_free(sc1); stats_cluster_free(sc2); } Test(stats_cluster, test_stats_cluster_key_equal_when_custom_tags_are_the_same) { StatsClusterKey sc_key1; StatsClusterKey sc_key2; stats_cluster_single_key_legacy_set_with_name(&sc_key1, SCS_SOURCE | SCS_FILE, "id", "instance", "name"); stats_cluster_single_key_legacy_set_with_name(&sc_key2, SCS_SOURCE | SCS_FILE, "id", "instance", "name"); StatsCluster *sc1 = stats_cluster_new(&sc_key1); StatsCluster *sc2 = stats_cluster_new(&sc_key2); cr_assert(stats_cluster_key_equal(&sc_key1, &sc_key2), "%s", __FUNCTION__); stats_cluster_free(sc1); stats_cluster_free(sc2); } static inline void assert_key_equal(StatsClusterKey k1, StatsClusterKey k2, gboolean equal) { StatsClusterKey key1, key2; stats_cluster_logpipe_key_set(&key1, k1.name, k1.labels, k1.labels_len); stats_cluster_logpipe_key_set(&key2, k2.name, k2.labels, k2.labels_len); cr_assert_eq(stats_cluster_key_equal(&key1, &key2), equal); cr_assert_eq(stats_cluster_key_hash(&key1) == stats_cluster_key_hash(&key2), equal); } static inline StatsClusterKey test_cluster_key(const gchar *name, StatsClusterLabel *labels, gsize labels_len) { return (StatsClusterKey) { .name = name, .labels = labels, .labels_len = labels_len }; } Test(stats_cluster, test_stats_cluster_key) { StatsClusterLabel labels1[] = { stats_cluster_label("app", "cisco"), stats_cluster_label("sourceip", "127.0.0.1"), stats_cluster_label("customlabel", "value"), }; StatsClusterLabel labels2[] = { stats_cluster_label("app", "cisco") }; assert_key_equal(test_cluster_key("name", NULL, 0), test_cluster_key("name", NULL, 0), TRUE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), TRUE); assert_key_equal(test_cluster_key("name", labels2, G_N_ELEMENTS(labels2)), test_cluster_key("name", labels2, G_N_ELEMENTS(labels2)), TRUE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name", NULL, 0), FALSE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name", labels2, G_N_ELEMENTS(labels2)), FALSE); assert_key_equal(test_cluster_key("name", NULL, 0), test_cluster_key("name2", NULL, 0), FALSE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name2", labels1, G_N_ELEMENTS(labels1)), FALSE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name2", NULL, 0), FALSE); assert_key_equal(test_cluster_key("name", labels1, G_N_ELEMENTS(labels1)), test_cluster_key("name2", labels2, G_N_ELEMENTS(labels2)), FALSE); } Test(stats_cluster, test_stats_cluster_key_legacy_alias) { StatsClusterKey key1, key2, key3; stats_cluster_logpipe_key_set(&key1, "name", NULL, 0); stats_cluster_logpipe_key_add_legacy_alias(&key1, SCS_FILE, "id", "instance"); stats_cluster_logpipe_key_set(&key2, "name2", NULL, 0); stats_cluster_logpipe_key_add_legacy_alias(&key2, SCS_FILE, "id2", "instance"); stats_cluster_logpipe_key_set(&key3, "name", NULL, 0); cr_assert(stats_cluster_key_equal(&key1, &key1)); cr_assert_eq(stats_cluster_key_hash(&key1), stats_cluster_key_hash(&key1)); cr_assert_not(stats_cluster_key_equal(&key1, &key2)); cr_assert_neq(stats_cluster_key_hash(&key1), stats_cluster_key_hash(&key2)); cr_assert_not(stats_cluster_key_equal(&key1, &key3)); cr_assert_neq(stats_cluster_key_hash(&key1), stats_cluster_key_hash(&key3)); } typedef struct _ValidateCountersState { gint type1; va_list types; gint validate_count; } ValidateCountersState; static void _validate_yielded_counters(StatsCluster *sc, gint type, StatsCounterItem *counter, gpointer user_data) { ValidateCountersState *st = (ValidateCountersState *) user_data; gint t; t = va_arg(st->types, gint); cr_assert_geq(t, 0, "foreach counter returned a new counter, but we expected the end already"); cr_assert_eq(type, t, "Counter type mismatch"); st->validate_count++; } static void assert_stats_foreach_yielded_counters_matches(StatsCluster *sc, ...) { ValidateCountersState st; va_list va; gint type_count = 0; gint t; va_start(va, sc); st.validate_count = 0; va_copy(st.types, va); t = va_arg(va, gint); while (t >= 0) { type_count++; t = va_arg(va, gint); } stats_cluster_foreach_counter(sc, _validate_yielded_counters, &st); va_end(va); cr_assert_eq(type_count, st.validate_count, "the number of validated counters mismatch the expected size"); } Test(stats_cluster, test_stats_foreach_counter_yields_tracked_counters) { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance" ); StatsCluster *sc = stats_cluster_new(&sc_key); assert_stats_foreach_yielded_counters_matches(sc, -1); stats_cluster_track_counter(sc, SC_TYPE_PROCESSED); assert_stats_foreach_yielded_counters_matches(sc, SC_TYPE_PROCESSED, -1); stats_cluster_track_counter(sc, SC_TYPE_STAMP); assert_stats_foreach_yielded_counters_matches(sc, SC_TYPE_PROCESSED, SC_TYPE_STAMP, -1); stats_cluster_free(sc); } Test(stats_cluster, test_stats_foreach_counter_never_forgets_untracked_counters) { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance" ); StatsCluster *sc = stats_cluster_new(&sc_key); StatsCounterItem *processed, *stamp; processed = stats_cluster_track_counter(sc, SC_TYPE_PROCESSED); stamp = stats_cluster_track_counter(sc, SC_TYPE_STAMP); stats_cluster_untrack_counter(sc, SC_TYPE_PROCESSED, &processed); assert_stats_foreach_yielded_counters_matches(sc, SC_TYPE_PROCESSED, SC_TYPE_STAMP, -1); stats_cluster_untrack_counter(sc, SC_TYPE_STAMP, &stamp); assert_stats_foreach_yielded_counters_matches(sc, SC_TYPE_PROCESSED, SC_TYPE_STAMP, -1); stats_cluster_free(sc); } static void assert_stats_component_name(gint component, const gchar *expected) { gchar buf[32]; const gchar *name; StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, component, NULL, NULL ); StatsCluster *sc = stats_cluster_new(&sc_key); name = stats_cluster_get_component_name(sc, buf, sizeof(buf)); cr_assert_str_eq(name, expected, "component name mismatch"); stats_cluster_free(sc); } Test(stats_cluster, test_get_component_name_translates_component_to_name_properly) { assert_stats_component_name(SCS_SOURCE | SCS_FILE, "src.file"); assert_stats_component_name(SCS_DESTINATION | SCS_FILE, "dst.file"); assert_stats_component_name(SCS_GLOBAL, "global"); assert_stats_component_name(SCS_SOURCE | SCS_GROUP, "source"); assert_stats_component_name(SCS_DESTINATION | SCS_GROUP, "destination"); } Test(stats_cluster, test_get_counter) { StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_SOURCE | SCS_FILE, "id", "instance" ); StatsCluster *sc = stats_cluster_new(&sc_key); StatsCounterItem *processed; cr_assert_null(stats_cluster_get_counter(sc, SC_TYPE_PROCESSED), "get counter before tracked"); processed = stats_cluster_track_counter(sc, SC_TYPE_PROCESSED); cr_assert_eq(stats_cluster_get_counter(sc, SC_TYPE_PROCESSED), processed, "get counter after tracked"); StatsCounterItem *saved_processed = processed; stats_cluster_untrack_counter(sc, SC_TYPE_PROCESSED, &processed); cr_assert_null(processed, "untrack counter"); cr_assert_eq(stats_cluster_get_counter(sc, SC_TYPE_PROCESSED), saved_processed, "get counter after untracked"); stats_cluster_free(sc); } Test(stats_cluster, test_register_type) { guint first = stats_register_type("HAL"); guint second = stats_register_type("Just what do you think you are doing, Dave?"); cr_assert_eq(first + 1, second); guint same = stats_register_type("HAL"); cr_assert_eq(first, same); } TestSuite(stats_cluster, .init=setup, .fini = app_shutdown); syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_stats_cluster_key_builder.c000066400000000000000000000350661450431004300271130ustar00rootroot00000000000000/* * Copyright (c) 2023 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "stats/stats-cluster-key-builder.h" #include "stats/stats-cluster-single.h" #include "stats/stats-cluster-logpipe.h" typedef enum { TEST_LOGPIPE, TEST_SINGLE, } KeyType; static void _assert_built_sc_key_equals(const StatsClusterKeyBuilder *builder, KeyType type, const gchar *name, StatsClusterLabel *labels, gssize labels_len) { StatsClusterKey expected_sc_key; StatsClusterKey *built_key; if (type == TEST_LOGPIPE) { stats_cluster_logpipe_key_set(&expected_sc_key, name, labels, labels_len); built_key = stats_cluster_key_builder_build_logpipe(builder); } else if (type == TEST_SINGLE) { stats_cluster_single_key_set(&expected_sc_key, name, labels, labels_len); built_key = stats_cluster_key_builder_build_single(builder); } else { cr_assert_fail(); } cr_assert(stats_cluster_key_equal(&expected_sc_key, built_key)); cr_assert_eq(memcmp(&expected_sc_key.formatting, &built_key->formatting, sizeof(built_key->formatting)), 0); stats_cluster_key_free(built_key); } static void _assert_built_sc_key_has_unit(const StatsClusterKeyBuilder *builder, KeyType type, StatsClusterUnit unit) { StatsClusterKey *built_key = stats_cluster_key_builder_build_single(builder); if (type == TEST_SINGLE) cr_assert(built_key->formatting.stored_unit == unit); stats_cluster_key_free(built_key); } static void _assert_built_sc_key_has_frame_of_reference(const StatsClusterKeyBuilder *builder, KeyType type, StatsClusterFrameOfReference frame_of_reference) { StatsClusterKey *built_key = stats_cluster_key_builder_build_single(builder); if (type == TEST_SINGLE) cr_assert(built_key->formatting.frame_of_reference == frame_of_reference); stats_cluster_key_free(built_key); } static void _assert_built_sc_key_equals_with_legacy(const StatsClusterKeyBuilder *builder, KeyType type, const gchar *name, StatsClusterLabel *labels, gssize labels_len, guint16 legacy_component, const gchar *legacy_id, const gchar *legacy_instance, const gchar *legacy_name) { StatsClusterKey expected_sc_key; StatsClusterKey *built_key; if (type == TEST_LOGPIPE) { stats_cluster_logpipe_key_set(&expected_sc_key, name, labels, labels_len); stats_cluster_logpipe_key_add_legacy_alias(&expected_sc_key, legacy_component, legacy_id, legacy_instance); built_key = stats_cluster_key_builder_build_logpipe(builder); } else if (type == TEST_SINGLE) { stats_cluster_single_key_set(&expected_sc_key, name, labels, labels_len); if (legacy_name) { stats_cluster_single_key_add_legacy_alias_with_name(&expected_sc_key, legacy_component, legacy_id, legacy_instance, legacy_name); } else { stats_cluster_single_key_add_legacy_alias(&expected_sc_key, legacy_component, legacy_id, legacy_instance); } built_key = stats_cluster_key_builder_build_single(builder); } else { cr_assert_fail(); } cr_assert(stats_cluster_key_equal(&expected_sc_key, built_key)); stats_cluster_key_free(built_key); } static void _assert_built_sc_key_equals_with_legacy_only(const StatsClusterKeyBuilder *builder, KeyType type, guint16 legacy_component, const gchar *legacy_id, const gchar *legacy_instance) { StatsClusterKey expected_sc_key; StatsClusterKey *built_key = NULL; if (type == TEST_LOGPIPE) { stats_cluster_logpipe_key_legacy_set(&expected_sc_key, legacy_component, legacy_id, legacy_instance); built_key = stats_cluster_key_builder_build_logpipe(builder); } else if (type == TEST_SINGLE) { stats_cluster_single_key_legacy_set(&expected_sc_key, legacy_component, legacy_id, legacy_instance); built_key = stats_cluster_key_builder_build_single(builder); } else { cr_assert_fail(); } cr_assert(!built_key->name); cr_assert(stats_cluster_key_equal(&expected_sc_key, built_key)); stats_cluster_key_free(built_key); } static void _test_builder(KeyType type) { StatsClusterKeyBuilder *builder = stats_cluster_key_builder_new(); const gchar *dummy_name = "dummy_name"; const gchar *dummy_name_2 = "dummy_name_2"; const gchar *dummy_name_prefix = "dummy_name_prefix_"; const gchar *dummy_name_with_prefix = "dummy_name_prefix_dummy_name"; const gchar *dummy_name_with_foobar_prefix = "foobardummy_name"; const gchar *dummy_name_suffix = "_dummy_name_suffix"; const gchar *dummy_name_with_suffix = "dummy_name_dummy_name_suffix"; const gchar *dummy_name_with_foobar_suffix = "dummy_namefoobar"; guint16 dummy_legacy_component = 42; const gchar *dummy_legacy_id = "dummy_legacy_id"; const gchar *dummy_legacy_instance = "dummy_legacy_instance"; const gchar *dummy_legacy_name = "dummy_legacy_name"; stats_cluster_key_builder_push(builder); { /* Name only */ stats_cluster_key_builder_set_name(builder, dummy_name); StatsClusterLabel empty_labels[] = {}; _assert_built_sc_key_equals(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels)); /* One label */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_add_label(builder, stats_cluster_label("dummy-label-name-99", "dummy-label-value-99")); StatsClusterLabel one_label[] = { stats_cluster_label("dummy-label-name-99", "dummy-label-value-99"), }; _assert_built_sc_key_equals(builder, type, dummy_name, one_label, G_N_ELEMENTS(one_label)); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels)); /* Two labels, set in wrong ordering */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_add_label(builder, stats_cluster_label("dummy-label-name-99", "dummy-label-value-99")); stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_add_label(builder, stats_cluster_label("dummy-label-name-00", "dummy-label-value-00")); StatsClusterLabel two_labels[] = { stats_cluster_label("dummy-label-name-00", "dummy-label-value-00"), stats_cluster_label("dummy-label-name-99", "dummy-label-value-99"), }; _assert_built_sc_key_equals(builder, type, dummy_name, two_labels, G_N_ELEMENTS(two_labels)); } stats_cluster_key_builder_pop(builder); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels)); /* New name */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_name(builder, dummy_name_2); _assert_built_sc_key_equals(builder, type, dummy_name_2, empty_labels, G_N_ELEMENTS(empty_labels)); } stats_cluster_key_builder_pop(builder); /* Name prefix */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_name_prefix(builder, dummy_name_prefix); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_equals(builder, type, dummy_name_with_prefix, empty_labels, G_N_ELEMENTS(empty_labels)); stats_cluster_key_builder_set_name_prefix(builder, "foobar"); _assert_built_sc_key_equals(builder, type, dummy_name_with_foobar_prefix, empty_labels, G_N_ELEMENTS(empty_labels)); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals(builder, type, dummy_name_with_prefix, empty_labels, G_N_ELEMENTS(empty_labels)); } stats_cluster_key_builder_pop(builder); /* Name suffix */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_name_suffix(builder, dummy_name_suffix); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_equals(builder, type, dummy_name_with_suffix, empty_labels, G_N_ELEMENTS(empty_labels)); stats_cluster_key_builder_set_name_suffix(builder, "foobar"); _assert_built_sc_key_equals(builder, type, dummy_name_with_foobar_suffix, empty_labels, G_N_ELEMENTS(empty_labels)); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals(builder, type, dummy_name_with_suffix, empty_labels, G_N_ELEMENTS(empty_labels)); } stats_cluster_key_builder_pop(builder); /* Unit */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_unit(builder, SCU_NANOSECONDS); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_has_unit(builder, type, SCU_NANOSECONDS); stats_cluster_key_builder_set_unit(builder, SCU_KIB); _assert_built_sc_key_has_unit(builder, type, SCU_KIB); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_has_unit(builder, type, SCU_NANOSECONDS); } stats_cluster_key_builder_pop(builder); /* Frame of reference */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_frame_of_reference(builder, SCFOR_RELATIVE_TO_TIME_OF_QUERY); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_has_frame_of_reference(builder, type, SCFOR_RELATIVE_TO_TIME_OF_QUERY); stats_cluster_key_builder_set_frame_of_reference(builder, SCFOR_ABSOLUTE); _assert_built_sc_key_has_frame_of_reference(builder, type, SCFOR_ABSOLUTE); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_has_frame_of_reference(builder, type, SCFOR_RELATIVE_TO_TIME_OF_QUERY); } stats_cluster_key_builder_pop(builder); /* Legacy alias */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_legacy_alias(builder, 1337, "foobar", "foobar"); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), 1337, "foobar", "foobar", NULL); stats_cluster_key_builder_set_legacy_alias(builder, dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance); _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance, NULL); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), 1337, "foobar", "foobar", NULL); } stats_cluster_key_builder_pop(builder); /* Legacy alias name */ if (type == TEST_SINGLE) { /* LOGPIPE does not support setting the legacy name */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_legacy_alias(builder, dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance); stats_cluster_key_builder_set_legacy_alias_name(builder, "foobar"); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance, "foobar"); stats_cluster_key_builder_set_legacy_alias_name(builder, dummy_legacy_name); _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance, dummy_legacy_name); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals_with_legacy(builder, type, dummy_name, empty_labels, G_N_ELEMENTS(empty_labels), dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance, "foobar"); } stats_cluster_key_builder_pop(builder); } } stats_cluster_key_builder_pop(builder); /* Legacy only */ stats_cluster_key_builder_push(builder); { stats_cluster_key_builder_set_legacy_alias(builder, 1337, "foobar", "foobar"); stats_cluster_key_builder_push(builder); { _assert_built_sc_key_equals_with_legacy_only(builder, type, 1337, "foobar", "foobar"); stats_cluster_key_builder_set_legacy_alias(builder, dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance); _assert_built_sc_key_equals_with_legacy_only(builder, type, dummy_legacy_component, dummy_legacy_id, dummy_legacy_instance); } stats_cluster_key_builder_pop(builder); _assert_built_sc_key_equals_with_legacy_only(builder, type, 1337, "foobar", "foobar"); } stats_cluster_key_builder_pop(builder); stats_cluster_key_builder_free(builder); } Test(stats_cluster_key_builder, single) { _test_builder(TEST_SINGLE); } Test(stats_cluster_key_builder, logpipe) { _test_builder(TEST_LOGPIPE); } TestSuite(stats_cluster_key_builder); syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_stats_prometheus.c000066400000000000000000000271721450431004300252460ustar00rootroot00000000000000/* * Copyright (c) 2023 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "syslog-ng.h" #include "stats/stats.h" #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "stats/stats-cluster-logpipe.h" #include "stats/stats-prometheus.h" #include "timeutils/unixtime.h" #include "scratch-buffers.h" #include "mainloop.h" #include "libtest/fake-time.h" #include #include static void setup(void) { main_loop_thread_resource_init(); stats_init(); scratch_buffers_global_init(); scratch_buffers_allocator_init(); } static void teardown(void) { scratch_buffers_explicit_gc(); scratch_buffers_allocator_deinit(); scratch_buffers_global_deinit(); stats_destroy(); main_loop_thread_resource_deinit(); } TestSuite(stats_prometheus, .init = setup, .fini = teardown); static inline StatsCluster * test_single_cluster(const gchar *name, StatsClusterLabel *labels, gsize labels_len) { StatsClusterKey key; stats_cluster_single_key_set(&key, name, labels, labels_len); return stats_cluster_new(&key); } static inline StatsCluster * test_logpipe_cluster(const gchar *name, StatsClusterLabel *labels, gsize labels_len) { StatsClusterKey key; stats_cluster_logpipe_key_set(&key, name, labels, labels_len); return stats_cluster_new(&key); } static inline void assert_prometheus_format(StatsCluster *cluster, gint type, const gchar *expected_prom_record) { cr_assert_str_eq(stats_prometheus_format_counter(cluster, type, stats_cluster_get_counter(cluster, type))->str, expected_prom_record); } Test(stats_prometheus, test_prometheus_format_single) { StatsCluster *cluster = test_single_cluster("test_name", NULL, 0); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name 0\n"); stats_cluster_free(cluster); StatsClusterLabel labels[] = { stats_cluster_label("app", "cisco") }; cluster = test_single_cluster("test_name", labels, G_N_ELEMENTS(labels)); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name{app=\"cisco\"} 0\n"); stats_cluster_free(cluster); StatsClusterLabel labels2[] = { stats_cluster_label("app", "cisco"), stats_cluster_label("sourceip", "127.0.0.1"), stats_cluster_label("customlabel", "value"), }; cluster = test_single_cluster("test_name", labels2, G_N_ELEMENTS(labels2)); stats_counter_inc(stats_cluster_track_counter(cluster, SC_TYPE_SINGLE_VALUE)); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name{app=\"cisco\",sourceip=\"127.0.0.1\",customlabel=\"value\"} 1\n"); stats_cluster_free(cluster); } Test(stats_prometheus, test_prometheus_format_logpipe) { StatsCluster *cluster = test_logpipe_cluster("test_name", NULL, 0); assert_prometheus_format(cluster, SC_TYPE_PROCESSED, "syslogng_test_name{result=\"processed\"} 0\n"); stats_cluster_free(cluster); StatsClusterLabel labels[] = { stats_cluster_label("app", "cisco") }; cluster = test_logpipe_cluster("test_name", labels, G_N_ELEMENTS(labels)); assert_prometheus_format(cluster, SC_TYPE_DROPPED, "syslogng_test_name{app=\"cisco\",result=\"dropped\"} 0\n"); stats_cluster_free(cluster); StatsClusterLabel labels2[] = { stats_cluster_label("app", "cisco"), stats_cluster_label("sourceip", "127.0.0.1"), stats_cluster_label("customlabel", "value"), }; cluster = test_logpipe_cluster("test_name", labels2, G_N_ELEMENTS(labels2)); stats_counter_inc(stats_cluster_track_counter(cluster, SC_TYPE_WRITTEN)); assert_prometheus_format(cluster, SC_TYPE_WRITTEN, "syslogng_test_name{app=\"cisco\",sourceip=\"127.0.0.1\",customlabel=\"value\"," "result=\"delivered\"} 1\n"); stats_cluster_free(cluster); } Test(stats_prometheus, test_prometheus_format_empty_label_value) { StatsClusterLabel labels[] = { stats_cluster_label("app", ""), stats_cluster_label("sourceip", NULL), stats_cluster_label("customlabel", "value"), }; StatsCluster *cluster = test_single_cluster("test_name", labels, G_N_ELEMENTS(labels)); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name{customlabel=\"value\"} 0\n"); stats_cluster_free(cluster); StatsClusterLabel labels2[] = { stats_cluster_label("app", NULL), stats_cluster_label("sourceip", ""), }; cluster = test_single_cluster("test_name", labels2, G_N_ELEMENTS(labels2)); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name 0\n"); stats_cluster_free(cluster); cluster = test_logpipe_cluster("test_name", labels2, G_N_ELEMENTS(labels2)); assert_prometheus_format(cluster, SC_TYPE_PROCESSED, "syslogng_test_name{result=\"processed\"} 0\n"); stats_cluster_free(cluster); } Test(stats_prometheus, test_prometheus_format_sanitize) { StatsClusterLabel labels[] = { stats_cluster_label("app.name:", "a"), stats_cluster_label("//source-ip\n", "\"b\""), stats_cluster_label("laűúőbel", "c\n"), }; StatsCluster *cluster = test_single_cluster("test.name-http://localhost/ű#", labels, G_N_ELEMENTS(labels)); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_test_name_httplocalhost{app_name=\"a\",source_ip=\"\\\"b\\\"\",label=\"c\\n\"} 0\n"); stats_cluster_free(cluster); } gchar *stats_format_prometheus_format_value(const StatsClusterKey *key, const StatsCounterItem *counter); Test(stats_prometheus, test_prometheus_format_value) { StatsCounterItem counter = {0}; stats_counter_set(&counter, 9); StatsClusterKey key; stats_cluster_single_key_set(&key, "name", NULL, 0); stats_cluster_single_key_add_unit(&key, SCU_NONE); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9"); stats_cluster_single_key_add_unit(&key, SCU_GIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9663676416"); stats_cluster_single_key_add_unit(&key, SCU_MIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9437184"); stats_cluster_single_key_add_unit(&key, SCU_KIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9216"); stats_cluster_single_key_add_unit(&key, SCU_BYTES); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9"); stats_cluster_single_key_add_unit(&key, SCU_HOURS); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "32400"); stats_cluster_single_key_add_unit(&key, SCU_MINUTES); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "540"); stats_cluster_single_key_add_unit(&key, SCU_SECONDS); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9"); stats_cluster_single_key_add_unit(&key, SCU_MILLISECONDS); gdouble actual = g_ascii_strtod(stats_format_prometheus_format_value(&key, &counter), NULL); cr_assert_float_eq(actual, 0.009L, DBL_EPSILON); stats_cluster_single_key_add_unit(&key, SCU_NANOSECONDS); actual = g_ascii_strtod(stats_format_prometheus_format_value(&key, &counter), NULL); cr_assert_float_eq(actual, 9e-9, DBL_EPSILON); /* Relative to time of query */ stats_cluster_single_key_add_frame_of_reference(&key, SCFOR_RELATIVE_TO_TIME_OF_QUERY); /* Fri Jan 01 2100 01:01:01 GMT+0000 */ fake_time(INT_MAX); fake_time_add(1954964814); /* None, bytes and milli/nanoseconds units are unaffected */ stats_cluster_single_key_add_unit(&key, SCU_NONE); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9"); stats_cluster_single_key_add_unit(&key, SCU_GIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9663676416"); stats_cluster_single_key_add_unit(&key, SCU_MIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9437184"); stats_cluster_single_key_add_unit(&key, SCU_KIB); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9216"); stats_cluster_single_key_add_unit(&key, SCU_BYTES); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "9"); stats_cluster_single_key_add_unit(&key, SCU_MILLISECONDS); actual = g_ascii_strtod(stats_format_prometheus_format_value(&key, &counter), NULL); cr_assert_float_eq(actual, 0.009L, DBL_EPSILON); stats_cluster_single_key_add_unit(&key, SCU_NANOSECONDS); actual = g_ascii_strtod(stats_format_prometheus_format_value(&key, &counter), NULL); cr_assert_float_eq(actual, 9e-9, DBL_EPSILON); /* Hours, minutes and seconds are affected */ stats_cluster_single_key_add_unit(&key, SCU_HOURS); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "4102416061"); stats_cluster_single_key_add_unit(&key, SCU_MINUTES); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "4102447921"); stats_cluster_single_key_add_unit(&key, SCU_SECONDS); cr_assert_str_eq(stats_format_prometheus_format_value(&key, &counter), "4102448452"); } Test(stats_prometheus, test_prometheus_format_legacy) { StatsClusterKey key; stats_cluster_single_key_legacy_set_with_name(&key, SCS_GLOBAL, "id", NULL, "value"); StatsCluster *cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_global_id 0\n"); stats_cluster_free(cluster); stats_cluster_single_key_legacy_set_with_name(&key, SCS_GLOBAL, "id", NULL, "custom"); cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_global_id_custom 0\n"); stats_cluster_free(cluster); stats_cluster_single_key_legacy_set_with_name(&key, SCS_SOURCE | SCS_TAG, "", "instance", "custom"); cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_src_tag_custom{stat_instance=\"instance\"} 0\n"); stats_cluster_free(cluster); stats_cluster_single_key_legacy_set_with_name(&key, SCS_SOURCE | SCS_TAG, "id", "instance", "custom"); cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_src_tag_custom{id=\"id\",stat_instance=\"instance\"} 0\n"); stats_cluster_free(cluster); stats_cluster_logpipe_key_legacy_set(&key, SCS_SOURCE | SCS_TAG, "id", "instance"); cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_PROCESSED, "syslogng_src_tag_processed{id=\"id\",stat_instance=\"instance\"} 0\n"); stats_cluster_free(cluster); } Test(stats_prometheus, test_prometheus_format_legacy_alias_is_ignored) { StatsClusterKey key; stats_cluster_single_key_set(&key, "name", NULL, 0); stats_cluster_single_key_add_legacy_alias_with_name(&key, SCS_SOURCE | SCS_TAG, "", "instance", "custom"); StatsCluster *cluster = stats_cluster_new(&key); assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, "syslogng_name 0\n"); stats_cluster_free(cluster); } syslog-ng-syslog-ng-4.4.0/lib/stats/tests/test_stats_query.c000066400000000000000000000254571450431004300242240ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "apphook.h" #include "logmsg/logmsg.h" #include "stats/stats-cluster.h" #include "stats/stats-cluster-single.h" #include "stats/stats-counter.h" #include "stats/stats-query.h" #include "stats/stats-registry.h" #include guint SCS_FILE; guint SCS_PIPE; guint SCS_TCP; #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) typedef struct _CounterHashContent { const gint component; const gchar *id; const gchar *instance; const gint type; atomic_gssize *external_counter; gssize initial_value; } CounterHashContent; typedef struct _QueryTestCase { const gchar *pattern; const gchar *expected; } QueryTestCase; typedef void(*ClusterKeySet)(StatsClusterKey *, guint16, const gchar *, const gchar *); static void setup(void) { app_startup(); SCS_FILE = stats_register_type("file"); SCS_PIPE = stats_register_type("pipe"); SCS_TCP = stats_register_type("tcp"); } static void _register_counters(const CounterHashContent *counters, size_t n, ClusterKeySet key_set) { stats_lock(); for (size_t i = 0; i < n; i++) { StatsClusterKey sc_key; key_set(&sc_key, counters[i].component, counters[i].id, counters[i].instance); if (counters[i].external_counter) { atomic_gssize_set(counters[i].external_counter, counters[i].initial_value); stats_register_external_counter(0, &sc_key, counters[i].type, counters[i].external_counter); } else { StatsCounterItem *item = NULL; stats_register_counter(0, &sc_key, counters[i].type, &item); } } stats_unlock(); } static void _register_single_counter_with_name(void) { stats_lock(); { StatsClusterKey sc_key; StatsCounterItem *ctr_item; stats_cluster_single_key_legacy_set_with_name(&sc_key, SCS_GLOBAL, "id", "instance", "name"); stats_register_counter(0, &sc_key, SC_TYPE_SINGLE_VALUE, &ctr_item); } stats_unlock(); } static void _initialize_counter_hash(void) { setup(); static atomic_gssize external_frozen_ctr; const CounterHashContent logpipe_cluster_counters[] = { {SCS_CENTER, "guba.polo", "frozen", SC_TYPE_SUPPRESSED, &external_frozen_ctr, 12}, {SCS_FILE | SCS_SOURCE, "guba", "processed", SC_TYPE_PROCESSED, NULL, 0}, {SCS_GLOBAL, "guba.gumi.diszno", "frozen", SC_TYPE_SUPPRESSED, NULL, 0}, {SCS_PIPE | SCS_SOURCE, "guba.gumi.disz", "frozen", SC_TYPE_SUPPRESSED, NULL, 0}, {SCS_TCP | SCS_DESTINATION, "guba.labda", "received", SC_TYPE_DROPPED, NULL, 0}, {SCS_TCP | SCS_SOURCE, "guba.frizbi", "left", SC_TYPE_QUEUED, NULL, 0}, }; const CounterHashContent single_cluster_counters[] = { {SCS_GLOBAL, "", "guba", SC_TYPE_SINGLE_VALUE, NULL, 0} }; _register_counters(logpipe_cluster_counters, ARRAY_SIZE(logpipe_cluster_counters), stats_cluster_logpipe_key_legacy_set); _register_counters(single_cluster_counters, ARRAY_SIZE(single_cluster_counters), stats_cluster_single_key_legacy_set); _register_single_counter_with_name(); } static gboolean _test_format_log_msg_get(StatsCounterItem *ctr, gpointer user_data) { gchar *name, *value; LogMessage *msg = (LogMessage *)user_data; name = g_strdup_printf("%s", stats_counter_get_name(ctr)); value = g_strdup_printf("%"G_GSIZE_FORMAT, stats_counter_get(ctr)); log_msg_set_value_by_name(msg, name, value, -1); g_free(name); g_free(value); return TRUE; } static gboolean _test_format_str_get(StatsCounterItem *ctr, gpointer user_data) { GString *str = (GString *)user_data; g_string_append_printf(str, "%s: %"G_GSIZE_FORMAT"\n", stats_counter_get_name(ctr), stats_counter_get(ctr)); return TRUE; } static gboolean _test_format_log_msg_get_sum(gpointer user_data) { gchar *name, *value; gpointer *args = (gpointer *) user_data; LogMessage *msg = (LogMessage *) args[0]; gint *sum = (gint *) args[1]; name = "sum"; value = g_strdup_printf("%d", *sum); log_msg_set_value_by_name(msg, name, value, -1); g_free(value); return TRUE; } static gboolean _test_format_str_get_sum(gpointer user_data) { gpointer *args = (gpointer *) user_data; GString *result = (GString *) args[0]; gint *sum = (gint *) args[1]; g_string_printf(result, "%d", *sum); return TRUE; } static gboolean _test_format_list(StatsCounterItem *ctr, gpointer user_data) { GString *str = (GString *)user_data; g_string_append_printf(str, "%s\n", stats_counter_get_name(ctr)); return TRUE; } TestSuite(cluster_query_key, .init = setup, .fini = app_shutdown); Test(cluster_query_key, test_global_key) { const gchar *expected_key = "dst.file.d_file.instance"; StatsClusterKey sc_key; stats_cluster_logpipe_key_legacy_set(&sc_key, SCS_DESTINATION|SCS_FILE, "d_file", "instance" ); StatsCluster *sc = stats_cluster_new(&sc_key); cr_assert_str_eq(sc->query_key, expected_key, "generated query key(%s) does not match to the expected key(%s)", sc->query_key, expected_key); stats_cluster_free(sc); } TestSuite(stats_query, .init = _initialize_counter_hash, .fini = app_shutdown); ParameterizedTestParameters(stats_query, test_stats_query_get_log_msg_out) { static QueryTestCase test_cases[] = { {"dst.tcp.guba.labda.received.dropped", "0"}, {"src.pipe.guba.gumi.disz.frozen.suppressed", "0"}, }; return cr_make_param_array(QueryTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(QueryTestCase *test_cases, stats_query, test_stats_query_get_log_msg_out) { const gchar *actual; LogMessage *msg = log_msg_new_empty(); stats_query_get(test_cases->pattern, _test_format_log_msg_get, (gpointer)msg); actual = log_msg_get_value_by_name(msg, test_cases->pattern, NULL); cr_assert_str_eq(actual, test_cases->expected, "Counter: '%s'; expected number: '%s';, got: '%s';", test_cases->pattern, test_cases->expected, actual); log_msg_unref(msg); } ParameterizedTestParameters(stats_query, test_stats_query_get_str_out) { static QueryTestCase test_cases[] = { {"center.*.*", "center.guba.polo.frozen.suppressed: 12\n"}, {"cent*", "center.guba.polo.frozen.suppressed: 12\n"}, {"src.pipe.guba.gumi.disz.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed: 0\n"}, {"src.pipe.guba.gumi.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed: 0\n"}, {"src.pipe.guba.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed: 0\n"}, {"src.pipe.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed: 0\n"}, {"dst.*.*", "dst.tcp.guba.labda.received.dropped: 0\n"}, {"dst.*.*.*", "dst.tcp.guba.labda.received.dropped: 0\n"}, {"dst.*.*.*.*", "dst.tcp.guba.labda.received.dropped: 0\n"}, {"src.java.*.*", ""}, {"src.ja*.*.*", ""}, {"global.id.instance.name", "global.id.instance.name: 0\n"}, }; return cr_make_param_array(QueryTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(QueryTestCase *test_cases, stats_query, test_stats_query_get_str_out) { GString *result = g_string_new(""); stats_query_get(test_cases->pattern, _test_format_str_get, (gpointer)result); cr_assert_str_eq(result->str, test_cases->expected, "Pattern: '%s'; expected key and value: '%s';, got: '%s';", test_cases->pattern, test_cases->expected, result->str); g_string_free(result, TRUE); } ParameterizedTestParameters(stats_query, test_stats_query_get_sum_log_msg_out) { static QueryTestCase test_cases[] = { {"dst.tcp.guba.labda.received.dropped", "0"}, {"src.pipe.guba.gumi.disz.frozen.suppressed", "0"}, }; return cr_make_param_array(QueryTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(QueryTestCase *test_cases, stats_query, test_stats_query_get_sum_log_msg_out) { const gchar *actual; LogMessage *msg = log_msg_new_empty(); stats_query_get_sum(test_cases->pattern, _test_format_log_msg_get_sum, (gpointer)msg); actual = log_msg_get_value_by_name(msg, "sum", NULL); cr_assert_str_eq(actual, test_cases->expected, "Pattern: '%s'; expected number: '%s';, got: '%s';", test_cases->pattern, test_cases->expected, actual); log_msg_unref(msg); } ParameterizedTestParameters(stats_query, test_stats_query_get_sum_str_out) { static QueryTestCase test_cases[] = { {"*", "12"}, {"center.*.*", "12"}, {"cent*", "12"}, {"src.pipe.guba.gumi.disz.*.*", "0"}, {"*.tcp.guba.*.*", "0"}, {"*.guba.*i.*.*", "0"}, {"*.guba.gum?.*.*", "0"}, {"src.ja*.*.*", ""}, }; return cr_make_param_array(QueryTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(QueryTestCase *test_cases, stats_query, test_stats_query_get_sum_str_out) { GString *result = g_string_new(""); stats_query_get_sum(test_cases->pattern, _test_format_str_get_sum, (gpointer)result); cr_assert_str_eq(result->str, test_cases->expected, "Pattern: '%s'; expected key and value: '%s';, got: '%s';", test_cases->pattern, test_cases->expected, result->str); g_string_free(result, TRUE); } ParameterizedTestParameters(stats_query, test_stats_query_list) { static QueryTestCase test_cases[] = { {"center.*.*", "center.guba.polo.frozen.suppressed\n"}, {"cent*", "center.guba.polo.frozen.suppressed\n"}, {"src.pipe.guba.gumi.disz.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed\n"}, {"src.pipe.*.*", "src.pipe.guba.gumi.disz.frozen.suppressed\n"}, {"src.java.*.*", ""}, {"src.ja*.*.*", ""}, }; return cr_make_param_array(QueryTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(QueryTestCase *test_cases, stats_query, test_stats_query_list) { GString *result = g_string_new(""); stats_query_list(test_cases->pattern, _test_format_list, (gpointer)result); cr_assert_str_eq(result->str, test_cases->expected, "Pattern: '%s'; expected key: '%s';, got: '%s';", test_cases->pattern, test_cases->expected, result->str); g_string_free(result, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/str-format.c000066400000000000000000000176131450431004300203730ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "str-format.h" #include #include static gchar digits[] = "0123456789abcdef"; /* format 64 bit ints */ static inline gint format_uint64_base10_rev(gchar *result, gsize result_len, gint sign, guint64 value) { gchar *p; gboolean negative = FALSE; gboolean first = TRUE; if (sign && ((gint64) value) < 0) { value = -((gint64) value); negative = TRUE; } p = result; while (first || (result_len > 0 && value > 0)) { *p = digits[value % 10]; value /= 10; p++; result_len--; first = FALSE; } if (negative && result_len > 0) { *p = '-'; p++; } return p - result; } static inline gint format_uint64_base16_rev(gchar *result, gsize result_len, guint64 value) { gchar *p; p = result; while (result_len > 0 && value > 0) { *p = digits[value & 0x0F]; value >>= 4; p++; result_len--; } return p - result; } static inline gint format_uint64_base8_rev(gchar *result, gsize result_len, guint64 value) { gchar *p; gboolean first = TRUE; p = result; while (first || (result_len > 0 && value > 0)) { *p = digits[value & 0x07]; value >>= 3; p++; result_len--; first = FALSE; } return p - result; } static gint format_padded_int64(GString *result, gint field_len, gchar pad_char, gint sign, gint base, guint64 value) { gchar num[64]; gint len, i, pos; if (base == 10) len = format_uint64_base10_rev(num, sizeof(num), sign, value); else if (base == 16) len = format_uint64_base16_rev(num, sizeof(num), value); else if (base == 8) len = format_uint64_base8_rev(num, sizeof(num), value); else g_assert_not_reached(); if (field_len == 0 || field_len < len) field_len = len; pos = result->len; if (G_UNLIKELY(result->allocated_len < pos + field_len + 1)) { g_string_set_size(result, pos + field_len); } else { result->len += field_len; result->str[pos + field_len] = 0; } memset(result->str + pos, pad_char, field_len - len); for (i = 0; i < len; i++) { result->str[pos + field_len - i - 1] = num[i]; } return field_len; } gint format_uint64_padded(GString *result, gint field_len, gchar pad_char, gint base, guint64 value) { return format_padded_int64(result, field_len, pad_char, 0, base, value); } gint format_int64_padded(GString *result, gint field_len, gchar pad_char, gint base, gint64 value) { return format_padded_int64(result, field_len, pad_char, 1, base, value); } /* format 32 bit ints */ static inline gint format_uint32_base10_rev(gchar *result, gsize result_len, gint sign, guint32 value) { gchar *p; gboolean negative = 0; gboolean first = TRUE; if (sign && ((gint32) value) < 0) { value = -((gint32) value); negative = 1; } p = result; while (first || (result_len > 0 && value > 0)) { *p = digits[value % 10]; value /= 10; p++; result_len--; first = FALSE; } if (negative && result_len > 0) { *p = '-'; p++; } return p - result; } static inline gint format_uint32_base16_rev(gchar *result, gsize result_len, guint32 value) { gchar *p; gboolean first = TRUE; p = result; while (first || (result_len > 0 && value > 0)) { *p = digits[value & 0x0F]; value >>= 4; p++; result_len--; first = FALSE; } return p - result; } static inline gint format_uint32_base8_rev(gchar *result, gsize result_len, guint32 value) { gchar *p; gboolean first = TRUE; p = result; while (first || (result_len > 0 && value > 0)) { *p = digits[value & 0x07]; value >>= 3; p++; result_len--; first = FALSE; } return p - result; } static gint format_padded_int32(GString *result, gint field_len, gchar pad_char, gint sign, gint base, guint32 value) { gchar num[32]; gint len, i, pos; if (base == 10) len = format_uint32_base10_rev(num, sizeof(num), sign, value); else if (base == 16) len = format_uint32_base16_rev(num, sizeof(num), value); else if (base == 8) len = format_uint32_base8_rev(num, sizeof(num), value); else g_assert_not_reached(); if (field_len == 0 || field_len < len) field_len = len; pos = result->len; if (G_UNLIKELY(result->allocated_len < pos + field_len + 1)) { g_string_set_size(result, pos + field_len); } else { result->len += field_len; result->str[pos + field_len] = 0; } memset(result->str + pos, pad_char, field_len - len); for (i = 0; i < len; i++) { result->str[pos + field_len - i - 1] = num[i]; } return field_len; } gint format_uint32_padded(GString *result, gint field_len, gchar pad_char, gint base, guint32 value) { return format_padded_int32(result, field_len, pad_char, 0, base, value); } gint format_int32_padded(GString *result, gint field_len, gchar pad_char, gint base, gint32 value) { return format_padded_int32(result, field_len, pad_char, 1, base, value); } gchar * format_hex_string_with_delimiter(gpointer data, gsize data_len, gchar *result, gsize result_len, gchar delimiter) { gint i; gint pos = 0; guchar *str = (guchar *) data; for (i = 0; i < data_len && result_len - pos >= 3; i++) { if ( (delimiter != 0) && (i < data_len - 1)) { g_snprintf(result + pos, 4, "%02x%c", str[i], delimiter); pos += 3; } else { g_snprintf(result + pos, 3, "%02x", str[i]); pos += 2; } } return result; } gchar * format_hex_string(gpointer data, gsize data_len, gchar *result, gsize result_len) { return format_hex_string_with_delimiter(data, data_len, result, result_len, 0); } /* parse 32 bit ints */ gboolean scan_positive_int(const gchar **buf, gint *left, gint field_width, gint *num) { const gchar *original_buf = *buf; gint original_left = *left; guint32 result; result = 0; while (*left > 0 && field_width > 0 && **buf == ' ') { (*buf)++; (*left)--; field_width--; } while (*left > 0 && field_width > 0 && (**buf) >= '0' && (**buf) <= '9') { result = result * 10 + ((**buf) - '0'); (*buf)++; (*left)--; field_width--; } if (field_width != 0) goto fail; *num = result; return TRUE; fail: *buf = original_buf; *left = original_left; return FALSE; } gboolean scan_expect_char(const gchar **buf, gint *left, gchar value) { if (*left == 0) return FALSE; if ((**buf) != value) return FALSE; (*buf)++; (*left)--; return TRUE; } gboolean scan_expect_str(const gchar **buf, gint *left, const gchar *value) { const gchar *original_buf = *buf; gint original_left = *left; while (*value) { if (*left == 0 || *value != **buf) { *buf = original_buf; *left = original_left; return FALSE; } (*buf)++; (*left)--; value++; } return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/str-format.h000066400000000000000000000036351450431004300203770ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STR_FORMAT_H_INCLUDED #define STR_FORMAT_H_INCLUDED #include "syslog-ng.h" gint format_uint32_padded(GString *result, gint field_len, gchar pad_char, gint base, guint32 value); gint format_int32_padded(GString *result, gint field_len, gchar pad_char, gint base, gint32 value); gint format_uint64_padded(GString *result, gint field_len, gchar pad_char, gint base, guint64 value); gint format_int64_padded(GString *result, gint field_len, gchar pad_char, gint base, gint64 value); gchar *format_hex_string(gpointer str, gsize str_len, gchar *result, gsize result_len); gchar *format_hex_string_with_delimiter(gpointer str, gsize str_len, gchar *result, gsize result_len, gchar delimiter); gboolean scan_positive_int(const gchar **buf, gint *left, gint field_width, gint *num); gboolean scan_expect_char(const gchar **buf, gint *left, gchar value); gboolean scan_expect_str(const gchar **buf, gint *left, const gchar *value); #endif syslog-ng-syslog-ng-4.4.0/lib/str-repr/000077500000000000000000000000001450431004300176775ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/str-repr/CMakeLists.txt000066400000000000000000000003051450431004300224350ustar00rootroot00000000000000set(STR_REPR_HEADERS str-repr/encode.h str-repr/decode.h PARENT_SCOPE) set(STR_REPR_SOURCES str-repr/encode.c str-repr/decode.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/str-repr/Makefile.am000066400000000000000000000004321450431004300217320ustar00rootroot00000000000000str_reprincludedir = ${pkgincludedir}/str-repr EXTRA_DIST += lib/str-repr/CMakeLists.txt str_reprinclude_HEADERS = \ lib/str-repr/decode.h \ lib/str-repr/encode.h str_repr_sources = \ lib/str-repr/decode.c \ lib/str-repr/encode.c include lib/str-repr/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/str-repr/decode.c000066400000000000000000000156501450431004300212750ustar00rootroot00000000000000/* * Copyright (c) 2015-2016 Balabit * Copyright (c) 2015-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "str-repr/decode.h" #include enum { KV_QUOTE_INITIAL = 0, KV_QUOTE_STRING, KV_QUOTE_BACKSLASH, KV_QUOTE_FINISH, KV_EXPECT_DELIMITER, KV_QUOTE_ERROR, KV_UNQUOTED_CHARACTERS, KV_FINISH_SUCCESS, KV_FINISH_FAILURE, }; static void _decode_backslash_escape(GString *value, gchar quote_char, gchar ch) { gchar control; switch (ch) { case 'b': control = '\b'; break; case 'f': control = '\f'; break; case 'n': control = '\n'; break; case 'r': control = '\r'; break; case 't': control = '\t'; break; case '\\': control = '\\'; break; default: if (quote_char != ch) g_string_append_c(value, '\\'); control = ch; break; } g_string_append_c(value, control); } typedef struct _StrReprDecodeState { GString *value; const gchar *cur; gchar quote_char; const StrReprDecodeOptions *options; } StrReprDecodeState; static gboolean _invoke_match_delimiter(StrReprDecodeState *state, const gchar **new_cur) { const StrReprDecodeOptions *options = state->options; if (options->delimiter_chars[0]) { if (*state->cur == options->delimiter_chars[0] || *state->cur == options->delimiter_chars[1] || *state->cur == options->delimiter_chars[2]) { if (options->match_delimiter) return options->match_delimiter(state->cur, new_cur, options->match_delimiter_data); else { *new_cur = state->cur + 1; return TRUE; } } } else { if (options->match_delimiter) return options->match_delimiter(state->cur, new_cur, options->match_delimiter_data); } return FALSE; } static gboolean _match_and_skip_delimiter(StrReprDecodeState *state) { const gchar *new_cur; if (_invoke_match_delimiter(state, &new_cur)) { state->cur = new_cur; return TRUE; } return FALSE; } static gint _process_initial_character(StrReprDecodeState *state) { if (_match_and_skip_delimiter(state)) { return KV_FINISH_SUCCESS; } else if (*state->cur == '\"' || *state->cur == '\'') { state->quote_char = *state->cur; return KV_QUOTE_STRING; } else { g_string_append_c(state->value, *state->cur); return KV_UNQUOTED_CHARACTERS; } } static gint _process_quoted_string_characters(StrReprDecodeState *state) { if (*state->cur == state->quote_char) return KV_EXPECT_DELIMITER; else if (*state->cur == '\\') return KV_QUOTE_BACKSLASH; g_string_append_c(state->value, *state->cur); return KV_QUOTE_STRING; } static gint _process_backslash_escaped_character_in_strings(StrReprDecodeState *state) { _decode_backslash_escape(state->value, state->quote_char, *state->cur); return KV_QUOTE_STRING; } static gint _process_delimiter_characters_after_a_quoted_string(StrReprDecodeState *state) { if (_match_and_skip_delimiter(state)) return KV_FINISH_SUCCESS; return KV_QUOTE_ERROR; } static gint _process_junk_after_closing_quote(StrReprDecodeState *state) { if (_match_and_skip_delimiter(state)) return KV_FINISH_FAILURE; return KV_QUOTE_ERROR; } static gint _process_unquoted_characters(StrReprDecodeState *state) { if (_match_and_skip_delimiter(state)) return KV_FINISH_SUCCESS; g_string_append_c(state->value, *state->cur); return KV_UNQUOTED_CHARACTERS; } static gboolean _is_an_ending_string_acceptable_in_this_state(gint quote_state) { return quote_state == KV_QUOTE_INITIAL || quote_state == KV_EXPECT_DELIMITER || quote_state == KV_UNQUOTED_CHARACTERS || quote_state == KV_FINISH_SUCCESS; } static gboolean _decode(StrReprDecodeState *state) { gint quote_state = KV_QUOTE_INITIAL; for (; *state->cur; state->cur++) { switch (quote_state) { case KV_QUOTE_INITIAL: quote_state = _process_initial_character(state); break; case KV_QUOTE_STRING: quote_state = _process_quoted_string_characters(state); break; case KV_QUOTE_BACKSLASH: quote_state = _process_backslash_escaped_character_in_strings(state); break; case KV_EXPECT_DELIMITER: quote_state = _process_delimiter_characters_after_a_quoted_string(state); break; case KV_QUOTE_ERROR: quote_state = _process_junk_after_closing_quote(state); break; case KV_UNQUOTED_CHARACTERS: quote_state = _process_unquoted_characters(state); break; default: break; } if (quote_state == KV_FINISH_SUCCESS || quote_state == KV_FINISH_FAILURE) break; } if (_is_an_ending_string_acceptable_in_this_state(quote_state)) return TRUE; return FALSE; } gboolean str_repr_decode_append_with_options(GString *value, const gchar *input, const gchar **end, const StrReprDecodeOptions *options) { StrReprDecodeState state = { .value = value, .cur = input, .quote_char = 0, .options = options, }; gsize initial_len = value->len; gboolean success = _decode(&state); *end = state.cur; if (!success) { g_string_truncate(value, initial_len); g_string_append_len(value, input, state.cur - input); return FALSE; } return TRUE; } gboolean str_repr_decode_append(GString *value, const gchar *input, const gchar **end) { StrReprDecodeOptions options = { 0, .delimiter_chars = " ", }; return str_repr_decode_append_with_options(value, input, end, &options); } gboolean str_repr_decode(GString *value, const gchar *input, const gchar **end) { g_string_truncate(value, 0); return str_repr_decode_append(value, input, end); } gboolean str_repr_decode_with_options(GString *value, const gchar *input, const gchar **end, const StrReprDecodeOptions *options) { g_string_truncate(value, 0); return str_repr_decode_append_with_options(value, input, end, options); } syslog-ng-syslog-ng-4.4.0/lib/str-repr/decode.h000066400000000000000000000036001450431004300212720ustar00rootroot00000000000000/* * Copyright (c) 2015-2016 Balabit * Copyright (c) 2015-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SYSLOG_NG_C_LITERAL_UNESCAPE_H_INCLUDED #define SYSLOG_NG_C_LITERAL_UNESCAPE_H_INCLUDED #include "syslog-ng.h" typedef gboolean (*MatchDelimiterFunc)(const gchar *cur, const gchar **new_cur, gpointer user_data); typedef struct _StrReprDecodeOptions { MatchDelimiterFunc match_delimiter; gpointer match_delimiter_data; gchar delimiter_chars[3]; } StrReprDecodeOptions; gboolean str_repr_decode(GString *value, const gchar *input, const gchar **end); gboolean str_repr_decode_append(GString *value, const gchar *input, const gchar **end); gboolean str_repr_decode_with_options(GString *value, const gchar *input, const gchar **end, const StrReprDecodeOptions *options); gboolean str_repr_decode_append_with_options(GString *value, const gchar *input, const gchar **end, const StrReprDecodeOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/str-repr/encode.c000066400000000000000000000054561450431004300213120ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "str-repr/encode.h" #include "utf8utils.h" #include void str_repr_encode_append(GString *escaped_string, const gchar *str, gssize str_len, const gchar *forbidden_chars) { const gchar *apostrophe, *quote; if (str_len < 0) str_len = strlen(str); if (str_len == 0) { g_string_append_len(escaped_string, "\"\"", 2); return; } apostrophe = memchr(str, '\'', str_len); quote = memchr(str, '"', str_len); if (!apostrophe && !quote) { gboolean quoting_needed = FALSE; /* NOTE: for non-NUL terminated strings, this would go over the end of * the string until the first NUL character. It is not ideal at all, * but there's no strncspn() */ if ((strcspn(str, "\b\f\n\r\t\\ ")) < str_len || (forbidden_chars && strcspn(str, forbidden_chars) < str_len)) quoting_needed = TRUE; if (!quoting_needed) { g_string_append_len(escaped_string, str, str_len); return; } } if (!apostrophe && quote) { g_string_append_c(escaped_string, '\''); append_unsafe_utf8_as_escaped_binary(escaped_string, str, str_len, NULL); g_string_append_c(escaped_string, '\''); } else if (!quote && apostrophe) { g_string_append_c(escaped_string, '"'); append_unsafe_utf8_as_escaped_binary(escaped_string, str, str_len, NULL); g_string_append_c(escaped_string, '"'); } else { g_string_append_c(escaped_string, '"'); append_unsafe_utf8_as_escaped_binary(escaped_string, str, str_len, "\""); g_string_append_c(escaped_string, '"'); } } void str_repr_encode(GString *escaped_string, const gchar *str, gssize str_len, const gchar *forbidden_chars) { g_string_truncate(escaped_string, 0); str_repr_encode_append(escaped_string, str, str_len, forbidden_chars); } syslog-ng-syslog-ng-4.4.0/lib/str-repr/encode.h000066400000000000000000000025001450431004300213020ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SYSLOG_NG_C_LITERAL_ESCAPE_INCLUDED #define SYSLOG_NG_C_LITERAL_ESCAPE_INCLUDED #include "syslog-ng.h" void str_repr_encode(GString *escaped_string, const gchar *str, gssize str_len, const gchar *forbidden_chars); void str_repr_encode_append(GString *escaped_string, const gchar *str, gssize str_len, const gchar *forbidden_chars); #endif syslog-ng-syslog-ng-4.4.0/lib/str-repr/tests/000077500000000000000000000000001450431004300210415ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/str-repr/tests/CMakeLists.txt000066400000000000000000000001401450431004300235740ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_decode) add_unit_test(CRITERION LIBTEST TARGET test_encode) syslog-ng-syslog-ng-4.4.0/lib/str-repr/tests/Makefile.am000066400000000000000000000006421450431004300230770ustar00rootroot00000000000000lib_str_repr_tests_TESTS = \ lib/str-repr/tests/test_decode \ lib/str-repr/tests/test_encode EXTRA_DIST += lib/str-repr/tests/CMakeLists.txt check_PROGRAMS += ${lib_str_repr_tests_TESTS} lib_str_repr_tests_test_decode_CFLAGS = $(TEST_CFLAGS) lib_str_repr_tests_test_decode_LDADD = \ $(TEST_LDADD) lib_str_repr_tests_test_encode_CFLAGS = $(TEST_CFLAGS) lib_str_repr_tests_test_encode_LDADD = \ $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/str-repr/tests/test_decode.c000066400000000000000000000103771450431004300234770ustar00rootroot00000000000000/* * Copyright (c) 2015-2016 Balabit * Copyright (c) 2015-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "str-repr/decode.h" GString *value; static void assert_decode_equals(const gchar *input, const gchar *expected) { GString *str = g_string_new(""); const gchar *end; cr_assert(str_repr_decode(str, input, &end), "Decode operation failed while success was expected, input=%s", input); cr_assert_str_eq(str->str, expected, "Decoded value does not match expected"); g_string_free(str, TRUE); } static void assert_decode_equals_and_fails(const gchar *input, const gchar *expected) { GString *str = g_string_new(""); const gchar *end; cr_assert_not(str_repr_decode(str, input, &end), "Decode operation succeeded while failure was expected, input=%s", input); cr_assert_str_eq(str->str, expected, "Decoded value does not match expected"); g_string_free(str, TRUE); } static gboolean _match_three_tabs_as_delimiter(const gchar *cur, const gchar **new_cur, gpointer user_data) { *new_cur = cur + 3; return (strncmp(cur, "\t\t\t", 3) == 0); } static void assert_decode_with_three_tabs_as_delimiter_equals(const gchar *input, const gchar *expected) { StrReprDecodeOptions options = { .match_delimiter = _match_three_tabs_as_delimiter, 0 }; GString *str = g_string_new(""); const gchar *end; str_repr_decode_with_options(str, input, &end, &options); cr_assert_str_eq(str->str, expected, "Decoded value does not match expected"); g_string_free(str, TRUE); } Test(decode, test_decode_unquoted_strings) { assert_decode_equals("a", "a"); assert_decode_equals("alma", "alma"); assert_decode_equals("al ma", "al"); } Test(decode, test_decode_double_quoted_strings) { assert_decode_equals("\"al ma\"", "al ma"); /* embedded quote */ assert_decode_equals("\"\\\"value1\"", "\"value1"); /* control sequences */ assert_decode_equals("\"\\b \\f \\n \\r \\t \\\\\"", "\b \f \n \r \t \\"); /* unknown backslash escape is left as is */ assert_decode_equals("\"\\p\"", "\\p"); } Test(decode, test_decode_apostrophe_quoted_strings) { assert_decode_equals("'al ma'", "al ma"); /* embedded quote */ assert_decode_equals("'\\'value1'", "'value1"); /* control sequences */ assert_decode_equals("'\\b \\f \\n \\r \\t \\\\'", "\b \f \n \r \t \\"); /* unknown backslash escape is left as is */ assert_decode_equals("'\\p\'", "\\p"); } Test(decode, test_decode_malformed_strings) { assert_decode_equals_and_fails("'alma", "'alma"); assert_decode_equals_and_fails("\"alma", "\"alma"); assert_decode_equals("alma'", "alma'"); assert_decode_equals("alma\"", "alma\""); assert_decode_equals("alma\"korte", "alma\"korte"); assert_decode_equals("alma\"korte\"", "alma\"korte\""); assert_decode_equals_and_fails("'alma'@korte", "'alma'@korte"); } Test(decode, test_decode_delimited_strings) { assert_decode_with_three_tabs_as_delimiter_equals("alma\t\t\tkorte", "alma"); assert_decode_with_three_tabs_as_delimiter_equals("'alma\t\t\tkorte'", "alma\t\t\tkorte"); assert_decode_with_three_tabs_as_delimiter_equals("'alma\t\t\tkorte'\t\t", "'alma\t\t\tkorte'\t\t"); assert_decode_with_three_tabs_as_delimiter_equals("'alma\t\t\tkorte'\t\t\t", "alma\t\t\tkorte"); assert_decode_with_three_tabs_as_delimiter_equals("alma\t\t", "alma\t\t"); assert_decode_with_three_tabs_as_delimiter_equals("\t\t\tfoobar", ""); } syslog-ng-syslog-ng-4.4.0/lib/str-repr/tests/test_encode.c000066400000000000000000000107721450431004300235100ustar00rootroot00000000000000/* * Copyright (c) 2015-2016 Balabit * Copyright (c) 2015-2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/stopwatch.h" #include "str-repr/encode.h" GString *value; typedef struct _EncodeTestStr { const gchar *actual; const gchar *expected; } EncodeTestStr; typedef struct _EncodeTestForbidden { const gchar *actual; const gchar *forbidden; const gchar *expected; } EncodeTestForbidden; static void assert_encode_equals(const gchar *input, const gchar *expected) { GString *str = g_string_new(""); str_repr_encode(str, input, -1, NULL); cr_assert_str_eq(str->str, expected, "Encoded value does not match expected; actual: %s, expected: %s", str->str, expected); str_repr_encode(str, input, strlen(input), NULL); cr_assert_str_eq(str->str, expected, "Encoded value does not match expected; actual: %s, expected: %s", str->str, expected); gchar *space_ended_input = g_strdup_printf("%s ", input); str_repr_encode(str, space_ended_input, strlen(input), ","); cr_assert_str_eq(str->str, expected, "Encoded value does not match expected; actual: %s, expected: %s", str->str, expected); g_free(space_ended_input); g_string_free(str, TRUE); } static void assert_encode_with_forbidden_equals(const gchar *input, const gchar *forbidden_chars, const gchar *expected) { GString *str = g_string_new(""); str_repr_encode(str, input, -1, forbidden_chars); cr_assert_str_eq(str->str, expected, "Encoded value does not match expected; actual: %s, expected: %s", str->str, expected); g_string_free(str, TRUE); } ParameterizedTestParameters(encode, test_strings) { static EncodeTestStr test_cases[] = { {"", "\"\""}, {"a", "a"}, {"alma", "alma"}, {"al\nma", "\"al\\nma\""}, {"foo bar", "\"foo bar\""}, /* embedded quote */ {"\"value1", "'\"value1'"}, {"'value1", "\"'value1\""}, /* control sequences */ {"\b \f \n \r \t \\", "\"\\b \\f \\n \\r \\t \\\\\""} }; return cr_make_param_array(EncodeTestStr, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(EncodeTestStr *test_cases, encode, test_strings) { assert_encode_equals(test_cases->actual, test_cases->expected); } ParameterizedTestParameters(encode, test_encode_strings_that_need_quotation) { static EncodeTestForbidden test_cases[] = { {"foo,", ",", "\"foo,\""}, {"\"'foo,", ",", "\"\\\"'foo,\""} }; return cr_make_param_array(EncodeTestForbidden, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(EncodeTestForbidden *test_cases, encode, test_encode_strings_that_need_quotation) { assert_encode_with_forbidden_equals(test_cases->actual, test_cases->forbidden, test_cases->expected); } #define ITERATION_NUMBER 100000 static void _perftest(const gchar *value_to_encode) { gint iteration_index = 0; GString *result = g_string_sized_new(64); gsize value_len = strlen(value_to_encode); start_stopwatch(); for (iteration_index = 0; iteration_index < ITERATION_NUMBER; iteration_index++) { str_repr_encode(result, value_to_encode, value_len, ","); } stop_stopwatch_and_display_result(iteration_index, "%.64s...", value_to_encode); g_string_free(result, TRUE); } Test(encode, test_performance) { _perftest("This is a long value with spaces and control characters\n" " "); _perftest("This is 'a long' value with spaces and control characters\n"); _perftest("This is \"a long\" value with spaces and control characters\n"); } syslog-ng-syslog-ng-4.4.0/lib/str-utils.c000066400000000000000000000040121450431004300202300ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "str-utils.h" GString * g_string_assign_len(GString *s, const gchar *val, gint len) { g_string_truncate(s, 0); if (val && len) g_string_append_len(s, val, len); return s; } void g_string_steal(GString *s) { s->str = g_malloc0(1); s->allocated_len = 1; s->len = 0; } static gchar * str_replace_char(const gchar *str, const gchar from, const gchar to) { gchar *p; gchar *ret = g_strdup(str); p = ret; while (*p) { if (*p == from) *p = to; p++; } return ret; } /* This function normalizes differently than the flags version. TODO: investigate if the two can be aligned. Hint: as flag normalization has strong position in the code, aligning block normalization to flag normalization might prove easier. Some more info: https://github.com/syslog-ng/syslog-ng/pull/2162#discussion_r202247468 */ gchar * __normalize_key(const gchar *buffer) { return str_replace_char(buffer, '-', '_'); } gchar * normalize_flag(const gchar *buffer) { return str_replace_char(buffer, '_', '-'); } syslog-ng-syslog-ng-4.4.0/lib/str-utils.h000066400000000000000000000112511450431004300202400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STR_UTILS_H_INCLUDED #define STR_UTILS_H_INCLUDED 1 #include "syslog-ng.h" #include /* functions that should be implemented by GLib but they aren't */ GString *g_string_assign_len(GString *s, const gchar *val, gint len); void g_string_steal(GString *s); static inline GString * g_string_append_unichar_optimized(GString *string, gunichar wc) { if (wc < 0x80) g_string_append_c(string, (gchar) wc); else g_string_append_unichar(string, wc); return string; } /* * DO NOT USE THIS MACRO UNLESS STRICTLY NECESSARY FOR PERFORMANCE REASONS. * * This macro tries hard to zero-terminate the string without moving it to a * new buffer. * * It is expected to be used at sites where the length is known and where * the input string is expected to be properly NUL terminated but not always. * * The macro checks if the string is indeed NUL terminated and if it is it * just assigns the original pointer to dest. If it's not, it allocates a * new string via g_alloca() so it is automatically freed when the current * scope exits. * * This does not work as an inline function as we use g_alloca() and that * would be freed when the inline function exits (e.g. when it is in fact * not inlined). */ #define APPEND_ZERO(dest, value, value_len) \ do { \ gchar *__buf; \ if (G_UNLIKELY(value[value_len] != 0)) \ { \ /* value is NOT zero terminated */ \ \ __buf = g_alloca(value_len + 1); \ memcpy(__buf, value, value_len); \ __buf[value_len] = 0; \ } \ else \ { \ /* value is zero terminated */ \ __buf = (gchar *) value; \ } \ dest = __buf; \ } while (0) gchar *__normalize_key(const gchar *buffer); gchar *normalize_flag(const gchar *buffer); /* This version of strchr() is optimized for cases where the string we are * looking up characters in is often zero or one character in length. In * those cases we can avoid the strchr() call, which can make a tight loop * doing a lot of strchr() calls a lot faster, especially as this function * is inlined. * * Naming: I originally wanted to use the original function as a prefix * (strchr), however that would potentially pollute the namespace of the * library that we are optimizing. So I've added an underscore prefix in * order not to clash, with that it is still obvious that it intends to * behave the same as strchr(). * * NOTE: don't use this unless strchr() really shows up in your profile. */ static inline char * _strchr_optimized_for_single_char_haystack(const char *str, int c) { if (str[0] == c) return (char *) str; else if (str[0] == '\0') return NULL; if (str[1] == '\0') { if (c != '\0') return NULL; else return (char *) &str[1]; } return strchr(str + 1, c); } /* * strsplit() splits the `str` into `maxtokens` pieces. * This version skips multiple `delims`. * */ static inline gchar **strsplit(const gchar *str, char delim, gint maxtokens) { if (!str || delim == '\0') return NULL; const gchar *delim_pos = NULL; const gchar *remainder = str; GPtrArray *array = g_ptr_array_new(); if (maxtokens < 1) maxtokens = G_MAXINT; for (delim_pos = strchr(remainder, delim); delim_pos && maxtokens; maxtokens--) { const gchar *d = delim_pos; while (d && *d++ == delim); if (!d) break; --d; gint len = delim_pos - remainder; if (len > 0) g_ptr_array_add(array, g_strndup(remainder, len)); remainder = d; delim_pos = strchr(remainder, delim); } if (remainder) g_ptr_array_add(array, g_strdup(remainder)); g_ptr_array_add(array, NULL); return (gchar **) g_ptr_array_free(array, FALSE); } #endif syslog-ng-syslog-ng-4.4.0/lib/string-list.c000066400000000000000000000054061450431004300205510ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "string-list.h" /* The aim of this module is to support the grammar to parse string lists * into simple linked lists. Items can contain special values denoted by * integers. We probably could find a _much_ nicer solution than this, I am * just extracting it from misc.c to its separate module. -- Bazsi */ /* * NOTE: pointer values below 0x1000 (4096) are taken as special values used * by the application code and are not duplicated, but assumed to be literal * tokens. */ GList * string_list_clone(const GList *string_list) { GList *cloned = NULL; const GList *l; for (l = string_list; l; l = l->next) cloned = g_list_append(cloned, (gulong)(l->data) > 4096 ? g_strdup(l->data) : l->data); return cloned; } GList * string_array_to_list(const gchar *strlist[]) { gint i; GList *l = NULL; for (i = 0; strlist[i]; i++) { l = g_list_prepend(l, g_strdup(strlist[i])); } return g_list_reverse(l); } GList * string_vargs_to_list_va(const gchar *str, va_list va) { GList *p = NULL; while (str) { p = g_list_append(p, g_strdup(str)); str = va_arg(va, const gchar *); } return p; } GList * string_vargs_to_list(const gchar *str, ...) { va_list va; va_start(va, str); GList *p = string_vargs_to_list_va(str, va); va_end(va); return p; } /* * NOTE: pointer values below 0x1000 (4096) are taken as special * values used by the application code and are not freed. Since this * is the NULL page, this should not cause memory leaks. */ static void _free_valid_str_pointers(gpointer data) { /* some of the string lists use invalid pointer values as special * items, see SQL "default" item */ if ((gulong)data > 4096) g_free(data); } void string_list_free(GList *l) { g_list_free_full(l, _free_valid_str_pointers); } syslog-ng-syslog-ng-4.4.0/lib/string-list.h000066400000000000000000000025111450431004300205500ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STRING_LIST_H_INCLUDED #define STRING_LIST_H_INCLUDED 1 #include "syslog-ng.h" GList *string_list_clone(const GList *string_list); GList *string_array_to_list(const gchar *strlist[]); GList *string_vargs_to_list_va(const gchar *str, va_list va); GList *string_vargs_to_list(const gchar *str, ...); void string_list_free(GList *l); #endif syslog-ng-syslog-ng-4.4.0/lib/syslog-names.c000066400000000000000000000076001450431004300207110ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-names.h" #include "syslog-ng.h" #include struct sl_name sl_severities[] = { {"emerg", SYSLOG_SEVERITY_CODE(0) }, {"emergency", SYSLOG_SEVERITY_CODE(0) }, {"panic", SYSLOG_SEVERITY_CODE(0) }, {"alert", SYSLOG_SEVERITY_CODE(1) }, {"crit", SYSLOG_SEVERITY_CODE(2) }, {"critical", SYSLOG_SEVERITY_CODE(2) }, {"err", SYSLOG_SEVERITY_CODE(3) }, {"error", SYSLOG_SEVERITY_CODE(3) }, {"warning", SYSLOG_SEVERITY_CODE(4) }, {"warn", SYSLOG_SEVERITY_CODE(4) }, {"notice", SYSLOG_SEVERITY_CODE(5) }, {"info", SYSLOG_SEVERITY_CODE(6) }, {"informational", SYSLOG_SEVERITY_CODE(6) }, {"debug", SYSLOG_SEVERITY_CODE(7) }, {NULL, -1} }; struct sl_name sl_facilities[] = { {"kern", SYSLOG_FACILITY_CODE(0) }, {"user", SYSLOG_FACILITY_CODE(1) }, {"mail", SYSLOG_FACILITY_CODE(2) }, {"daemon", SYSLOG_FACILITY_CODE(3) }, {"auth", SYSLOG_FACILITY_CODE(4) }, {"syslog", SYSLOG_FACILITY_CODE(5) }, {"lpr", SYSLOG_FACILITY_CODE(6) }, {"news", SYSLOG_FACILITY_CODE(7) }, {"uucp", SYSLOG_FACILITY_CODE(8) }, {"cron", SYSLOG_FACILITY_CODE(9) }, {"authpriv", SYSLOG_FACILITY_CODE(10) }, {"megasafe", SYSLOG_FACILITY_CODE(10) }, /* DEC UNIX AdvFS logging */ {"ftp", SYSLOG_FACILITY_CODE(11) }, {"ntp", SYSLOG_FACILITY_CODE(12) }, {"security", SYSLOG_FACILITY_CODE(13) }, {"console", SYSLOG_FACILITY_CODE(14) }, {"solaris-cron", SYSLOG_FACILITY_CODE(15) }, {"local0", SYSLOG_FACILITY_CODE(16) }, {"local1", SYSLOG_FACILITY_CODE(17) }, {"local2", SYSLOG_FACILITY_CODE(18) }, {"local3", SYSLOG_FACILITY_CODE(19) }, {"local4", SYSLOG_FACILITY_CODE(20) }, {"local5", SYSLOG_FACILITY_CODE(21) }, {"local6", SYSLOG_FACILITY_CODE(22) }, {"local7", SYSLOG_FACILITY_CODE(23) }, {NULL, -1} }; static inline int syslog_name_find_name(const char *name, struct sl_name names[]) { int i; for (i = 0; names[i].name; i++) { if (strcasecmp(name, names[i].name) == 0) { return i; } } return -1; } int syslog_name_lookup_id_by_name(const char *name, struct sl_name names[]) { return syslog_name_find_name(name, names); } int syslog_name_lookup_value_by_name(const char *name, struct sl_name names[]) { int i; i = syslog_name_find_name(name, names); if (i != -1) { return names[i].value; } return -1; } const char * syslog_name_lookup_name_by_value(int value, struct sl_name names[]) { int i; for (i = 0; names[i].name; i++) { if (names[i].value == value) { return names[i].name; } } return NULL; } guint32 syslog_make_range(guint32 value1, guint32 value2) { guint32 x; if (value1 > value2) { x = value2; value2 = value1; value1 = x; } return ((1 << (value2 + 1)) - 1) & ~((1 << value1) - 1); } syslog-ng-syslog-ng-4.4.0/lib/syslog-names.h000066400000000000000000000047531450431004300207240ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef __SYSLOG_NAMES_H_INCLUDED #define __SYSLOG_NAMES_H_INCLUDED #include "syslog-ng.h" #define SYSLOG_FACMASK 0x03f8 /* mask to extract facility part */ /* facility of pri */ #define SYSLOG_FAC(p) (((p) & SYSLOG_FACMASK) >> 3) #define SYSLOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ /* extract priority */ #define SYSLOG_PRI(p) ((p) & SYSLOG_PRIMASK) #define SYSLOG_SEVERITY_CODE(n) ((n) & 7) #define SYSLOG_FACILITY_CODE(n) ((n) << 3) struct sl_name { const char *name; int value; }; extern struct sl_name sl_severities[]; extern struct sl_name sl_facilities[]; /* returns an index where this name is found */ int syslog_name_lookup_id_by_name(const char *name, struct sl_name names[]); int syslog_name_lookup_value_by_name(const char *name, struct sl_name names[]); const char *syslog_name_lookup_name_by_value(int value, struct sl_name names[]); guint32 syslog_make_range(guint32 r1, guint32 r2); static inline guint32 syslog_name_lookup_severity_by_name(const gchar *name) { return syslog_name_lookup_value_by_name(name, sl_severities); } static inline guint32 syslog_name_lookup_facility_by_name(const gchar *name) { return syslog_name_lookup_value_by_name(name, sl_facilities); } static inline const gchar * syslog_name_lookup_severity_by_value(int value) { return syslog_name_lookup_name_by_value(value, sl_severities); } static inline const gchar * syslog_name_lookup_facility_by_value(int value) { return syslog_name_lookup_name_by_value(value, sl_facilities); } #endif syslog-ng-syslog-ng-4.4.0/lib/syslog-ng.h000066400000000000000000000044051450431004300202170ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SYSLOG_NG_H_INCLUDED #define SYSLOG_NG_H_INCLUDED #include #if SYSLOG_NG_ENABLE_DEBUG #undef YYDEBUG #define YYDEBUG 1 #endif #include "compat/glib.h" #include "versioning.h" #define PATH_SYSLOG_NG_CONF SYSLOG_NG_PATH_SYSCONFDIR "/syslog-ng.conf" #define PATH_INSTALL_DAT SYSLOG_NG_PATH_SYSCONFDIR "/install.dat" #define PATH_PIDFILE SYSLOG_NG_PATH_PIDFILEDIR "/syslog-ng.pid" #define PATH_CONTROL_SOCKET SYSLOG_NG_PATH_PIDFILEDIR "/syslog-ng.ctl" #if SYSLOG_NG_ENABLE_ENV_WRAPPER #define PATH_SYSLOGNG SYSLOG_NG_PATH_LIBEXECDIR "/syslog-ng" #endif #define PATH_PERSIST_CONFIG SYSLOG_NG_PATH_LOCALSTATEDIR "/syslog-ng.persist" typedef struct _LogPipe LogPipe; typedef struct _LogMessage LogMessage; typedef struct _GlobalConfig GlobalConfig; typedef struct _CfgLexer CfgLexer; typedef struct _PluginContext PluginContext; typedef struct _Bookmark Bookmark; typedef struct _AckTracker AckTracker; typedef struct _AckRecord AckRecord; typedef struct _AckTrackerFactory AckTrackerFactory; typedef struct _StatsClusterKey StatsClusterKey; typedef struct _StatsClusterLabel StatsClusterLabel; /* configuration being parsed, used by the bison generated code, NULL whenever parsing is finished. */ extern GlobalConfig *configuration; #endif syslog-ng-syslog-ng-4.4.0/lib/template/000077500000000000000000000000001450431004300177345ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/template/CMakeLists.txt000066400000000000000000000010631450431004300224740ustar00rootroot00000000000000set(TEMPLATE_HEADERS template/templates.h template/macros.h template/function.h template/eval.h template/simple-function.h template/repr.h template/compiler.h template/user-function.h template/escaping.h template/common-template-typedefs.h PARENT_SCOPE) set(TEMPLATE_SOURCES template/templates.c template/macros.c template/eval.c template/simple-function.c template/repr.c template/compiler.c template/user-function.c template/escaping.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/template/Makefile.am000066400000000000000000000013561450431004300217750ustar00rootroot00000000000000templateincludedir = ${pkgincludedir}/template EXTRA_DIST += lib/template/CMakeLists.txt \ lib/template/tests/CMakeLists.txt templateinclude_HEADERS = \ lib/template/templates.h \ lib/template/macros.h \ lib/template/function.h \ lib/template/eval.h \ lib/template/simple-function.h \ lib/template/repr.h \ lib/template/compiler.h \ lib/template/user-function.h \ lib/template/escaping.h \ lib/template/common-template-typedefs.h template_sources = \ lib/template/templates.c \ lib/template/macros.c \ lib/template/eval.c \ lib/template/simple-function.c \ lib/template/repr.c \ lib/template/compiler.c \ lib/template/user-function.c \ lib/template/escaping.c include lib/template/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/template/common-template-typedefs.h000066400000000000000000000022151450431004300250270ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef COMMON_TYPEDEFS_H_INCLUDED #define COMMON_TYPEDEFS_H_INCLUDED typedef struct _LogTemplateOptions LogTemplateOptions; typedef struct _LogTemplate LogTemplate; #endif syslog-ng-syslog-ng-4.4.0/lib/template/compiler.c000066400000000000000000000303541450431004300217170ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/compiler.h" #include "template/templates.h" #include "template/repr.h" #include "template/macros.h" #include "plugin.h" static void log_template_add_macro_elem(LogTemplateCompiler *self, guint macro, gchar *default_value) { LogTemplateElem *e; e = log_template_elem_new_macro(self->text->str, macro, default_value, self->msg_ref); self->result = g_list_prepend(self->result, e); } static void log_template_add_value_elem(LogTemplateCompiler *self, gchar *value_name, gsize value_name_len, gchar *default_value) { LogTemplateElem *e; gchar *value_name_z = g_strndup(value_name, value_name_len); e = log_template_elem_new_value(self->text->str, value_name_z, default_value, self->msg_ref); g_free(value_name_z); self->result = g_list_prepend(self->result, e); } /* NOTE: this steals argv if successful */ static gboolean log_template_add_func_elem(LogTemplateCompiler *self, gint argc, gchar *argv[], GError **error) { LogTemplateElem *e; if (argc == 0) return TRUE; e = log_template_elem_new_func(self->template, self->text->str, argc, argv, self->msg_ref, error); if (!e) return FALSE; self->result = g_list_prepend(self->result, e); return TRUE; } static void parse_msg_ref(LogTemplateCompiler *self) { self->msg_ref = 0; if ((*self->cursor) == '@') { self->cursor++; if ((*self->cursor) >= '0' && (*self->cursor) <= '9') { /* syntax: ${name}@1 to denote the log message index in the correlation state */ while ((*self->cursor) >= '0' && (*self->cursor) <= '9') { self->msg_ref += self->msg_ref * 10 + ((*self->cursor) - '0'); self->cursor++; } self->msg_ref += 1; } else { if ((*self->cursor) != '@') { msg_warning("Non-numeric correlation state ID found, assuming a literal '@' character. To avoid confusion when using a literal '@' after a macro or template function, write '@@' in the template.", evt_tag_str("Template", self->template->template_str)); self->cursor--; } self->msg_ref = 0; } } } static void log_template_compiler_fill_compile_error(GError **error, const gchar *error_info, gint error_pos) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "%s, error_pos='%d'", error_info, error_pos); } static void log_template_compiler_append_and_increment(LogTemplateCompiler *self, GString *text) { g_string_append_c(text, *self->cursor); self->cursor++; } static gint log_template_compiler_get_macro_length(gchar *start, gchar *end, gchar **token) { gint result = 0; gchar *colon = memchr(start, ':', end - start - 1); if (colon) { result = colon - start; *token = colon < end ? colon + 1 : NULL; } else { result = end - start - 1; *token = NULL; } return result; } static gchar * log_template_compiler_get_default_value(LogTemplateCompiler *self, gchar *token) { g_assert(token); if (*token != '-') { return NULL; } return g_strndup(token + 1, self->cursor - token - 2); } static inline gboolean is_macro_name(gchar c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_') || (c >= '0' && c <= '9'); } #define STEP_BY_TRUE(p, x) while(x) p++; static void log_template_compiler_add_elem(LogTemplateCompiler *self, gchar *start, gint macro_len, gchar *default_value) { gint macro = log_macro_lookup(start, macro_len); if (macro == M_NONE) { log_template_add_value_elem(self, start, macro_len, default_value); } else { log_template_add_macro_elem(self, macro, default_value); } } static gboolean log_template_compiler_process_braced_template(LogTemplateCompiler *self, GError **error) { gint macro_len; gchar *default_value = NULL; gchar *start; gchar *end; gchar *token; self->cursor++; start = self->cursor; end = strchr(self->cursor, '}'); if (!end) { log_template_compiler_fill_compile_error(error, "Invalid macro, '}' is missing", strlen(self->template->template_str)); return FALSE; } self->cursor = end + 1; macro_len = log_template_compiler_get_macro_length(start, self->cursor, &token); if (token) { default_value = log_template_compiler_get_default_value(self, token); if (!default_value) { log_template_compiler_fill_compile_error(error, "Unknown substitution function", token - self->template->template_str); return FALSE; } } parse_msg_ref(self); log_template_compiler_add_elem(self, start, macro_len, default_value); return TRUE; } static gboolean log_template_compiler_add_quoted_string(LogTemplateCompiler *self, gboolean is_top_level, GString *result) { gchar *quote = self->cursor; gchar *end_of_quote = strchr(quote + 1, *quote); if (!end_of_quote) { return FALSE; } self->cursor = end_of_quote + 1; if (is_top_level) { /* skip the quote in top-level and don't skip in expressions enclosed in parens */ quote++; } else { end_of_quote++; } g_string_append_len(result, quote, end_of_quote - quote); return TRUE; } static gboolean log_template_compiler_process_arg_list(LogTemplateCompiler *self, GPtrArray *result) { GString *arg_buf = g_string_sized_new(32); gboolean arg_buf_has_a_value = FALSE; gint parens = 1; self->cursor++; while (*self->cursor && g_ascii_isspace(*self->cursor)) self->cursor++; while(*self->cursor) { if (*self->cursor == '\\') { self->cursor++; } else if (*self->cursor == '(') { parens++; } else if (*self->cursor == ')') { parens--; if (parens == 0) { break; } } else if (*self->cursor == '"' || *self->cursor == '\'') { if (!log_template_compiler_add_quoted_string(self, parens == 1, arg_buf)) { g_ptr_array_add(result, NULL); g_string_free(arg_buf, TRUE); return FALSE; } arg_buf_has_a_value = TRUE; continue; } else if (parens == 1 && g_ascii_isspace(*self->cursor)) { g_ptr_array_add(result, g_strndup(arg_buf->str, arg_buf->len)); g_string_truncate(arg_buf, 0); arg_buf_has_a_value = FALSE; while (*self->cursor && g_ascii_isspace(*self->cursor)) self->cursor++; continue; } log_template_compiler_append_and_increment(self, arg_buf); arg_buf_has_a_value = TRUE; } if (arg_buf_has_a_value) { g_ptr_array_add(result, g_strndup(arg_buf->str, arg_buf->len)); } g_ptr_array_add(result, NULL); g_string_free(arg_buf, TRUE); return *self->cursor == ')'; } static gboolean log_template_compiler_process_template_function(LogTemplateCompiler *self, GError **error) { GPtrArray *strv = g_ptr_array_new(); if (!log_template_compiler_process_arg_list(self, strv)) { log_template_compiler_fill_compile_error(error, "Invalid template function reference, missing function name or imbalanced '('", self->cursor - self->template->template_str); goto error; } self->cursor++; parse_msg_ref(self); if (!log_template_add_func_elem(self, strv->len - 1, (gchar **) strv->pdata, error)) { goto error; } g_ptr_array_free(strv, FALSE); return TRUE; error: g_strfreev((gchar **)strv->pdata); g_ptr_array_free(strv, FALSE); return FALSE; } static void log_template_compiler_process_unbraced_template(LogTemplateCompiler *self) { gchar *start = self->cursor; gint macro_len; do { self->cursor++; } while (is_macro_name(*self->cursor)); macro_len = self->cursor - start; log_template_compiler_add_elem(self, start, macro_len, NULL); } static void log_template_compiler_process_dollar_asterisk(LogTemplateCompiler *self) { self->cursor++; log_template_add_macro_elem(self, M__ASTERISK, NULL); } static gboolean log_template_compiler_process_value(LogTemplateCompiler *self, GError **error) { gboolean finished = FALSE; gchar p; self->cursor++; p = *self->cursor; /* macro reference */ if (p == '{') { if (!log_template_compiler_process_braced_template(self, error)) { return FALSE; } finished = TRUE; } /* template function */ else if (p == '(') { if (!log_template_compiler_process_template_function(self, error)) { return FALSE; } finished = TRUE; } /* unbraced macro */ else if (is_macro_name(p)) { log_template_compiler_process_unbraced_template(self); finished = TRUE; } else if (p == '*') { log_template_compiler_process_dollar_asterisk(self); finished = TRUE; } /* escaped value with dollar */ else { if (p != '$') { g_string_append_c(self->text, '$'); } if (p) { log_template_compiler_append_and_increment(self, self->text); } } if (finished) { g_string_truncate(self->text, 0); } return TRUE; } gboolean log_template_compiler_process_token(LogTemplateCompiler *self, GError **error) { self->msg_ref = 0; if (*self->cursor == '$') { return log_template_compiler_process_value(self, error); } if (*self->cursor == '\\') { if (cfg_is_config_version_older(self->template->cfg, VERSION_VALUE_3_5)) { msg_warning("Template escaping changed in version " VERSION_3_5 ". " "Use '$$' to specify a literal dollar sign instead of '\\$' and " "remove the escaping of the backslash character when you upgrade " "your configuration", evt_tag_str("Template", self->template->template_str)); self->cursor++; } } if (*self->cursor) { log_template_compiler_append_and_increment(self, self->text); } return TRUE; } static void log_template_compiler_free_result(LogTemplateCompiler *self) { log_template_elem_free_list(self->result); self->result = NULL; } gboolean log_template_compiler_compile(LogTemplateCompiler *self, GList **compiled_template, GError **error) { gboolean result = FALSE; while (*self->cursor) { if (!log_template_compiler_process_token(self, error)) { log_template_compiler_free_result(self); g_string_printf(self->text, "error in template: %s", self->template->template_str); log_template_add_macro_elem(self, M_NONE, NULL); goto error; } } if (self->text->len) { log_template_add_macro_elem(self, M_NONE, NULL); } result = TRUE; error: *compiled_template = g_list_reverse(self->result); self->result = NULL; return result; } void log_template_compiler_init(LogTemplateCompiler *self, LogTemplate *template) { memset(self, 0, sizeof(*self)); self->template = log_template_ref(template); self->cursor = self->template->template_str; self->text = g_string_sized_new(32); } void log_template_compiler_clear(LogTemplateCompiler *self) { log_template_unref(self->template); g_string_free(self->text, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/template/compiler.h000066400000000000000000000027631450431004300217270ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_COMPILER_H_INCLUDED #define TEMPLATE_COMPILER_H_INCLUDED #include "syslog-ng.h" #include "templates.h" typedef struct { LogTemplate *template; GList *result; gchar *cursor; GString *text; gint msg_ref; } LogTemplateCompiler; gboolean log_template_compiler_compile(LogTemplateCompiler *self, GList **compiled_template, GError **error); void log_template_compiler_init(LogTemplateCompiler *self, LogTemplate *template); void log_template_compiler_clear(LogTemplateCompiler *self); #endif syslog-ng-syslog-ng-4.4.0/lib/template/escaping.c000066400000000000000000000034411450431004300216730ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/escaping.h" #include "str-format.h" #include void result_append(GString *result, const gchar *sstr, gssize len, gboolean escape) { gint i; const guchar *ustr = (const guchar *) sstr; if (len < 0) len = strlen(sstr); if (escape) { for (i = 0; i < len; i++) { if (ustr[i] == '\'' || ustr[i] == '"' || ustr[i] == '\\') { g_string_append_c(result, '\\'); g_string_append_c(result, ustr[i]); } else if (ustr[i] < ' ') { g_string_append_c(result, '\\'); format_uint32_padded(result, 3, '0', 8, ustr[i]); } else g_string_append_c(result, ustr[i]); } } else g_string_append_len(result, sstr, len); } syslog-ng-syslog-ng-4.4.0/lib/template/escaping.h000066400000000000000000000022571450431004300217040ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_ESCAPING_H_INCLUDED #define TEMPLATE_ESCAPING_H_INCLUDED 1 #include "syslog-ng.h" void result_append(GString *result, const gchar *sstr, gssize len, gboolean escape); #endif syslog-ng-syslog-ng-4.4.0/lib/template/eval.c000066400000000000000000000215271450431004300210360ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * Copyright (c) 2020 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "eval.h" #include "repr.h" #include "macros.h" #include "escaping.h" #include "cfg.h" #include "scratch-buffers.h" #include "templates.h" static LogMessageValueType _propagate_type(LogMessageValueType acc_type, LogMessageValueType elem_type) { /* NOTE: if this assertion fails, it means that a macro/template function * does not return a valid type. We are not defaulting to strings in this * case so we make a conscious decision on typing every time we add a new * macro/template function. */ g_assert(elem_type != LM_VT_NONE); if (acc_type == LM_VT_NONE) acc_type = elem_type; return acc_type; } static gboolean _should_render(const gchar *value, LogMessageValueType value_type, LogMessageValueType type_hint) { if (value_type == LM_VT_BYTES || value_type == LM_VT_PROTOBUF) return value_type == type_hint; return !!value[0]; } void log_template_append_format_value_and_type_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type) { LogTemplateElem *e; LogMessageValueType t = LM_VT_NONE; gboolean first_elem = TRUE; if (!options->opts) options->opts = &self->cfg->template_options; if (self->escape) t = LM_VT_STRING; for (GList *p = self->compiled_template; p; p = g_list_next(p), first_elem = FALSE) { gint msg_ndx; if (!first_elem) { /* this is the 2nd elem in the compiled template, we are * concatenating multiple elements, convert the value to string */ t = LM_VT_STRING; } e = (LogTemplateElem *) p->data; if (e->text) { g_string_append_len(result, e->text, e->text_len); /* concatenating literal text */ if (e->text_len) t = LM_VT_STRING; } /* NOTE: msg_ref is 1 larger than the index specified by the user in * order to make it distinguishable from the zero value. Therefore * the '>' instead of '>=' * * msg_ref == 0 means that the user didn't specify msg_ref * msg_ref >= 1 means that the user supplied the given msg_ref, 1 is equal to @0 */ if (e->msg_ref > num_messages) { /* msg_ref out of range, we expand to empty string without evaluating the element */ t = LM_VT_STRING; continue; } msg_ndx = num_messages - e->msg_ref; /* value and macro can't understand a context, assume that no msg_ref means @0 */ if (e->msg_ref == 0) msg_ndx--; switch (e->type) { case LTE_VALUE: { const gchar *value = NULL; gssize value_len = -1; LogMessageValueType value_type = LM_VT_NONE; value = log_msg_get_value_with_type(messages[msg_ndx], e->value_handle, &value_len, &value_type); if (value && _should_render(value, value_type, self->type_hint)) { result_append(result, value, value_len, self->escape); } else if (e->default_value) { result_append(result, e->default_value, -1, self->escape); value_type = LM_VT_STRING; } else if (value_type == LM_VT_BYTES || value_type == LM_VT_PROTOBUF) { value_type = LM_VT_NULL; } t = _propagate_type(t, value_type); break; } case LTE_MACRO: { gint len = result->len; LogMessageValueType value_type = LM_VT_NONE; if (e->macro) { log_macro_expand(e->macro, self->escape, options, messages[msg_ndx], result, &value_type); if (len == result->len && e->default_value) g_string_append(result, e->default_value); t = _propagate_type(t, value_type); } break; } case LTE_FUNC: { LogTemplateInvokeArgs args = { e->msg_ref ? &messages[msg_ndx] : messages, e->msg_ref ? 1 : num_messages, options, }; LogMessageValueType value_type = LM_VT_NONE; /* if a function call is called with an msg_ref, we only * pass that given logmsg to argument resolution, otherwise * we pass the whole set so the arguments can individually * specify which message they want to resolve from */ if (e->func.ops->eval) e->func.ops->eval(e->func.ops, e->func.state, &args); e->func.ops->call(e->func.ops, e->func.state, &args, result, &value_type); t = _propagate_type(t, value_type); break; } default: g_assert_not_reached(); break; } } if (type) { if (first_elem && t == LM_VT_NONE) { /* empty template string, use LM_VT_STRING before applying the type-cast */ t = LM_VT_STRING; } /* apply cast */ t = _propagate_type(self->type_hint, t); /* default to string if none */ *type = _propagate_type(t, LM_VT_STRING); } } void log_template_append_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result) { log_template_append_format_value_and_type_with_context(self, messages, num_messages, options, result, NULL); } void log_template_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result) { g_string_truncate(result, 0); log_template_append_format_with_context(self, messages, num_messages, options, result); } void log_template_append_format_value_and_type(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type) { log_template_append_format_value_and_type_with_context(self, &lm, 1, options, result, type); } void log_template_append_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result) { log_template_append_format_value_and_type(self, lm, options, result, NULL); } void log_template_format_value_and_type(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type) { g_string_truncate(result, 0); log_template_append_format_value_and_type(self, lm, options, result, type); } void log_template_format_value_and_type_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type) { g_string_truncate(result, 0); log_template_append_format_value_and_type_with_context(self, messages, num_messages, options, result, type); } void log_template_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result) { log_template_format_value_and_type(self, lm, options, result, NULL); } guint log_template_hash(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options) { if (log_template_is_literal_string(self)) return g_str_hash(log_template_get_literal_value(self, NULL)); if (log_template_is_trivial(self)) { NVHandle handle = log_template_get_trivial_value_handle(self); g_assert(handle != LM_V_NONE); return g_str_hash(log_msg_get_value(lm, handle, NULL)); } ScratchBuffersMarker mark; GString *buffer = scratch_buffers_alloc_and_mark(&mark); log_template_format(self, lm, options, buffer); guint hash = g_str_hash(buffer->str); scratch_buffers_reclaim_marked(mark); return hash; } syslog-ng-syslog-ng-4.4.0/lib/template/eval.h000066400000000000000000000077331450431004300210460ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * Copyright (c) 2020 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_EVAL_H_INCLUDED #define TEMPLATE_EVAL_H_INCLUDED 1 #include "syslog-ng.h" #include "common-template-typedefs.h" #include "timeutils/zoneinfo.h" #include "logmsg/logmsg.h" #define LTZ_LOCAL 0 #define LTZ_SEND 1 #define LTZ_MAX 2 /* template expansion options that can be influenced by the user and * is static throughout the runtime for a given configuration. There * are call-site specific options too, those are specified as * arguments to log_template_format() */ struct _LogTemplateOptions { gboolean initialized; /* timestamp format as specified by ts_format() */ gint ts_format; /* number of digits in the fraction of a second part, specified using frac_digits() */ gint frac_digits; gboolean use_fqdn; /* timezone for LTZ_LOCAL/LTZ_SEND settings */ gchar *time_zone[LTZ_MAX]; TimeZoneInfo *time_zone_info[LTZ_MAX]; /* Template error handling settings */ gint on_error; }; typedef struct _LogTemplateEvalOptions { /* options for recursive template evaluation, inherited from the parent */ const LogTemplateOptions *opts; gint tz; gint seq_num; const gchar *context_id; LogMessageValueType context_id_type; } LogTemplateEvalOptions; #define DEFAULT_TEMPLATE_EVAL_OPTIONS ((LogTemplateEvalOptions){NULL, LTZ_LOCAL, 0, NULL, LM_VT_STRING}) void log_template_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result); void log_template_format_value_and_type(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type); void log_template_append_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result); void log_template_append_format_value_and_type(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type); void log_template_append_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result); void log_template_append_format_value_and_type_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type); void log_template_format_value_and_type_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result, LogMessageValueType *type); void log_template_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages, LogTemplateEvalOptions *options, GString *result); guint log_template_hash(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/template/function.h000066400000000000000000000103671450431004300217410ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_FUNCTION_H_INCLUDED #define TEMPLATE_FUNCTION_H_INCLUDED #include "syslog-ng.h" #include "plugin-types.h" #include "common-template-typedefs.h" #define TEMPLATE_INVOKE_MAX_ARGS 64 /* This structure contains the arguments for template-function * expansion. It is defined in a struct because otherwise a large * number of function arguments, that are passed around, possibly * several times. */ typedef struct _LogTemplateInvokeArgs { /* context in case of correlation */ LogMessage **messages; gint num_messages; LogTemplateEvalOptions *options; GString *argv[TEMPLATE_INVOKE_MAX_ARGS]; } LogTemplateInvokeArgs; typedef struct _LogTemplateFunction LogTemplateFunction; struct _LogTemplateFunction { /* size of the state that carries information from parse-time to * runtime. Can be used to store the results of expensive * operations that don't need to be performed for all invocations */ gint size_of_state; /* called when parsing the arguments to be compiled into an internal * representation if necessary. Returns the compiled state in state */ gboolean (*prepare)(LogTemplateFunction *self, gpointer state, LogTemplate *parent, gint argc, gchar *argv[], GError **error); /* evaluate arguments, storing argument buffers in arg_bufs in case it * makes sense to reuse those buffers */ void (*eval)(LogTemplateFunction *self, gpointer state, LogTemplateInvokeArgs *args); /* call the function */ void (*call)(LogTemplateFunction *self, gpointer state, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type); /* free data in state */ void (*free_state)(gpointer s); /* free LogTemplateFunction instance (if not static) */ void (*free_fn)(LogTemplateFunction *self); /* generic argument that can be used to pass information from registration time */ gpointer arg; }; #define TEMPLATE_FUNCTION_PROTOTYPE(prefix) \ gpointer \ prefix ## _construct(Plugin *self) #define TEMPLATE_FUNCTION_DECLARE(prefix) \ TEMPLATE_FUNCTION_PROTOTYPE(prefix); /* helper macros for template function plugins */ #define TEMPLATE_FUNCTION(state_struct, prefix, prepare, eval, call, free_state, arg) \ TEMPLATE_FUNCTION_PROTOTYPE(prefix) \ { \ static LogTemplateFunction func = { \ sizeof(state_struct), \ prepare, \ eval, \ call, \ free_state, \ NULL, \ arg \ }; \ return &func; \ } #define TEMPLATE_FUNCTION_PLUGIN(x, tf_name) \ { \ .type = LL_CONTEXT_TEMPLATE_FUNC, \ .name = tf_name, \ .construct = x ## _construct, \ } #endif syslog-ng-syslog-ng-4.4.0/lib/template/macros.c000066400000000000000000000552301450431004300213710ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/macros.h" #include "template/escaping.h" #include "timeutils/cache.h" #include "timeutils/names.h" #include "timeutils/unixtime.h" #include "timeutils/format.h" #include "timeutils/misc.h" #include "timeutils/conv.h" #include "messages.h" #include "str-format.h" #include "run-id.h" #include "host-id.h" #include "rcptid.h" #include "logmsg/logmsg.h" #include "syslog-names.h" #include "hostname.h" #include "template/templates.h" #include "cfg.h" #include LogMacroDef macros[] = { { "FACILITY", M_FACILITY }, { "FACILITY_NUM", M_FACILITY_NUM }, { "SEVERITY", M_SEVERITY }, { "SEVERITY_NUM", M_SEVERITY_NUM }, /* these are obsolete aliases of $SEVERITY that we support for compatibility only */ { "PRIORITY", M_SEVERITY }, /* deprecated */ { "LEVEL", M_SEVERITY }, /* deprecated */ { "LEVEL_NUM", M_SEVERITY_NUM }, /* deprecated */ { "TAG", M_TAG }, { "TAGS", M_TAGS }, { "BSDTAG", M_BSDTAG }, { "PRI", M_PRI }, { "DATE", M_DATE }, { "FULLDATE", M_FULLDATE }, { "ISODATE", M_ISODATE }, { "STAMP", M_STAMP }, { "YEAR", M_YEAR }, { "YEAR_DAY", M_YEAR_DAY }, { "MONTH", M_MONTH }, { "MONTH_WEEK", M_MONTH_WEEK }, { "MONTH_ABBREV", M_MONTH_ABBREV }, { "MONTH_NAME", M_MONTH_NAME }, { "DAY", M_DAY }, { "HOUR", M_HOUR }, { "HOUR12", M_HOUR12 }, { "MIN", M_MIN }, { "SEC", M_SEC }, { "USEC", M_USEC }, { "MSEC", M_MSEC }, { "AMPM", M_AMPM }, { "WEEKDAY", M_WEEK_DAY_ABBREV }, /* deprecated */ { "WEEK_DAY", M_WEEK_DAY }, { "WEEK_DAY_ABBREV", M_WEEK_DAY_ABBREV }, { "WEEK_DAY_NAME", M_WEEK_DAY_NAME }, { "WEEK", M_WEEK }, { "ISOWEEK", M_ISOWEEK }, { "TZOFFSET", M_TZOFFSET }, { "TZ", M_TZ }, { "SYSUPTIME", M_SYSUPTIME }, { "UNIXTIME", M_UNIXTIME }, { "R_DATE", M_RECVD_OFS + M_DATE }, { "R_FULLDATE", M_RECVD_OFS + M_FULLDATE }, { "R_ISODATE", M_RECVD_OFS + M_ISODATE }, { "R_STAMP", M_RECVD_OFS + M_STAMP }, { "R_YEAR", M_RECVD_OFS + M_YEAR }, { "R_YEAR_DAY", M_RECVD_OFS + M_YEAR_DAY }, { "R_MONTH", M_RECVD_OFS + M_MONTH }, { "R_MONTH_WEEK", M_RECVD_OFS + M_MONTH_WEEK }, { "R_MONTH_ABBREV", M_RECVD_OFS + M_MONTH_ABBREV }, { "R_MONTH_NAME", M_RECVD_OFS + M_MONTH_NAME }, { "R_DAY", M_RECVD_OFS + M_DAY }, { "R_HOUR", M_RECVD_OFS + M_HOUR }, { "R_HOUR12", M_RECVD_OFS + M_HOUR12 }, { "R_MIN", M_RECVD_OFS + M_MIN }, { "R_SEC", M_RECVD_OFS + M_SEC }, { "R_MSEC", M_RECVD_OFS + M_MSEC }, { "R_USEC", M_RECVD_OFS + M_USEC }, { "R_AMPM", M_RECVD_OFS + M_AMPM }, { "R_WEEKDAY", M_RECVD_OFS + M_WEEK_DAY_ABBREV }, /* deprecated */ { "R_WEEK_DAY", M_RECVD_OFS + M_WEEK_DAY }, { "R_WEEK_DAY_ABBREV", M_RECVD_OFS + M_WEEK_DAY_ABBREV }, { "R_WEEK_DAY_NAME", M_RECVD_OFS + M_WEEK_DAY_NAME }, { "R_WEEK", M_RECVD_OFS + M_WEEK }, { "R_ISOWEEK", M_RECVD_OFS + M_ISOWEEK }, { "R_TZOFFSET", M_RECVD_OFS + M_TZOFFSET }, { "R_TZ", M_RECVD_OFS + M_TZ }, { "R_UNIXTIME", M_RECVD_OFS + M_UNIXTIME }, { "S_DATE", M_STAMP_OFS + M_DATE }, { "S_FULLDATE", M_STAMP_OFS + M_FULLDATE }, { "S_ISODATE", M_STAMP_OFS + M_ISODATE }, { "S_STAMP", M_STAMP_OFS + M_STAMP }, { "S_YEAR", M_STAMP_OFS + M_YEAR }, { "S_YEAR_DAY", M_STAMP_OFS + M_YEAR_DAY }, { "S_MONTH", M_STAMP_OFS + M_MONTH }, { "S_MONTH_WEEK", M_STAMP_OFS + M_MONTH_WEEK }, { "S_MONTH_ABBREV", M_STAMP_OFS + M_MONTH_ABBREV }, { "S_MONTH_NAME", M_STAMP_OFS + M_MONTH_NAME }, { "S_DAY", M_STAMP_OFS + M_DAY }, { "S_HOUR", M_STAMP_OFS + M_HOUR }, { "S_HOUR12", M_STAMP_OFS + M_HOUR12 }, { "S_MIN", M_STAMP_OFS + M_MIN }, { "S_SEC", M_STAMP_OFS + M_SEC }, { "S_MSEC", M_STAMP_OFS + M_MSEC }, { "S_USEC", M_STAMP_OFS + M_USEC }, { "S_AMPM", M_STAMP_OFS + M_AMPM }, { "S_WEEKDAY", M_STAMP_OFS + M_WEEK_DAY_ABBREV }, /* deprecated */ { "S_WEEK_DAY", M_STAMP_OFS + M_WEEK_DAY }, { "S_WEEK_DAY_ABBREV", M_STAMP_OFS + M_WEEK_DAY_ABBREV }, { "S_WEEK_DAY_NAME", M_STAMP_OFS + M_WEEK_DAY_NAME }, { "S_WEEK", M_STAMP_OFS + M_WEEK }, { "S_ISOWEEK", M_STAMP_OFS + M_ISOWEEK }, { "S_TZOFFSET", M_STAMP_OFS + M_TZOFFSET }, { "S_TZ", M_STAMP_OFS + M_TZ }, { "S_UNIXTIME", M_STAMP_OFS + M_UNIXTIME }, { "C_DATE", M_CSTAMP_OFS + M_DATE }, { "C_FULLDATE", M_CSTAMP_OFS + M_FULLDATE }, { "C_ISODATE", M_CSTAMP_OFS + M_ISODATE }, { "C_STAMP", M_CSTAMP_OFS + M_STAMP }, { "C_YEAR", M_CSTAMP_OFS + M_YEAR }, { "C_YEAR_DAY", M_CSTAMP_OFS + M_YEAR_DAY }, { "C_MONTH", M_CSTAMP_OFS + M_MONTH }, { "C_MONTH_WEEK", M_CSTAMP_OFS + M_MONTH_WEEK }, { "C_MONTH_ABBREV", M_CSTAMP_OFS + M_MONTH_ABBREV }, { "C_MONTH_NAME", M_CSTAMP_OFS + M_MONTH_NAME }, { "C_DAY", M_CSTAMP_OFS + M_DAY }, { "C_HOUR", M_CSTAMP_OFS + M_HOUR }, { "C_HOUR12", M_CSTAMP_OFS + M_HOUR12 }, { "C_MIN", M_CSTAMP_OFS + M_MIN }, { "C_SEC", M_CSTAMP_OFS + M_SEC }, { "C_MSEC", M_CSTAMP_OFS + M_MSEC }, { "C_USEC", M_CSTAMP_OFS + M_USEC }, { "C_AMPM", M_CSTAMP_OFS + M_AMPM }, { "C_WEEKDAY", M_CSTAMP_OFS + M_WEEK_DAY_ABBREV }, /* deprecated */ { "C_WEEK_DAY", M_CSTAMP_OFS + M_WEEK_DAY }, { "C_WEEK_DAY_ABBREV", M_CSTAMP_OFS + M_WEEK_DAY_ABBREV }, { "C_WEEK_DAY_NAME", M_CSTAMP_OFS + M_WEEK_DAY_NAME }, { "C_WEEK", M_CSTAMP_OFS + M_WEEK }, { "C_ISOWEEK", M_CSTAMP_OFS + M_ISOWEEK }, { "C_TZOFFSET", M_CSTAMP_OFS + M_TZOFFSET }, { "C_TZ", M_CSTAMP_OFS + M_TZ }, { "C_UNIXTIME", M_CSTAMP_OFS + M_UNIXTIME }, { "P_DATE", M_PROCESSED_OFS + M_DATE }, { "P_FULLDATE", M_PROCESSED_OFS + M_FULLDATE }, { "P_ISODATE", M_PROCESSED_OFS + M_ISODATE }, { "P_STAMP", M_PROCESSED_OFS + M_STAMP }, { "P_YEAR", M_PROCESSED_OFS + M_YEAR }, { "P_YEAR_DAY", M_PROCESSED_OFS + M_YEAR_DAY }, { "P_MONTH", M_PROCESSED_OFS + M_MONTH }, { "P_MONTH_WEEK", M_PROCESSED_OFS + M_MONTH_WEEK }, { "P_MONTH_ABBREV", M_PROCESSED_OFS + M_MONTH_ABBREV }, { "P_MONTH_NAME", M_PROCESSED_OFS + M_MONTH_NAME }, { "P_DAY", M_PROCESSED_OFS + M_DAY }, { "P_HOUR", M_PROCESSED_OFS + M_HOUR }, { "P_HOUR12", M_PROCESSED_OFS + M_HOUR12 }, { "P_MIN", M_PROCESSED_OFS + M_MIN }, { "P_SEC", M_PROCESSED_OFS + M_SEC }, { "P_MSEC", M_PROCESSED_OFS + M_MSEC }, { "P_USEC", M_PROCESSED_OFS + M_USEC }, { "P_AMPM", M_PROCESSED_OFS + M_AMPM }, { "P_WEEKDAY", M_PROCESSED_OFS + M_WEEK_DAY_ABBREV }, /* deprecated */ { "P_WEEK_DAY", M_PROCESSED_OFS + M_WEEK_DAY }, { "P_WEEK_DAY_ABBREV", M_PROCESSED_OFS + M_WEEK_DAY_ABBREV }, { "P_WEEK_DAY_NAME", M_PROCESSED_OFS + M_WEEK_DAY_NAME }, { "P_WEEK", M_PROCESSED_OFS + M_WEEK }, { "P_ISOWEEK", M_PROCESSED_OFS + M_ISOWEEK }, { "P_TZOFFSET", M_PROCESSED_OFS + M_TZOFFSET }, { "P_TZ", M_PROCESSED_OFS + M_TZ }, { "P_UNIXTIME", M_PROCESSED_OFS + M_UNIXTIME }, { "SDATA", M_SDATA }, { "MSGHDR", M_MSGHDR }, { "SOURCEIP", M_SOURCE_IP }, { "DESTIP", M_DEST_IP }, { "DESTPORT", M_DEST_PORT }, { "PROTO", M_PROTOCOL }, { "RAWMSG_SIZE", M_RAWMSG_SIZE }, { "SEQNUM", M_SEQNUM }, { "CONTEXT_ID", M_CONTEXT_ID }, { "_", M_CONTEXT_ID }, { "RCPTID", M_RCPTID }, { "RUNID", M_RUNID }, { "HOSTID", M_HOSTID }, { "UNIQID", M_UNIQID }, /* values that have specific behaviour with older syslog-ng config versions */ { "MSG", M_MESSAGE }, { "MESSAGE", M_MESSAGE }, { "HOST", M_HOST }, /* message independent macros */ { "LOGHOST", M_LOGHOST }, { NULL, 0 } }; static GTimeVal app_uptime; static GHashTable *macro_hash; static LogTemplateOptions template_options_for_macro_expand; static void _result_append_value(GString *result, const LogMessage *lm, NVHandle handle, gboolean escape) { const gchar *str; gssize len = 0; str = log_msg_get_value(lm, handle, &len); result_append(result, str, len, escape); } static gboolean _is_message_source_an_ip_address(const LogMessage *msg) { if (!msg->saddr) return FALSE; if (g_sockaddr_inet_check(msg->saddr)) return TRUE; #if SYSLOG_NG_ENABLE_IPV6 if (g_sockaddr_inet6_check(msg->saddr)) return TRUE; #endif return FALSE; } static gboolean _is_message_dest_an_ip_address(const LogMessage *msg) { if (!msg->daddr) return FALSE; if (g_sockaddr_inet_check(msg->daddr)) return TRUE; #if SYSLOG_NG_ENABLE_IPV6 if (g_sockaddr_inet6_check(msg->daddr)) return TRUE; #endif return FALSE; } static void log_macro_expand_date_time(gint id, gboolean escape, LogTemplateEvalOptions *options, const LogMessage *msg, GString *result, LogMessageValueType *type) { /* year, month, day */ const UnixTime *stamp; UnixTime sstamp; guint tmp_hour; if (id >= M_TIME_FIRST && id <= M_TIME_LAST) { stamp = &msg->timestamps[LM_TS_STAMP]; } else if (id >= M_TIME_FIRST + M_RECVD_OFS && id <= M_TIME_LAST + M_RECVD_OFS) { id -= M_RECVD_OFS; stamp = &msg->timestamps[LM_TS_RECVD]; } else if (id >= M_TIME_FIRST + M_STAMP_OFS && id <= M_TIME_LAST + M_STAMP_OFS) { id -= M_STAMP_OFS; stamp = &msg->timestamps[LM_TS_STAMP]; } else if (id >= M_TIME_FIRST + M_CSTAMP_OFS && id <= M_TIME_LAST + M_CSTAMP_OFS) { id -= M_CSTAMP_OFS; unix_time_set_now(&sstamp); stamp = &sstamp; } else if (id >= M_TIME_FIRST + M_PROCESSED_OFS && id <= M_TIME_LAST + M_PROCESSED_OFS) { id -= M_PROCESSED_OFS; stamp = &msg->timestamps[LM_TS_PROCESSED]; if (!unix_time_is_set(stamp)) { unix_time_set_now(&sstamp); stamp = &sstamp; } } else { g_assert_not_reached(); return; } /* try to use the following zone values in order: * destination specific timezone, if one is specified * message specific timezone, if one is specified * local timezone */ WallClockTime wct; convert_unix_time_to_wall_clock_time_with_tz_override(stamp, &wct, time_zone_info_get_offset(options->opts->time_zone_info[options->tz], stamp->ut_sec)); switch (id) { case M_WEEK_DAY_ABBREV: g_string_append_len(result, weekday_names_abbrev[wct.wct_wday], WEEKDAY_NAME_ABBREV_LEN); break; case M_WEEK_DAY_NAME: g_string_append(result, weekday_names[wct.wct_wday]); break; case M_WEEK_DAY: format_uint32_padded(result, 0, 0, 10, wct.wct_wday + 1); break; case M_WEEK: format_uint32_padded(result, 2, '0', 10, (wct.wct_yday - (wct.wct_wday - 1 + 7) % 7 + 7) / 7); break; case M_ISOWEEK: format_uint32_padded(result, 2, '0', 10, wall_clock_time_iso_week_number(&wct)); break; case M_YEAR: format_uint32_padded(result, 4, '0', 10, wct.wct_year + 1900); break; case M_YEAR_DAY: format_uint32_padded(result, 3, '0', 10, wct.wct_yday + 1); break; case M_MONTH: format_uint32_padded(result, 2, '0', 10, wct.wct_mon + 1); break; case M_MONTH_WEEK: format_uint32_padded(result, 0, 0, 10, ((wct.wct_mday / 7) + ((wct.wct_wday > 0) && ((wct.wct_mday % 7) >= wct.wct_wday)))); break; case M_MONTH_ABBREV: g_string_append_len(result, month_names_abbrev[wct.wct_mon], MONTH_NAME_ABBREV_LEN); break; case M_MONTH_NAME: g_string_append(result, month_names[wct.wct_mon]); break; case M_DAY: format_uint32_padded(result, 2, '0', 10, wct.wct_mday); break; case M_HOUR: format_uint32_padded(result, 2, '0', 10, wct.wct_hour); break; case M_HOUR12: if (wct.wct_hour < 12) tmp_hour = wct.wct_hour; else tmp_hour = wct.wct_hour - 12; if (tmp_hour == 0) tmp_hour = 12; format_uint32_padded(result, 2, '0', 10, tmp_hour); break; case M_MIN: format_uint32_padded(result, 2, '0', 10, wct.wct_min); break; case M_SEC: format_uint32_padded(result, 2, '0', 10, wct.wct_sec); break; case M_MSEC: format_uint32_padded(result, 3, '0', 10, stamp->ut_usec/1000); break; case M_USEC: format_uint32_padded(result, 6, '0', 10, stamp->ut_usec); break; case M_AMPM: g_string_append(result, wct.wct_hour < 12 ? "AM" : "PM"); break; case M_DATE: append_format_wall_clock_time(&wct, result, TS_FMT_BSD, options->opts->frac_digits); break; case M_STAMP: if (options->opts->ts_format == TS_FMT_UNIX) append_format_unix_time(stamp, result, TS_FMT_UNIX, wct.wct_gmtoff, options->opts->frac_digits); else append_format_wall_clock_time(&wct, result, options->opts->ts_format, options->opts->frac_digits); break; case M_ISODATE: append_format_wall_clock_time(&wct, result, TS_FMT_ISO, options->opts->frac_digits); break; case M_FULLDATE: append_format_wall_clock_time(&wct, result, TS_FMT_FULL, options->opts->frac_digits); break; case M_UNIXTIME: *type = LM_VT_DATETIME; append_format_unix_time(stamp, result, TS_FMT_UNIX, wct.wct_gmtoff, options->opts->frac_digits); break; case M_TZ: case M_TZOFFSET: append_format_zone_info(result, wct.wct_gmtoff); break; default: g_assert_not_reached(); break; } } gboolean log_macro_expand(gint id, gboolean escape, LogTemplateEvalOptions *options, const LogMessage *msg, GString *result, LogMessageValueType *type) { LogMessageValueType t = LM_VT_STRING; switch (id) { case M_FACILITY: { /* facility */ const char *n; n = syslog_name_lookup_facility_by_value(msg->pri & SYSLOG_FACMASK); if (n) { g_string_append(result, n); } else { format_uint32_padded(result, 0, 0, 16, (msg->pri & SYSLOG_FACMASK) >> 3); } break; } case M_FACILITY_NUM: { t = LM_VT_INTEGER; format_uint32_padded(result, 0, 0, 10, (msg->pri & SYSLOG_FACMASK) >> 3); break; } case M_SEVERITY: { /* level */ const char *n; n = syslog_name_lookup_severity_by_value(msg->pri & SYSLOG_PRIMASK); if (n) { g_string_append(result, n); } else { format_uint32_padded(result, 0, 0, 10, msg->pri & SYSLOG_PRIMASK); } break; } case M_SEVERITY_NUM: { t = LM_VT_INTEGER; format_uint32_padded(result, 0, 0, 10, msg->pri & SYSLOG_PRIMASK); break; } case M_TAG: { format_uint32_padded(result, 2, '0', 16, msg->pri); break; } case M_TAGS: { t = LM_VT_LIST; log_msg_format_tags(msg, result); break; } case M__ASTERISK: { t = LM_VT_LIST; log_msg_format_matches(msg, result); break; } case M_BSDTAG: { format_uint32_padded(result, 0, 0, 10, (msg->pri & SYSLOG_PRIMASK)); g_string_append_c(result, (((msg->pri & SYSLOG_FACMASK) >> 3) + 'A')); break; } case M_PRI: { format_uint32_padded(result, 0, 0, 10, msg->pri); break; } case M_HOST: { if (msg->flags & LF_CHAINED_HOSTNAME) { /* host */ const gchar *p1, *p2; int remaining, length; gssize host_len; const gchar *host = log_msg_get_value(msg, LM_V_HOST, &host_len); p1 = memchr(host, '@', host_len); if (p1) p1++; else p1 = host; remaining = host_len - (p1 - host); p2 = memchr(p1, '/', remaining); length = p2 ? p2 - p1 : host_len - (p1 - host); result_append(result, p1, length, escape); } else { _result_append_value(result, msg, LM_V_HOST, escape); } break; } case M_SDATA: { if (escape) { GString *sdstr = g_string_sized_new(0); log_msg_append_format_sdata(msg, sdstr, options->seq_num); result_append(result, sdstr->str, sdstr->len, TRUE); g_string_free(sdstr, TRUE); } else { log_msg_append_format_sdata(msg, result, options->seq_num); } break; } case M_MSGHDR: { gssize len; const gchar *p; p = log_msg_get_value(msg, LM_V_LEGACY_MSGHDR, &len); if (len > 0) result_append(result, p, len, escape); else { /* message, complete with program name and pid */ len = result->len; _result_append_value(result, msg, LM_V_PROGRAM, escape); if (len != result->len) { const gchar *pid = log_msg_get_value(msg, LM_V_PID, &len); if (len > 0) { result_append(result, "[", 1, FALSE); result_append(result, pid, len, escape); result_append(result, "]", 1, FALSE); } result_append(result, ": ", 2, FALSE); } } break; } case M_MESSAGE: { _result_append_value(result, msg, LM_V_MESSAGE, escape); break; } case M_SOURCE_IP: { gchar *ip; gchar buf[MAX_SOCKADDR_STRING]; if (_is_message_source_an_ip_address(msg)) { g_sockaddr_format(msg->saddr, buf, sizeof(buf), GSA_ADDRESS_ONLY); ip = buf; } else { ip = "127.0.0.1"; } result_append(result, ip, strlen(ip), escape); break; } case M_DEST_IP: { gchar *ip; gchar buf[MAX_SOCKADDR_STRING]; if (_is_message_dest_an_ip_address(msg)) { g_sockaddr_format(msg->daddr, buf, sizeof(buf), GSA_ADDRESS_ONLY); ip = buf; } else { ip = "127.0.0.1"; } result_append(result, ip, strlen(ip), escape); break; } case M_DEST_PORT: { gint port; if (_is_message_dest_an_ip_address(msg)) { port = g_sockaddr_get_port(msg->daddr); } else { port = 0; } t = LM_VT_INTEGER; format_uint32_padded(result, 0, 0, 10, port); break; } case M_PROTOCOL: { t = LM_VT_INTEGER; format_uint32_padded(result, 0, 0, 10, msg->proto); break; } case M_RAWMSG_SIZE: { t = LM_VT_INTEGER; format_uint32_padded(result, 0, 0, 10, msg->recvd_rawmsg_size); break; } case M_SEQNUM: { if (options->seq_num) { format_uint32_padded(result, 0, 0, 10, options->seq_num); } break; } case M_CONTEXT_ID: { if (options->context_id) { result_append(result, options->context_id, strlen(options->context_id), escape); t = options->context_id_type; } break; } case M_RCPTID: { rcptid_append_formatted_id(result, msg->rcptid); break; } case M_RUNID: { run_id_append_formatted_id(result); break; } case M_HOSTID: { host_id_append_formatted_id(result, msg->host_id); break; } case M_UNIQID: { if (msg->rcptid) { host_id_append_formatted_id(result, msg->host_id); g_string_append(result, "@"); format_uint64_padded(result, 16, '0', 16, msg->rcptid); break; } break; } case M_LOGHOST: { const gchar *hname = options->opts->use_fqdn ? get_local_hostname_fqdn() : get_local_hostname_short(); result_append(result, hname, -1, escape); break; } case M_SYSUPTIME: { GTimeVal ct; g_get_current_time(&ct); format_uint64_padded(result, 0, 0, 10, g_time_val_diff(&ct, &app_uptime) / 1000 / 10); break; } default: { log_macro_expand_date_time(id, escape, options, msg, result, &t); break; } } if (type) *type = escape ? LM_VT_STRING : t; return TRUE; } gboolean log_macro_expand_simple(gint id, const LogMessage *msg, GString *result, LogMessageValueType *type) { LogTemplateEvalOptions options = {&template_options_for_macro_expand, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; return log_macro_expand(id, FALSE, &options, msg, result, type); } guint log_macro_lookup(const gchar *macro, gint len) { gchar buf[256]; gint macro_id; g_assert(macro_hash); g_strlcpy(buf, macro, MIN(sizeof(buf), len+1)); gpointer hash_key = g_hash_table_lookup(macro_hash, buf); macro_id = GPOINTER_TO_INT(hash_key); return macro_id; } void log_macros_global_init(void) { gint i; /* init the uptime (SYSUPTIME macro) */ g_get_current_time(&app_uptime); log_template_options_global_defaults(&template_options_for_macro_expand); macro_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); for (i = 0; macros[i].name; i++) { g_hash_table_insert(macro_hash, g_strdup(macros[i].name), GINT_TO_POINTER(macros[i].id)); } return; } void log_macros_global_deinit(void) { g_hash_table_destroy(macro_hash); macro_hash = NULL; } syslog-ng-syslog-ng-4.4.0/lib/template/macros.h000066400000000000000000000061721450431004300213770ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_MACROS_H_INCLUDED #define TEMPLATE_MACROS_H_INCLUDED #include "syslog-ng.h" #include "common-template-typedefs.h" #include "eval.h" /* macro IDs */ enum { M_NONE, M_FACILITY, M_FACILITY_NUM, M_SEVERITY, M_SEVERITY_NUM, M_TAG, M_TAGS, M_BSDTAG, M_PRI, M_HOST, M_SDATA, M_MSGHDR, M_MESSAGE, M_SOURCE_IP, M_DEST_IP, M_DEST_PORT, M_PROTOCOL, M_RAWMSG_SIZE, M_SEQNUM, M_CONTEXT_ID, M_LOGHOST, M_SYSUPTIME, M_RCPTID, M_RUNID, M_HOSTID, M_UNIQID, M__ASTERISK, /* only touch this section if you want to add three macros, one w/o * prefix, and a R_ and S_ prefixed macro that relates one of the * timestamps of the log message. */ M_DATE, M_FULLDATE, M_ISODATE, M_STAMP, M_YEAR, M_YEAR_DAY, M_MONTH, M_MONTH_WEEK, M_MONTH_ABBREV, M_MONTH_NAME, M_DAY, M_HOUR, M_HOUR12, M_MIN, M_SEC, M_USEC, M_MSEC, M_AMPM, M_WEEK_DAY, M_WEEK_DAY_ABBREV, M_WEEK_DAY_NAME, M_WEEK, M_ISOWEEK, M_TZOFFSET, M_TZ, M_UNIXTIME, M_TIME_FIRST = M_DATE, M_TIME_LAST = M_UNIXTIME, M_TIME_MACROS_MAX = M_UNIXTIME - M_DATE + 1, M_RECVD_OFS = M_TIME_MACROS_MAX, M_STAMP_OFS = 2 * M_TIME_MACROS_MAX, M_CSTAMP_OFS = 3 * M_TIME_MACROS_MAX, M_PROCESSED_OFS = 4 * M_TIME_MACROS_MAX, }; /* macros (not NV pairs!) that syslog-ng knows about. This was the * earliest mechanism for inserting message-specific information into * texts. It is now superseded by name-value pairs where the value is * text, but remains to be used for time and other metadata. */ typedef struct _LogMacroDef { const char *name; int id; } LogMacroDef; extern LogMacroDef macros[]; /* low level macro functions */ guint log_macro_lookup(const gchar *macro, gint len); gboolean log_macro_expand(gint id, gboolean escape, LogTemplateEvalOptions *options, const LogMessage *msg, GString *result, LogMessageValueType *type); gboolean log_macro_expand_simple(gint id, const LogMessage *msg, GString *result, LogMessageValueType *type); void log_macros_global_init(void); void log_macros_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/template/repr.c000066400000000000000000000117351450431004300210570ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/repr.h" LogTemplateElem * log_template_elem_new_macro(const gchar *text, guint macro, gchar *default_value, gint msg_ref) { LogTemplateElem *e; e = g_new0(LogTemplateElem, 1); e->type = LTE_MACRO; e->text_len = strlen(text); e->text = g_strdup(text); e->macro = macro; e->default_value = default_value; e->msg_ref = msg_ref; return e; } LogTemplateElem * log_template_elem_new_value(const gchar *text, gchar *value_name, gchar *default_value, gint msg_ref) { LogTemplateElem *e; e = g_new0(LogTemplateElem, 1); e->type = LTE_VALUE; e->text_len = strlen(text); e->text = g_strdup(text); e->value_handle = log_msg_get_value_handle(value_name); e->default_value = default_value; e->msg_ref = msg_ref; return e; } static gboolean _setup_function_call(LogTemplate *template, Plugin *p, LogTemplateElem *e, gint argc, gchar *argv[], GError **error) { gchar *argv_copy[argc + 1]; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); e->func.ops = plugin_construct(p); e->func.state = e->func.ops->size_of_state > 0 ? g_malloc0(e->func.ops->size_of_state) : NULL; /* prepare may modify the argv array: remove and rearrange elements */ memcpy(argv_copy, argv, (argc + 1) * sizeof(argv[0])); if (!e->func.ops->prepare(e->func.ops, e->func.state, template, argc, argv_copy, error)) { if (e->func.state) { e->func.ops->free_state(e->func.state); g_free(e->func.state); } if (e->func.ops->free_fn) e->func.ops->free_fn(e->func.ops); return FALSE; } g_strfreev(argv); return TRUE; } static gboolean _lookup_and_setup_function_call(LogTemplate *template, LogTemplateElem *e, gint argc, gchar *argv[], GError **error) { Plugin *p; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* the plus one denotes the function name, which'll be removed from argc * during parsing */ if (argc > TEMPLATE_INVOKE_MAX_ARGS + 1) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Too many arguments (%d) to template function \"%s\", " "maximum number of arguments is %d", argc - 1, argv[0], TEMPLATE_INVOKE_MAX_ARGS); goto error; } p = cfg_find_plugin(template->cfg, LL_CONTEXT_TEMPLATE_FUNC, argv[0]); if (!p) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Unknown template function \"%s\"", argv[0]); goto error; } if (!_setup_function_call(template, p, e, argc, argv, error)) goto error; return TRUE; error: return FALSE; } /* NOTE: this steals argv if successful */ LogTemplateElem * log_template_elem_new_func(LogTemplate *template, const gchar *text, gint argc, gchar *argv[], gint msg_ref, GError **error) { LogTemplateElem *e; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); e = g_malloc0(sizeof(LogTemplateElem) + (argc - 1) * sizeof(LogTemplate *)); e->type = LTE_FUNC; e->text_len = strlen(text); e->text = g_strdup(text); e->msg_ref = msg_ref; if (!_lookup_and_setup_function_call(template, e, argc, argv, error)) goto error; return e; error: if (e->text) g_free(e->text); g_free(e); return NULL; } void log_template_elem_free(LogTemplateElem *e) { switch (e->type) { case LTE_FUNC: if (e->func.state) { e->func.ops->free_state(e->func.state); g_free(e->func.state); } if (e->func.ops && e->func.ops->free_fn) e->func.ops->free_fn(e->func.ops); break; default: break; } if (e->default_value) g_free(e->default_value); if (e->text) g_free(e->text); g_free(e); } void log_template_elem_free_list(GList *l) { GList *el = l; for (; el; el = el->next) { log_template_elem_free((LogTemplateElem *) el->data); } g_list_free(l); } syslog-ng-syslog-ng-4.4.0/lib/template/repr.h000066400000000000000000000041721450431004300210610ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_REPR_H_INCLUDED #define TEMPLATE_REPR_H_INCLUDED #include "template/function.h" #include "template/macros.h" #include "logmsg/logmsg.h" enum { LTE_MACRO, LTE_VALUE, LTE_FUNC }; typedef struct _LogTemplateElem { gsize text_len; gchar *text; gchar *default_value; guint16 msg_ref; guint8 type; union { guint macro; NVHandle value_handle; struct { LogTemplateFunction *ops; gpointer state; } func; }; } LogTemplateElem; LogTemplateElem *log_template_elem_new_macro(const gchar *text, guint macro, gchar *default_value, gint msg_ref); LogTemplateElem *log_template_elem_new_value(const gchar *text, gchar *value_name, gchar *default_value, gint msg_ref); LogTemplateElem *log_template_elem_new_func(LogTemplate *template, const gchar *text, gint argc, gchar *argv[], gint msg_ref, GError **error); static inline gboolean log_template_elem_is_literal_string(const LogTemplateElem *self) { return self->type == LTE_MACRO && self->macro == M_NONE; } void log_template_elem_free_list(GList *el); #endif syslog-ng-syslog-ng-4.4.0/lib/template/simple-function.c000066400000000000000000000066151450431004300232240ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/simple-function.h" #include "template/templates.h" #include "scratch-buffers.h" void log_template_append_format_recursive(LogTemplate *self, const LogTemplateInvokeArgs *args, GString *result) { log_template_append_format_with_context(self, args->messages, args->num_messages, args->options, result); } /* simple template functions which take templates as arguments */ gboolean tf_simple_func_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFSimpleFuncState *state = (TFSimpleFuncState *) s; gint i; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); state->argv_templates = g_malloc(sizeof(LogTemplate *) * (argc - 1)); /* NOTE: the argv argument contains the function name as argv[0], * but the LogTemplate array doesn't. Thus the index is shifted by * one. */ for (i = 0; i < argc - 1; i++) { state->argv_templates[i] = log_template_new(parent->cfg, NULL); log_template_set_escape(state->argv_templates[i], parent->escape); if (!log_template_compile(state->argv_templates[i], argv[i + 1], error)) { state->argc = i + 1; goto error; } } state->argc = argc - 1; return TRUE; error: return FALSE; } void tf_simple_func_eval(LogTemplateFunction *self, gpointer s, LogTemplateInvokeArgs *args) { TFSimpleFuncState *state = (TFSimpleFuncState *) s; gint i; g_assert(state->argc <= TEMPLATE_INVOKE_MAX_ARGS); for (i = 0; i < state->argc; i++) { args->argv[i] = scratch_buffers_alloc(); log_template_append_format_recursive(state->argv_templates[i], args, args->argv[i]); } } void tf_simple_func_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFSimpleFunc simple_func = (TFSimpleFunc) self->arg; TFSimpleFuncState *state = (TFSimpleFuncState *) s; simple_func(args->messages[args->num_messages-1], state->argc, (GString **) args->argv, result, type); } void tf_simple_func_free_state(gpointer s) { TFSimpleFuncState *state = (TFSimpleFuncState *) s; gint i; for (i = 0; i < state->argc; i++) { if (state->argv_templates[i]) log_template_unref(state->argv_templates[i]); } g_free(state->argv_templates); } syslog-ng-syslog-ng-4.4.0/lib/template/simple-function.h000066400000000000000000000040241450431004300232210ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_SIMPLE_FUNCTION_H_INCLUDED #define TEMPLATE_SIMPLE_FUNCTION_H_INCLUDED #include "template/function.h" /* function pointers for template functions */ typedef struct _TFSimpleFuncState { gint argc; LogTemplate **argv_templates; } TFSimpleFuncState; typedef void (*TFSimpleFunc)(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type); gboolean tf_simple_func_prepare(LogTemplateFunction *self, gpointer state, LogTemplate *parent, gint argc, gchar *argv[], GError **error); void tf_simple_func_eval(LogTemplateFunction *self, gpointer state, LogTemplateInvokeArgs *args); void tf_simple_func_call(LogTemplateFunction *self, gpointer state, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type); void tf_simple_func_free_state(gpointer state); #define TEMPLATE_FUNCTION_SIMPLE(x) TEMPLATE_FUNCTION(TFSimpleFuncState, x, tf_simple_func_prepare, tf_simple_func_eval, tf_simple_func_call, tf_simple_func_free_state, x) #endif syslog-ng-syslog-ng-4.4.0/lib/template/templates.c000066400000000000000000000323671450431004300221110ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/templates.h" #include "template/repr.h" #include "template/compiler.h" #include "template/macros.h" #include "template/escaping.h" #include "template/repr.h" #include "timeutils/format.h" #include "cfg.h" gboolean log_template_is_literal_string(const LogTemplate *self) { return self->literal; } const gchar * log_template_get_literal_value(const LogTemplate *self, gssize *value_len) { g_assert(self->literal); if (!self->compiled_template) return ""; LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data; if (value_len) *value_len = e->text_len; return e->text; } gboolean log_template_is_trivial(LogTemplate *self) { return self->trivial; } NVHandle log_template_get_trivial_value_handle(LogTemplate *self) { g_assert(self->trivial); if (self->literal) return LM_V_NONE; LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data; switch (e->type) { case LTE_MACRO: if (e->macro == M_MESSAGE) return LM_V_MESSAGE; else if (e->macro == M_HOST) return LM_V_HOST; else g_assert_not_reached(); break; case LTE_VALUE: return e->value_handle; default: g_assert_not_reached(); } } const gchar * log_template_get_trivial_value_and_type(LogTemplate *self, LogMessage *msg, gssize *value_len, LogMessageValueType *type) { LogMessageValueType t = LM_VT_STRING; const gchar *result = ""; gssize result_len = 0; g_assert(self->trivial); if (self->literal) { result = log_template_get_literal_value(self, &result_len); } else { NVHandle handle = log_template_get_trivial_value_handle(self); g_assert(handle != LM_V_NONE); result = log_msg_get_value_with_type(msg, handle, &result_len, &t); } if (type) { *type = self->type_hint == LM_VT_NONE ? t : self->type_hint; } if (value_len) *value_len = result_len; return result; } const gchar * log_template_get_trivial_value(LogTemplate *self, LogMessage *msg, gssize *value_len) { return log_template_get_trivial_value_and_type(self, msg, value_len, NULL); } static gboolean _calculate_if_literal(LogTemplate *self) { if (!self->compiled_template) return TRUE; if (self->escape || self->compiled_template->next) return FALSE; return log_template_elem_is_literal_string((LogTemplateElem *) self->compiled_template->data); } static gboolean _calculate_if_trivial(LogTemplate *self) { /* if we need to escape, that's not trivial */ if (self->escape) return FALSE; /* empty templates are trivial */ if (self->compiled_template == NULL) return TRUE; /* more than one element */ if (self->compiled_template->next != NULL) return FALSE; const LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data; /* reference to non-last element of the context, that's not trivial */ if (e->msg_ref > 0) return FALSE; if (log_template_elem_is_literal_string(e)) return TRUE; switch (e->type) { case LTE_FUNC: /* functions are never trivial */ return FALSE; case LTE_MACRO: if (e->text_len > 0) return FALSE; /* we have macros for MESSAGE and HOST for compatibility reasons, but * they should be considered trivial */ if (e->macro == M_MESSAGE || e->macro == M_HOST) return TRUE; return FALSE; case LTE_VALUE: /* values are trivial if they don't contain text */ return e->text_len == 0; default: g_assert_not_reached(); } } static void log_template_reset_compiled(LogTemplate *self) { log_template_elem_free_list(self->compiled_template); self->compiled_template = NULL; self->trivial = FALSE; } gboolean log_template_compile(LogTemplate *self, const gchar *template, GError **error) { LogTemplateCompiler compiler; gboolean result; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); log_template_reset_compiled(self); if (self->template_str) g_free(self->template_str); self->template_str = g_strdup(template); log_template_compiler_init(&compiler, self); result = log_template_compiler_compile(&compiler, &self->compiled_template, error); log_template_compiler_clear(&compiler); self->literal = _calculate_if_literal(self); self->trivial = _calculate_if_trivial(self); return result; } void log_template_forget_template_string(LogTemplate *self) { g_free(self->template_str); self->template_str = NULL; } static void _split_type_and_template(gchar *spec, gchar **value, gchar **type) { char *sp, *ep; *type = NULL; sp = spec; while (g_ascii_isalnum(*sp) || (*sp) == '_') sp++; while (*sp == ' ' || *sp == '\t') sp++; if (*sp != '(' || !((g_ascii_toupper(spec[0]) >= 'A' && g_ascii_toupper(spec[0]) <= 'Z') || spec[0] == '_')) { *value = spec; return; } ep = strrchr(sp, ')'); if (ep == NULL || ep[1] != '\0') { *value = spec; return; } *value = sp + 1; *type = spec; sp[0] = '\0'; ep[0] = '\0'; } gboolean log_template_compile_with_type_hint(LogTemplate *self, const gchar *template_and_typehint, GError **error) { gchar *buf = g_strdup(template_and_typehint); gchar *template_string = NULL; gchar *typehint_string = NULL; gboolean result = FALSE; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); _split_type_and_template(buf, &template_string, &typehint_string); if (!log_template_compile(self, template_string, error)) goto exit; if (!log_template_set_type_hint(self, typehint_string, error)) goto exit; result = TRUE; exit: g_free(buf); return result; } void log_template_compile_literal_string(LogTemplate *self, const gchar *literal) { log_template_reset_compiled(self); g_free(self->template_str); self->template_str = g_strdup(literal); self->compiled_template = g_list_append(self->compiled_template, log_template_elem_new_macro(literal, M_NONE, NULL, 0)); /* double check that the representation here is actually considered trivial. It should be. */ g_assert(_calculate_if_trivial(self)); self->literal = TRUE; self->trivial = TRUE; } void log_template_set_escape(LogTemplate *self, gboolean enable) { self->escape = enable; } gboolean log_template_set_type_hint(LogTemplate *self, const gchar *type_hint, GError **error) { g_return_val_if_fail(error == NULL || *error == NULL, FALSE); gboolean result; if (!type_hint) { self->explicit_type_hint = LM_VT_NONE; result = TRUE; } else if (!type_hint_parse(type_hint, &self->explicit_type_hint, error)) { self->explicit_type_hint = LM_VT_NONE; result = FALSE; } else { result = TRUE; } self->type_hint = self->explicit_type_hint; return result; } /* NOTE: we should completely get rid off the name property of templates, * we basically use it at two locations: * * 1) dbparser uses it to store SyntheticMessages, there the "name" of a * value is stored here * * 2) we reuse the LogTemplate structure (which represents a compiled * template) to store a template {} statement in the configuration, * which apart from a compiled template, also sports a name. This was * the original reason the name attribute was introduced. This basically * blends two unrelated purposes in the same struct. * * Other call sites pass a dummy value, which is probably never used in any * meaningful way. * * Both usages and the dummy call-sites should be removed, and the entire * thing replaced by another struct that contains a LogTemplate. * * I saw this to cause confusion numerous times already. * -- * Bazsi. */ void log_template_set_name(LogTemplate *self, const gchar *name) { if (self->name) g_free(self->name); self->name = g_strdup(name); } /* NOTE: the name parameter should not be used, please pass a NULL until it is eliminated */ LogTemplate * log_template_new(GlobalConfig *cfg, const gchar *name) { LogTemplate *self = g_new0(LogTemplate, 1); log_template_set_name(self, name); g_atomic_counter_set(&self->ref_cnt, 1); self->cfg = cfg; if (cfg_is_config_version_older(cfg, VERSION_VALUE_4_0)) self->type_hint = LM_VT_STRING; else self->type_hint = LM_VT_NONE; self->explicit_type_hint = LM_VT_NONE; return self; } static void log_template_free(LogTemplate *self) { log_template_reset_compiled(self); g_free(self->name); g_free(self->template_str); g_free(self); } LogTemplate * log_template_ref(LogTemplate *s) { if (s) g_atomic_counter_inc(&s->ref_cnt); return s; } void log_template_unref(LogTemplate *s) { if (s && g_atomic_counter_dec_and_test(&s->ref_cnt)) log_template_free(s); } /* NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy */ void log_template_options_init(LogTemplateOptions *options, GlobalConfig *cfg) { gint i; if (options->initialized) return; if (options->ts_format == -1) options->ts_format = cfg->template_options.ts_format; for (i = 0; i < LTZ_MAX; i++) { if (options->time_zone[i] == NULL) options->time_zone[i] = g_strdup(cfg->template_options.time_zone[i]); if (options->time_zone_info[i] == NULL) options->time_zone_info[i] = time_zone_info_new(options->time_zone[i]); } if (options->frac_digits == -1) options->frac_digits = cfg->template_options.frac_digits; if (options->on_error == -1) options->on_error = cfg->template_options.on_error; options->use_fqdn = cfg->host_resolve_options.use_fqdn; options->initialized = TRUE; } void log_template_options_clone(LogTemplateOptions *source, LogTemplateOptions *dest) { dest->ts_format = source->ts_format; for (gint i = 0; i < LTZ_MAX; i++) { if (source->time_zone[i]) dest->time_zone[i] = g_strdup(source->time_zone[i]); } dest->frac_digits = source->frac_digits; dest->on_error = source->on_error; dest->use_fqdn = source->use_fqdn; /* NOTE: this still needs to be initialized by the owner as clone results * in an uninitialized state. */ dest->initialized = FALSE; } void log_template_options_destroy(LogTemplateOptions *options) { gint i; for (i = 0; i < LTZ_MAX; i++) { if (options->time_zone[i]) g_free(options->time_zone[i]); if (options->time_zone_info[i]) time_zone_info_free(options->time_zone_info[i]); } options->initialized = FALSE; } void log_template_options_defaults(LogTemplateOptions *options) { memset(options, 0, sizeof(LogTemplateOptions)); options->frac_digits = -1; options->ts_format = -1; options->on_error = -1; options->use_fqdn = FALSE; } void log_template_options_global_defaults(LogTemplateOptions *options) { log_template_options_defaults(options); options->ts_format = TS_FMT_BSD; options->frac_digits = 0; options->on_error = ON_ERROR_DROP_MESSAGE; } GQuark log_template_error_quark(void) { return g_quark_from_static_string("log-template-error-quark"); } void log_template_global_init(void) { log_macros_global_init(); } void log_template_global_deinit(void) { log_macros_global_deinit(); } gboolean log_template_on_error_parse(const gchar *strictness, gint *out) { const gchar *p = strictness; gboolean silently = FALSE; if (!strictness) { *out = ON_ERROR_DROP_MESSAGE; return TRUE; } if (strncmp(strictness, "silently-", strlen("silently-")) == 0) { silently = TRUE; p = strictness + strlen("silently-"); } if (strcmp(p, "drop-message") == 0) *out = ON_ERROR_DROP_MESSAGE; else if (strcmp(p, "drop-property") == 0) *out = ON_ERROR_DROP_PROPERTY; else if (strcmp(p, "fallback-to-string") == 0) *out = ON_ERROR_FALLBACK_TO_STRING; else return FALSE; if (silently) *out |= ON_ERROR_SILENT; return TRUE; } void log_template_options_set_on_error(LogTemplateOptions *options, gint on_error) { options->on_error = on_error; } EVTTAG * evt_tag_template(const gchar *name, LogTemplate *template_obj, LogMessage *msg, LogTemplateEvalOptions *options) { /* trying to avoid scratch-buffers here, this is only meant to be used in trace messages */ GString *buf = g_string_sized_new(256); log_template_format(template_obj, msg, options, buf); EVTTAG *result = evt_tag_str(name, buf->str); g_string_free(buf, TRUE); return result; } syslog-ng-syslog-ng-4.4.0/lib/template/templates.h000066400000000000000000000107411450431004300221060ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATES_H_INCLUDED #define TEMPLATES_H_INCLUDED #include "syslog-ng.h" #include "eval.h" #include "timeutils/zoneinfo.h" #include "logmsg/type-hinting.h" #include "common-template-typedefs.h" #include "atomic.h" #define LOG_TEMPLATE_ERROR log_template_error_quark() GQuark log_template_error_quark(void); enum LogTemplateError { LOG_TEMPLATE_ERROR_FAILED, LOG_TEMPLATE_ERROR_COMPILE, }; typedef enum { ON_ERROR_DROP_MESSAGE = 0x01, ON_ERROR_DROP_PROPERTY = 0x02, ON_ERROR_FALLBACK_TO_STRING = 0x04, /* Valid for type hinting only! */ ON_ERROR_SILENT = 0x08 } LogTemplateOnError; /* structure that represents an expandable syslog-ng template */ struct _LogTemplate { GAtomicCounter ref_cnt; gchar *name; gchar *template_str; GList *compiled_template; GlobalConfig *cfg; guint escape:1, def_inline:1, trivial:1, literal:1; /* This value stores the type-hint the user _explicitly_ specified. If * this is an automatic cast to string (in compat mode), this would be * LM_VT_NONE while "type_hint" would be LM_VT_STRING */ LogMessageValueType explicit_type_hint; /* This is the type-cast we do perform as we evaluate this template. It * might differ from explicit_type_hint in case we are in compatibility * mode where the template would be cast to a string when the type-hint is * unspecified. */ LogMessageValueType type_hint; }; /* appends the formatted output into result */ void log_template_set_escape(LogTemplate *self, gboolean enable); gboolean log_template_set_type_hint(LogTemplate *self, const gchar *hint, GError **error); gboolean log_template_compile(LogTemplate *self, const gchar *template_str, GError **error); gboolean log_template_compile_with_type_hint(LogTemplate *self, const gchar *template_and_typehint, GError **error); void log_template_forget_template_string(LogTemplate *self); void log_template_compile_literal_string(LogTemplate *self, const gchar *literal); gboolean log_template_is_literal_string(const LogTemplate *self); const gchar *log_template_get_literal_value(const LogTemplate *self, gssize *value_len); gboolean log_template_is_trivial(LogTemplate *self); NVHandle log_template_get_trivial_value_handle(LogTemplate *self); const gchar *log_template_get_trivial_value(LogTemplate *self, LogMessage *msg, gssize *value_len); const gchar *log_template_get_trivial_value_and_type(LogTemplate *self, LogMessage *msg, gssize *value_len, LogMessageValueType *type); void log_template_set_name(LogTemplate *self, const gchar *name); LogTemplate *log_template_new(GlobalConfig *cfg, const gchar *name); LogTemplate *log_template_ref(LogTemplate *s); void log_template_unref(LogTemplate *s); void log_template_options_clone(LogTemplateOptions *source, LogTemplateOptions *dest); void log_template_options_init(LogTemplateOptions *options, GlobalConfig *cfg); void log_template_options_destroy(LogTemplateOptions *options); void log_template_options_defaults(LogTemplateOptions *options); void log_template_options_global_defaults(LogTemplateOptions *options); void log_template_global_init(void); void log_template_global_deinit(void); gboolean log_template_on_error_parse(const gchar *on_error, gint *out); void log_template_options_set_on_error(LogTemplateOptions *options, gint on_error); EVTTAG *evt_tag_template(const gchar *name, LogTemplate *template_obj, LogMessage *msg, LogTemplateEvalOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/template/tests/000077500000000000000000000000001450431004300210765ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/template/tests/CMakeLists.txt000066400000000000000000000005421450431004300236370ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_template_compile) add_unit_test(LIBTEST CRITERION TARGET test_template_on_error) add_unit_test(LIBTEST CRITERION TARGET test_template DEPENDS syslogformat basicfuncs) add_unit_test(LIBTEST CRITERION TARGET test_template_speed DEPENDS syslogformat basicfuncs) add_unit_test(LIBTEST CRITERION TARGET test_macro) syslog-ng-syslog-ng-4.4.0/lib/template/tests/Makefile.am000066400000000000000000000017661450431004300231440ustar00rootroot00000000000000lib_template_tests_TESTS = \ lib/template/tests/test_template_compile \ lib/template/tests/test_template_on_error \ lib/template/tests/test_template \ lib/template/tests/test_template_speed \ lib/template/tests/test_macro check_PROGRAMS += ${lib_template_tests_TESTS} lib_template_tests_test_template_compile_CFLAGS = \ $(TEST_CFLAGS) lib_template_tests_test_template_compile_LDADD = \ $(TEST_LDADD) lib_template_tests_test_template_on_error_CFLAGS = \ $(TEST_CFLAGS) lib_template_tests_test_template_on_error_LDADD = \ $(TEST_LDADD) lib_template_tests_test_template_CFLAGS = $(TEST_CFLAGS) lib_template_tests_test_template_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) \ $(PREOPEN_BASICFUNCS) lib_template_tests_test_template_speed_CFLAGS = $(TEST_CFLAGS) lib_template_tests_test_template_speed_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) $(PREOPEN_BASICFUNCS) lib_template_tests_test_macro_CFLAGS = $(TEST_CFLAGS) lib_template_tests_test_macro_LDADD = \ $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/lib/template/tests/test_macro.c000066400000000000000000000100711450431004300234010ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/fake-time.h" #include "template/macros.h" #include "logmsg/logmsg.h" #include "syslog-names.h" #include "apphook.h" static void assert_macro_value(gint id, LogMessage *msg, const gchar *expected_value, LogMessageValueType expected_type) { GString *resolved = g_string_new(""); LogMessageValueType type; gboolean result = log_macro_expand_simple(id, msg, resolved, &type); cr_assert(result); cr_assert_str_eq(resolved->str, expected_value); cr_assert_eq(type, expected_type); g_string_free(resolved, TRUE); } Test(macro, test_facility) { const gchar *facility_printable = "lpr"; const gint facility_lpr = syslog_name_lookup_facility_by_name(facility_printable); LogMessage *msg = log_msg_new_empty(); msg->pri = facility_lpr; assert_macro_value(M_FACILITY, msg, "lpr", LM_VT_STRING); log_msg_unref(msg); } Test(macro, test_date_week) { LogMessage *msg = log_msg_new_empty(); /* Wed Jan 1 11:20:50 GMT 2015 */ fake_time(1420111250); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_WEEK, msg, "00", LM_VT_STRING); /* Thu Dec 31 11:20:50 GMT 2015 */ fake_time(1451560850); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_WEEK, msg, "52", LM_VT_STRING); log_msg_unref(msg); } Test(macro, test_date_iso_week_testcases) { LogMessage *msg = log_msg_new_empty(); /* First week: Thu Jan 1 11:20:50 GMT 2015 */ fake_time(1420111250); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_ISOWEEK, msg, "01", LM_VT_STRING); /* Last week, still in 2015: Thu Dec 31 11:20:50 GMT 2015 */ fake_time(1451560850); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_ISOWEEK, msg, "53", LM_VT_STRING); /* Already 2016, but still the same week as the previous case: Fri Jan 1 11:20:50 GMT 2016 */ fake_time(1451647250); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_ISOWEEK, msg, "53", LM_VT_STRING); /* Mon Jan 5 11:20:50 GMT 2015 */ fake_time(1420456850); unix_time_set_now(&msg->timestamps[LM_TS_STAMP]); assert_macro_value(M_ISOWEEK, msg, "02", LM_VT_STRING); log_msg_unref(msg); } Test(macro, test_context_id_type_is_returned) { GString *resolved = g_string_new(""); LogMessage *msg = log_msg_new_empty(); LogMessageValueType type; LogTemplateEvalOptions options = {NULL, LTZ_SEND, 5555, "5678", LM_VT_INTEGER}; gboolean result = log_macro_expand(M_CONTEXT_ID, FALSE, &options, msg, resolved, &type); cr_assert(result); cr_assert_str_eq(resolved->str, "5678"); cr_assert_eq(type, LM_VT_INTEGER); g_string_free(resolved, TRUE); log_msg_unref(msg); } Test(macro, test__asterisk_returns_the_matches_as_a_list) { LogMessage *msg = log_msg_new_empty(); log_msg_set_match(msg, 1, "foo", -1); log_msg_set_match(msg, 2, "bar", -1); assert_macro_value(M__ASTERISK, msg, "foo,bar", LM_VT_LIST); log_msg_unref(msg); } void setup(void) { app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); } void teardown(void) { app_shutdown(); } TestSuite(macro, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/template/tests/test_template.c000066400000000000000000001144721450431004300241250ustar00rootroot00000000000000/* * Copyright (c) 2007-2018 Balabit * Copyright (c) 2007-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "logmsg/logmsg.h" #include "template/templates.h" #include "template/user-function.h" #include "apphook.h" #include "cfg.h" #include "plugin.h" #include "scratch-buffers.h" #include "hostname.h" #include #include #include #include GCond thread_ping; GMutex thread_lock; gboolean thread_start; static gpointer format_template_thread(gpointer s) { gpointer *args = (gpointer *) s; LogMessage *msg = args[0]; LogTemplate *templ = args[1]; const gchar *expected = args[2]; GString *result; gint i; scratch_buffers_allocator_init(); g_mutex_lock(&thread_lock); while (!thread_start) g_cond_wait(&thread_ping, &thread_lock); g_mutex_unlock(&thread_lock); result = g_string_sized_new(0); LogTemplateEvalOptions options = {NULL, LTZ_SEND, 5555, NULL, LM_VT_STRING}; for (i = 0; i < 10000; i++) { log_template_format(templ, msg, &options, result); cr_assert_str_eq(result->str, expected, "multi-threaded formatting yielded invalid result (iteration: %d)", i); scratch_buffers_explicit_gc(); } g_string_free(result, TRUE); scratch_buffers_allocator_deinit(); return NULL; } static void assert_template_format_multi_thread(const gchar *template, const gchar *expected) { LogTemplate *templ; LogMessage *msg; gpointer args[3]; GThread *threads[16]; gint i; msg = create_sample_message(); templ = compile_template(template); args[0] = msg; args[1] = templ; args[2] = (gpointer) expected; thread_start = FALSE; g_cond_init(&thread_ping); g_mutex_init(&thread_lock); args[1] = templ; for (i = 0; i < 16; i++) { threads[i] = g_thread_new(NULL, format_template_thread, args); } thread_start = TRUE; g_mutex_lock(&thread_lock); g_cond_broadcast(&thread_ping); g_mutex_unlock(&thread_lock); for (i = 0; i < 16; i++) { g_thread_join(threads[i]); } g_cond_clear(&thread_ping); g_mutex_clear(&thread_lock); log_template_unref(templ); log_msg_unref(msg); } void setup(void) { app_startup(); init_template_tests(); cfg_load_module(configuration, "basicfuncs"); configuration->template_options.frac_digits = 3; configuration->template_options.time_zone_info[LTZ_LOCAL] = time_zone_info_new(NULL); setenv("TZ", "MET-1METDST", TRUE); tzset(); } void teardown(void) { scratch_buffers_explicit_gc(); deinit_template_tests(); app_shutdown(); } TestSuite(template, .init = setup, .fini = teardown); Test(template, test_macros_v3x) { /* pri 3, fac 19 == local3 */ /* v3.x behavior */ cfg_set_version_without_validation(configuration, VERSION_VALUE_3_38); assert_template_format_value_and_type("$FACILITY", "local3", LM_VT_STRING); assert_template_format_value_and_type("$FACILITY_NUM", "19", LM_VT_STRING); assert_template_format_value_and_type("$SEVERITY", "err", LM_VT_STRING); assert_template_format_value_and_type("$SEVERITY_NUM", "3", LM_VT_STRING); assert_template_format_value_and_type("$PRIORITY", "err", LM_VT_STRING); assert_template_format_value_and_type("$LEVEL", "err", LM_VT_STRING); assert_template_format_value_and_type("$LEVEL_NUM", "3", LM_VT_STRING); assert_template_format_value_and_type("$TAG", "9b", LM_VT_STRING); assert_template_format_value_and_type("$TAGS", "alma,korte,citrom,\"tag,containing,comma\"", LM_VT_STRING); assert_template_format_value_and_type("$PRI", "155", LM_VT_STRING); assert_template_format_value_and_type("$DATE", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$FULLDATE", "2006 Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$ISODATE", "2006-02-11T10:34:56.000+01:00", LM_VT_STRING); assert_template_format_value_and_type("$STAMP", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$HOUR", "10", LM_VT_STRING); assert_template_format_value_and_type("$MIN", "34", LM_VT_STRING); assert_template_format_value_and_type("$SEC", "56", LM_VT_STRING); assert_template_format_value_and_type("$WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$UNIXTIME", "1139650496.000", LM_VT_STRING); assert_template_format_value_and_type("$TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_DATE", "Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_FULLDATE", "2006 Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_ISODATE", "2006-02-11T19:58:35.639+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_STAMP", "Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$R_YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$R_DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$R_HOUR", "19", LM_VT_STRING); assert_template_format_value_and_type("$R_MIN", "58", LM_VT_STRING); assert_template_format_value_and_type("$R_SEC", "35", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$R_UNIXTIME", "1139684315.639", LM_VT_STRING); assert_template_format_value_and_type("$R_TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_DATE", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_FULLDATE", "2006 Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_ISODATE", "2006-02-11T10:34:56.000+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_STAMP", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$S_YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$S_DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$S_HOUR", "10", LM_VT_STRING); assert_template_format_value_and_type("$S_MIN", "34", LM_VT_STRING); assert_template_format_value_and_type("$S_SEC", "56", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$S_UNIXTIME", "1139650496.000", LM_VT_STRING); assert_template_format_value_and_type("$S_TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$HOST_FROM", "kismacska", LM_VT_STRING); assert_template_format_value_and_type("$FULLHOST_FROM", "kismacska", LM_VT_STRING); assert_template_format_value_and_type("$HOST", "bzorp", LM_VT_STRING); assert_template_format_value_and_type("$FULLHOST", "bzorp", LM_VT_STRING); assert_template_format_value_and_type("$PROGRAM", "syslog-ng", LM_VT_STRING); assert_template_format_value_and_type("$PID", "23323", LM_VT_STRING); assert_template_format_value_and_type("$MSGHDR", "syslog-ng[23323]:", LM_VT_STRING); assert_template_format_value_and_type("$MSG", "árvíztűrőtükörfúrógép", LM_VT_STRING); assert_template_format_value_and_type("$MESSAGE", "árvíztűrőtükörfúrógép", LM_VT_STRING); assert_template_format_value_and_type("$SOURCEIP", "10.11.12.13", LM_VT_STRING); assert_template_format_value_and_type("$RCPTID", "555", LM_VT_STRING); assert_template_format_value_and_type("$DESTIP", "127.0.0.5", LM_VT_STRING); assert_template_format_value_and_type("$DESTPORT", "6514", LM_VT_STRING); assert_template_format_value_and_type("$PROTO", "33", LM_VT_STRING); assert_template_format_value_and_type("$SEQNUM", "999", LM_VT_STRING); assert_template_format_value_and_type("$CONTEXT_ID", "test-context-id", LM_VT_STRING); assert_template_format_value_and_type("$UNIQID", "cafebabe@000000000000022b", LM_VT_STRING); } Test(template, test_macros_v40) { /* v4.x */ cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); assert_template_format_value_and_type("$FACILITY", "local3", LM_VT_STRING); assert_template_format_value_and_type("$FACILITY_NUM", "19", LM_VT_INTEGER); assert_template_format_value_and_type("$SEVERITY", "err", LM_VT_STRING); assert_template_format_value_and_type("$SEVERITY_NUM", "3", LM_VT_INTEGER); assert_template_format_value_and_type("$PRIORITY", "err", LM_VT_STRING); assert_template_format_value_and_type("$LEVEL", "err", LM_VT_STRING); assert_template_format_value_and_type("$LEVEL_NUM", "3", LM_VT_INTEGER); assert_template_format_value_and_type("$TAG", "9b", LM_VT_STRING); assert_template_format_value_and_type("$TAGS", "alma,korte,citrom,\"tag,containing,comma\"", LM_VT_LIST); assert_template_format_value_and_type("$PRI", "155", LM_VT_STRING); assert_template_format_value_and_type("$DATE", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$FULLDATE", "2006 Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$ISODATE", "2006-02-11T10:34:56.000+01:00", LM_VT_STRING); assert_template_format_value_and_type("$STAMP", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$HOUR", "10", LM_VT_STRING); assert_template_format_value_and_type("$MIN", "34", LM_VT_STRING); assert_template_format_value_and_type("$SEC", "56", LM_VT_STRING); assert_template_format_value_and_type("$WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$UNIXTIME", "1139650496.000", LM_VT_DATETIME); assert_template_format_value_and_type("$TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_DATE", "Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_FULLDATE", "2006 Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_ISODATE", "2006-02-11T19:58:35.639+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_STAMP", "Feb 11 19:58:35.639", LM_VT_STRING); assert_template_format_value_and_type("$R_YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$R_YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$R_MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$R_DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$R_HOUR", "19", LM_VT_STRING); assert_template_format_value_and_type("$R_MIN", "58", LM_VT_STRING); assert_template_format_value_and_type("$R_SEC", "35", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$R_WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$R_UNIXTIME", "1139684315.639", LM_VT_DATETIME); assert_template_format_value_and_type("$R_TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$R_TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_DATE", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_FULLDATE", "2006 Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_ISODATE", "2006-02-11T10:34:56.000+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_STAMP", "Feb 11 10:34:56.000", LM_VT_STRING); assert_template_format_value_and_type("$S_YEAR", "2006", LM_VT_STRING); assert_template_format_value_and_type("$S_YEAR_DAY", "042", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH", "02", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_WEEK", "1", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_ABBREV", "Feb", LM_VT_STRING); assert_template_format_value_and_type("$S_MONTH_NAME", "February", LM_VT_STRING); assert_template_format_value_and_type("$S_DAY", "11", LM_VT_STRING); assert_template_format_value_and_type("$S_HOUR", "10", LM_VT_STRING); assert_template_format_value_and_type("$S_MIN", "34", LM_VT_STRING); assert_template_format_value_and_type("$S_SEC", "56", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEKDAY", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY", "7", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY_NAME", "Saturday", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK_DAY_ABBREV", "Sat", LM_VT_STRING); assert_template_format_value_and_type("$S_WEEK", "06", LM_VT_STRING); assert_template_format_value_and_type("$S_UNIXTIME", "1139650496.000", LM_VT_DATETIME); assert_template_format_value_and_type("$S_TZOFFSET", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$S_TZ", "+01:00", LM_VT_STRING); assert_template_format_value_and_type("$HOST_FROM", "kismacska", LM_VT_STRING); assert_template_format_value_and_type("$FULLHOST_FROM", "kismacska", LM_VT_STRING); assert_template_format_value_and_type("$HOST", "bzorp", LM_VT_STRING); assert_template_format_value_and_type("$FULLHOST", "bzorp", LM_VT_STRING); assert_template_format_value_and_type("$PROGRAM", "syslog-ng", LM_VT_STRING); assert_template_format_value_and_type("$PID", "23323", LM_VT_STRING); assert_template_format_value_and_type("$MSGHDR", "syslog-ng[23323]:", LM_VT_STRING); assert_template_format_value_and_type("$MSG", "árvíztűrőtükörfúrógép", LM_VT_STRING); assert_template_format_value_and_type("$MESSAGE", "árvíztűrőtükörfúrógép", LM_VT_STRING); assert_template_format_value_and_type("$SOURCEIP", "10.11.12.13", LM_VT_STRING); assert_template_format_value_and_type("$RCPTID", "555", LM_VT_STRING); assert_template_format_value_and_type("$DESTIP", "127.0.0.5", LM_VT_STRING); assert_template_format_value_and_type("$DESTPORT", "6514", LM_VT_INTEGER); assert_template_format_value_and_type("$PROTO", "33", LM_VT_INTEGER); assert_template_format_value_and_type("$SEQNUM", "999", LM_VT_STRING); assert_template_format_value_and_type("$CONTEXT_ID", "test-context-id", LM_VT_STRING); assert_template_format_value_and_type("$UNIQID", "cafebabe@000000000000022b", LM_VT_STRING); } Test(template, test_loghost_macro) { const gchar *fqdn = get_local_hostname_fqdn(); const gchar *short_name = get_local_hostname_short(); /* by default $LOGHOST is using fqdn as the template options we are using uses use_fqdn by default */ cr_assert_not(configuration->template_options.use_fqdn); configuration->template_options.use_fqdn = TRUE; assert_template_format("$LOGHOST", fqdn); configuration->template_options.use_fqdn = FALSE; assert_template_format("$LOGHOST", short_name); } Test(template, test_nvpairs) { assert_template_format("$PROGRAM/var/log/messages/$HOST/$HOST_FROM/$MONTH$DAY${QQQQQ}valami", "syslog-ng/var/log/messages/bzorp/kismacska/0211valami"); assert_template_format("${APP.VALUE}", "value"); assert_template_format("${APP.VALUE:-ures}", "value"); assert_template_format("${APP.VALUE99:-ures}", "ures"); assert_template_format("${1}", "first-match"); assert_template_format("$1", "first-match"); assert_template_format("$$$1$$", "$first-match$"); } Test(template, test_template_functions) { /* template functions */ assert_template_format("$(echo $HOST $PID)", "bzorp 23323"); assert_template_format("$(echo\n$HOST\n$PID)", "bzorp 23323"); assert_template_format("$(echo \"$(echo $HOST)\" $PID)", "bzorp 23323"); assert_template_format("$(echo \"$(echo '$(echo $HOST)')\" $PID)", "bzorp 23323"); assert_template_format("$(echo \"$(echo '$(echo $HOST)')\" $PID)", "bzorp 23323"); assert_template_format("$(echo '\"$(echo $(echo $HOST))\"' $PID)", "\"bzorp\" 23323"); } Test(template, test_message_refs) { /* message refs */ assert_template_format_with_context("$(echo ${HOST}@0 ${PID}@1)", "bzorp 23323"); assert_template_format_with_context("$(echo $HOST $PID)@0", "bzorp 23323"); } Test(template, test_syntax_errors) { /* template syntax errors */ assert_template_failure("${unbalanced_brace", "'}' is missing"); assert_template_format("$unbalanced_brace}", "}"); assert_template_format("$}", "$}"); assert_template_failure("$(unbalanced_paren", "missing function name or imbalanced '('"); assert_template_format("$unbalanced_paren)", ")"); } Test(template, test_multi_thread) { /* name-value pair */ assert_template_format_multi_thread("alma $HOST bela", "alma bzorp bela"); assert_template_format_multi_thread("kukac $DATE mukac", "kukac Feb 11 10:34:56.000 mukac"); assert_template_format_multi_thread("dani $(echo $HOST $DATE $(echo huha)) balint", "dani bzorp Feb 11 10:34:56.000 huha balint"); } Test(template, test_escaping) { assert_template_format_with_escaping("${APP.QVALUE}", FALSE, "\"value\""); assert_template_format_with_escaping("${APP.QVALUE}", TRUE, "\\\"value\\\""); assert_template_format_with_escaping("$(if (\"${APP.VALUE}\" eq \"value\") \"${APP.QVALUE}\" \"${APP.QVALUE}\")", FALSE, "\"value\""); assert_template_format_with_escaping("$(if (\"${APP.VALUE}\" eq \"value\") \"${APP.QVALUE}\" \"${APP.QVALUE}\")", TRUE, "\\\"value\\\""); } Test(template, test_user_template_function) { LogTemplate *template; template = compile_template("this is a user-defined template function $DATE"); user_template_function_register(configuration, "dummy", template); assert_template_format("$(dummy)", "this is a user-defined template function Feb 11 10:34:56.000"); assert_template_failure("$(dummy arg)", "User defined template function $(dummy) cannot have arguments"); log_template_unref(template); } Test(template, test_template_function_args) { assert_template_format("$(echo foo bar)", "foo bar"); assert_template_format("$(echo 'foobar' \"barfoo\")", "foobar barfoo"); assert_template_format("$(echo foo '' bar)", "foo bar"); assert_template_format("$(echo foo '')", "foo "); assert_template_failure("$(echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 " "17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 " "33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 " "49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65)", "Too many arguments (65)"); assert_template_format("$(echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 " "17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 " "33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 " "49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64)", "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 " "17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 " "33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 " "49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64"); } static void assert_template_trivial_value(const gchar *template_code, LogMessage *msg, const gchar *expected_value, LogMessageValueType expected_type) { LogTemplate *template = compile_template(template_code); LogMessageValueType type; cr_assert(log_template_is_trivial(template)); const gchar *trivial_value = log_template_get_trivial_value_and_type(template, msg, NULL, &type); cr_assert_str_eq(trivial_value, expected_value); cr_assert_eq(type, expected_type); GString *formatted_value = g_string_sized_new(64); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq(trivial_value, formatted_value->str, "Formatted and trivial value does not match: '%s' - '%s'", trivial_value, formatted_value->str); cr_assert_eq(type, expected_type, "Formatted and trivial type does not match: '%d' - '%d'", type, expected_type); g_string_free(formatted_value, TRUE); log_template_unref(template); } Test(template, test_single_values_and_literal_strings_are_considered_trivial) { LogMessage *msg = create_sample_message(); cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); assert_template_trivial_value("", msg, "", LM_VT_STRING); assert_template_trivial_value(" ", msg, " ", LM_VT_STRING); assert_template_trivial_value("literal", msg, "literal", LM_VT_STRING); assert_template_trivial_value("$1", msg, "first-match", LM_VT_STRING); assert_template_trivial_value("$MSG", msg, "árvíztűrőtükörfúrógép", LM_VT_STRING); assert_template_trivial_value("$HOST", msg, "bzorp", LM_VT_STRING); assert_template_trivial_value("${APP.VALUE}", msg, "value", LM_VT_STRING); assert_template_trivial_value("${number1}", msg, "123", LM_VT_INTEGER); cfg_set_version_without_validation(configuration, VERSION_VALUE_3_38); assert_template_trivial_value("${number1}", msg, "123", LM_VT_STRING); log_msg_unref(msg); } Test(template, test_get_trivial_handle_returns_the_handle_associated_with_the_trivial_template) { LogTemplate *template; template = compile_template("$MESSAGE"); cr_assert(log_template_is_trivial(template) == TRUE); cr_assert(log_template_get_trivial_value_handle(template) == LM_V_MESSAGE); log_template_unref(template); template = compile_template("$1"); cr_assert(log_template_is_trivial(template) == TRUE); cr_assert(log_template_get_trivial_value_handle(template) == log_msg_get_match_handle(1)); log_template_unref(template); template = compile_template("literal"); cr_assert(log_template_is_trivial(template) == TRUE); cr_assert(log_template_get_trivial_value_handle(template) == LM_V_NONE); log_template_unref(template); } Test(template, test_invalid_templates_are_trivial) { LogMessage *msg = create_sample_message(); LogTemplate *template = log_template_new(configuration, NULL); cr_assert_not(log_template_compile(template, "$1 $2 ${MSG invalid", NULL)); cr_assert(log_template_is_trivial(template), "Invalid templates are trivial"); cr_assert(g_str_has_prefix(log_template_get_trivial_value(template, NULL, NULL), "error in template")); log_template_unref(template); log_msg_unref(msg); } Test(template, test_non_trivial_templates) { LogTemplate *template; template = compile_escaped_template("$1"); cr_assert_not(log_template_is_trivial(template), "Escaped template is not trivial"); log_template_unref(template); template = compile_template("$1 $2"); cr_assert_not(log_template_is_trivial(template), "Multi-element template is not trivial"); log_template_unref(template); template = compile_template("$1 literal"); cr_assert_not(log_template_is_trivial(template), "Multi-element template is not trivial"); log_template_unref(template); template = compile_template("pre${1}"); cr_assert_not(log_template_is_trivial(template), "Single-value template with preliminary text is not trivial"); log_template_unref(template); template = compile_template("${MSG}@3"); cr_assert_not(log_template_is_trivial(template), "Template referencing non-last context element is not trivial"); log_template_unref(template); template = compile_template("$(echo test)"); cr_assert_not(log_template_is_trivial(template), "Template functions are not trivial"); log_template_unref(template); template = compile_template("$DATE"); cr_assert_not(log_template_is_trivial(template), "Hard macros are not trivial"); log_template_unref(template); } static void assert_template_literal_value(const gchar *template_code, const gchar *expected_value) { LogTemplate *template = compile_template(template_code); cr_assert(log_template_is_literal_string(template)); const gchar *literal_val = log_template_get_literal_value(template, NULL); cr_assert_str_eq(literal_val, expected_value); GString *formatted_value = g_string_sized_new(64); LogMessage *msg = create_sample_message(); log_template_format(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value); cr_assert_str_eq(literal_val, formatted_value->str, "Formatted and literal value does not match: '%s' - '%s'", literal_val, formatted_value->str); log_msg_unref(msg); g_string_free(formatted_value, TRUE); log_template_unref(template); } Test(template, test_literal_string_templates) { assert_template_literal_value("", ""); assert_template_literal_value(" ", " "); assert_template_literal_value("literal string", "literal string"); assert_template_literal_value("$$not a macro", "$not a macro"); LogTemplate *template = compile_template("a b c d $MSG"); cr_assert_not(log_template_is_literal_string(template)); log_template_unref(template); } Test(template, test_compile_literal_string) { LogTemplate *template = log_template_new(configuration, NULL); log_template_compile_literal_string(template, "test literal"); cr_assert(log_template_is_literal_string(template)); cr_assert(log_template_is_trivial(template)); cr_assert_str_eq(log_template_get_literal_value(template, NULL), "test literal"); log_template_unref(template); } Test(template, test_result_of_concatenation_in_templates_are_typed_as_strings) { assert_template_format_value_and_type("$HOST$PROGRAM", "bzorpsyslog-ng", LM_VT_STRING); assert_template_format_value_and_type("${number1}123", "123123", LM_VT_STRING); assert_template_format_value_and_type("123${number1}", "123123", LM_VT_STRING); assert_template_format_value_and_type("${number1}${number2}", "123456", LM_VT_STRING); } Test(template, test_literals_in_templates_are_typed_as_strings) { assert_template_format_value_and_type("", "", LM_VT_STRING); assert_template_format_value_and_type("123", "123", LM_VT_STRING); assert_template_format_value_and_type("foobar", "foobar", LM_VT_STRING); } Test(template, test_single_element_typed_value_refs_are_typed_as_the_value) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); assert_template_format_value_and_type("${number1}", "123", LM_VT_INTEGER); } Test(template, test_single_element_typed_value_refs_with_escaping_are_typed_as_strings) { assert_template_format_value_and_type_with_escaping("${number1}", TRUE, "123", LM_VT_STRING); } Test(template, test_default_values_are_typed_as_strings) { assert_template_format_value_and_type("${unset:-foo}", "foo", LM_VT_STRING); } Test(template, test_type_hint_overrides_the_calculated_type) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); LogTemplate *template = compile_template("${number1}"); GString *formatted_value = g_string_sized_new(64); LogMessage *msg = create_sample_message(); LogMessageValueType type; /* no type-hint */ log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("123", formatted_value->str); cr_assert_eq(type, LM_VT_INTEGER); cr_assert(log_template_set_type_hint(template, "float", NULL)); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("123", formatted_value->str); cr_assert_eq(type, LM_VT_DOUBLE); cr_assert(log_template_set_type_hint(template, "string", NULL)); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("123", formatted_value->str); cr_assert_eq(type, LM_VT_STRING); log_template_unref(template); template = compile_template("${HOST}"); cr_assert(log_template_set_type_hint(template, "int64", NULL)); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("bzorp", formatted_value->str); cr_assert_eq(type, LM_VT_INTEGER); /* empty string with a type uses the type hint */ log_template_unref(template); template = compile_template(""); cr_assert(log_template_set_type_hint(template, "null", NULL)); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_NULL); log_template_unref(template); /* msgref out of range */ template = compile_template("${HOST}@2"); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_STRING); log_msg_unref(msg); log_template_unref(template); } Test(template, test_log_template_compile_with_type_hint_sets_the_type_hint_member_too) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); LogTemplate *template = log_template_new(configuration, NULL); GError *error = NULL; gboolean result; cr_assert_eq(template->type_hint, LM_VT_NONE); result = log_template_compile_with_type_hint(template, "int64(1234)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_INTEGER); result = log_template_compile_with_type_hint(template, "string(1234)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_STRING); result = log_template_compile_with_type_hint(template, "list(foo,bar,baz)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_LIST); result = log_template_compile_with_type_hint(template, "generic-string", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_NONE); log_template_unref(template); } Test(template, test_log_template_compile_with_invalid_type_hint_resets_the_type_hint_to_none) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); LogTemplate *template = log_template_new(configuration, NULL); GError *error = NULL; gboolean result; cr_assert_eq(template->type_hint, LM_VT_NONE); result = log_template_compile_with_type_hint(template, "int64(1234)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_INTEGER); result = log_template_compile_with_type_hint(template, "unknown(generic-string)", &error); cr_assert_not(result); cr_assert_neq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_NONE); log_template_unref(template); } Test(template, test_log_template_with_escaping_produces_string_even_if_the_value_would_otherwise_be_numeric) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); GString *formatted_value = g_string_sized_new(64); LogMessage *msg = create_sample_message(); LogMessageValueType type; LogTemplate *template = compile_template("$FACILITY_NUM"); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("19", formatted_value->str); cr_assert_eq(type, LM_VT_INTEGER); log_template_unref(template); template = compile_escaped_template("$FACILITY_NUM"); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("19", formatted_value->str); cr_assert_eq(type, LM_VT_STRING); log_template_unref(template); template = compile_template("$number1"); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("123", formatted_value->str); cr_assert_eq(type, LM_VT_INTEGER); log_template_unref(template); template = compile_escaped_template("$number1"); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("123", formatted_value->str); cr_assert_eq(type, LM_VT_STRING); log_template_unref(template); log_msg_unref(msg); g_string_free(formatted_value, TRUE); } Test(template, test_bytes_and_protobuf_types_are_rendered_when_necessary) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); LogTemplate *template = log_template_new(configuration, NULL); GError *error = NULL; gboolean result; GString *formatted_value = g_string_sized_new(64); LogMessage *msg = create_sample_message(); LogMessageValueType type; result = log_template_compile(template, "$bytes", &error); cr_assert(result); cr_assert_eq(error, NULL); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_NULL); result = log_template_compile(template, "$protobuf", &error); cr_assert(result); cr_assert_eq(error, NULL); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_NULL); result = log_template_compile_with_type_hint(template, "bytes($bytes almafa)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_BYTES); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_eq(formatted_value->len, 11); cr_assert_eq(memcmp(formatted_value->str, "\0\1\2\3 almafa", 11), 0); cr_assert_eq(type, LM_VT_BYTES); result = log_template_compile_with_type_hint(template, "protobuf($protobuf almafa)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_PROTOBUF); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_eq(formatted_value->len, 11); cr_assert_eq(memcmp(formatted_value->str, "\4\5\6\7 almafa", 11), 0); cr_assert_eq(type, LM_VT_PROTOBUF); result = log_template_compile_with_type_hint(template, "bytes($protobuf)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_BYTES); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_BYTES); result = log_template_compile_with_type_hint(template, "protobuf($bytes)", &error); cr_assert(result); cr_assert_eq(error, NULL); cr_assert_eq(template->type_hint, LM_VT_PROTOBUF); log_template_format_value_and_type(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, formatted_value, &type); cr_assert_str_eq("", formatted_value->str); cr_assert_eq(type, LM_VT_PROTOBUF); log_template_unref(template); log_msg_unref(msg); g_string_free(formatted_value, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/template/tests/test_template_compile.c000066400000000000000000000367671450431004300256470ustar00rootroot00000000000000/* * Copyright (c) 2013-2014 Balabit * Copyright (c) 2013-2014 Balázs Scheidler * Copyright (c) 2013 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "template/templates.c" #include "template/simple-function.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "cfg.h" #include "plugin.h" static void hello(LogMessage *msg, int argc, GString *argv[], GString *result) { return; } TEMPLATE_FUNCTION_SIMPLE(hello); Plugin hello_plugin = TEMPLATE_FUNCTION_PLUGIN(hello, "hello"); #define assert_common_element(expected) \ cr_assert_str_eq(current_elem->text, expected.text, "%s", "Bad compiled template text"); \ if (expected.default_value) \ { \ cr_assert_str_eq(current_elem->default_value, expected.default_value, "%s", "Bad compiled template default value"); \ } \ else \ { \ cr_assert_null(current_elem->default_value, "%s", "Bad compiled template default value"); \ } \ cr_assert_eq(current_elem->msg_ref, expected.msg_ref, "%s", "Bad compiled template msg_ref"); #define fill_expected_template_element(element, text, default_value, spec, type, msg_ref) {\ element.text; \ element.default_value; \ element.spec; \ element.type; \ element.msg_ref; } #define assert_compiled_template(set_text, set_default_value, spec, type, msg_ref) \ do { \ const gchar *text; \ set_text; \ gchar *text_mut = g_strdup(text); \ \ const gchar *default_value; \ set_default_value; \ gchar *default_value_mut = g_strdup(default_value); \ \ LogTemplateElem expected_elem; \ \ fill_expected_template_element(expected_elem, text = text_mut, \ default_value = default_value_mut, spec, type, msg_ref); \ cr_assert_eq((current_elem->type), (expected_elem.type), "%s", "Bad compiled template type"); \ assert_common_element(expected_elem); \ if ((expected_elem.type) == LTE_MACRO) cr_assert_eq(current_elem->macro, expected_elem.macro, "%s", "Bad compiled template macro"); \ if ((expected_elem.type) == LTE_VALUE) cr_assert_eq(current_elem->value_handle, expected_elem.value_handle, "%s", "Bad compiled template macro"); \ if ((expected_elem.type) == LTE_FUNC) cr_assert_eq(current_elem->func.ops, expected_elem.func.ops, "%s", "Bad compiled template macro"); \ g_free(text_mut); \ g_free(default_value_mut); \ } while (0) static LogTemplate *template; static GList *current_elem_list; static LogTemplateElem *current_elem; static void select_current_element(void) { current_elem = (LogTemplateElem *) current_elem_list->data; } static void select_first_element(void) { current_elem_list = template->compiled_template; select_current_element(); } static void select_next_element(void) { current_elem_list = current_elem_list->next; select_current_element(); } static inline void assert_template_compile(const gchar *template_string) { GError *error = NULL; cr_assert(log_template_compile(template, template_string, &error), "%s", "Can't compile template"); cr_assert_str_eq(template->template_str, template_string, "%s", "Bad stored template"); select_first_element(); } static inline void assert_failed_template_compile(const gchar *template_string, const gchar *expected_error_message) { GError *error = NULL; cr_assert_not(log_template_compile(template, template_string, &error), "%s", "Can compile bad template"); cr_assert_str_eq(error->message, expected_error_message, "%s", "Bad error message"); g_clear_error(&error); select_first_element(); } static gpointer get_template_function_ops(const gchar *name) { Plugin *plugin; plugin = cfg_find_plugin(configuration, LL_CONTEXT_TEMPLATE_FUNC, name); cr_assert_not_null(plugin, "Template function %s is not found", name); if (plugin) return plugin->construct(plugin); return NULL; } Test(template_compile, test_simple_string_literal) { const gchar *text_ = "Test String"; assert_template_compile(text_); assert_compiled_template(text = text_, default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_simple_macro) { assert_template_compile("${MESSAGE}"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_macro_and_text) { assert_template_compile("${MESSAGE}test value"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); select_next_element(); assert_compiled_template(text = "test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_macro_without_braces) { assert_template_compile("$MESSAGE"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_macro_name_without_braces_are_terminated_with_non_identifier_characters) { /* macro names consist of [A-Z0-9_] */ assert_template_compile("$MESSAGE test value"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); select_next_element(); assert_compiled_template(text = " test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_macro_without_at_records_that_no_msgref_was_present_by_msgref_zero) { assert_template_compile("${MESSAGE}"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_macro_with_at_references_a_single_msg_in_the_context_stack_by_setting_msgref) { assert_template_compile("${MESSAGE}@0"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 1); assert_template_compile("${MESSAGE}@1"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 2); } Test(template_compile, test_macro_with_invalid_msgref_are_recognized_as_the_top_element_in_the_stack) { assert_template_compile("${MESSAGE}@gmail.com"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); select_next_element(); assert_compiled_template(text = "@gmail.com", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_dollar_prefixed_with_backslash_is_a_literal_dollar) { cfg_set_version_without_validation(configuration, 0x304); assert_template_compile("Test \\$STRING"); assert_compiled_template(text = "Test $STRING", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); cfg_set_version_without_validation(configuration, 0x305); assert_template_compile("Test \\$STRING"); assert_compiled_template(text = "Test \\", default_value = NULL, value_handle = log_msg_get_value_handle("STRING"), type = LTE_VALUE, msg_ref = 0); } Test(template_compile, test_colon_dash_in_braces_is_parsed_as_default_value) { assert_template_compile("${MESSAGE:-default value}"); assert_compiled_template(text = "", default_value = "default value", macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); assert_template_compile("${MESSAGE:-}"); assert_compiled_template(text = "", default_value = "", macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_double_dollars_is_a_literal_dollar) { assert_template_compile("$$VALUE_NAME"); assert_compiled_template(text = "$VALUE_NAME", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); assert_template_compile("$${VALUE_NAME}"); assert_compiled_template(text = "${VALUE_NAME}", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_dollar_with_an_invalid_macro_name_without_braces_is_parsed_as_a_literal_dollar) { assert_template_compile("$:VALUE_NAME"); assert_compiled_template(text = "$:VALUE_NAME", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); assert_template_compile("$"); assert_compiled_template(text = "$", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_backslash_without_finishing_the_escape_sequence_is_ignored) { cfg_set_version_without_validation(configuration, 0x304); assert_template_compile("foo\\"); assert_compiled_template(text = "foo", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); cfg_set_version_without_validation(configuration, 0x305); assert_template_compile("foo\\"); assert_compiled_template(text = "foo\\", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_double_at_is_a_literal_at) { assert_template_compile("${MESSAGE}@@12"); assert_compiled_template(text = "", default_value = NULL, macro = M_MESSAGE, type = LTE_MACRO, msg_ref = 0); select_next_element(); assert_compiled_template(text = "@12", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_simple_value) { assert_template_compile("${VALUE_NAME}"); assert_compiled_template(text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE_NAME"), type = LTE_VALUE, msg_ref = 0); } Test(template_compile, test_value_without_braces) { assert_template_compile("$VALUE_NAME"); assert_compiled_template(text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE_NAME"), type = LTE_VALUE, msg_ref = 0); } Test(template_compile, test_backslash_within_braces_is_taken_literally) { assert_template_compile("${VALUE\\}NAME}"); assert_compiled_template(text = "", default_value = NULL, value_handle = log_msg_get_value_handle("VALUE\\"), type = LTE_VALUE, msg_ref = 0); } Test(template_compile, test_value_name_can_be_the_empty_string_when_referenced_using_braces) { assert_template_compile("${}"); assert_compiled_template(text = "", default_value = NULL, value_handle = log_msg_get_value_handle(""), type = LTE_VALUE, msg_ref = 0); } Test(template_compile, test_simple_template_function) { assert_template_compile("$(hello)"); assert_compiled_template(text = "", default_value = NULL, func.ops = get_template_function_ops("hello"), type = LTE_FUNC, msg_ref = 0); } Test(template_compile, test_complicated_template_function) { assert_template_compile("$( hello \\tes\t\t\t value(xyz) \"value with spaces\" 'test value with spa\"ces')@2"); assert_compiled_template(text = "", default_value = NULL, func.ops = get_template_function_ops("hello"), type = LTE_FUNC, msg_ref = 3); } Test(template_compile, test_simple_template_function_with_additional_text) { assert_template_compile("$(hello)test value"); assert_compiled_template(text = "", default_value = NULL, func.ops = get_template_function_ops("hello"), type = LTE_FUNC, msg_ref = 0); select_next_element(); assert_compiled_template(text = "test value", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_qouted_string_in_name_template_function) { assert_template_compile("$(he\"ll\"o)"); assert_compiled_template(text = "", default_value = NULL, func.ops = get_template_function_ops("hello"), type = LTE_FUNC, msg_ref = 0); } Test(template_compile, test_invalid_macro) { assert_failed_template_compile("${MESSAGE", "Invalid macro, '}' is missing, error_pos='9'"); assert_compiled_template(text = "error in template: ${MESSAGE", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_invalid_subst) { assert_failed_template_compile("${MESSAGE:1}", "Unknown substitution function, error_pos='10'"); assert_compiled_template(text = "error in template: ${MESSAGE:1}", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_template_function_bad1) { assert_failed_template_compile("$( hello \\tes\t\t\t value(xyz \"value with spaces\" 'test value with spa\"ces')", "Invalid template function reference, missing function name or imbalanced '(', error_pos='73'"); assert_compiled_template(text = "error in template: $( hello \\tes\t\t\t value(xyz \"value with spaces\" 'test value with spa\"ces')", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_template_function_bad2) { assert_failed_template_compile("$( hello \\tes\t\t\t value xyz \"value with spaces\" 'test value with spa\"ces'", "Invalid template function reference, missing function name or imbalanced '(', error_pos='72'"); assert_compiled_template(text = "error in template: $( hello \\tes\t\t\t value xyz \"value with spaces\" 'test value with spa\"ces'", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_template_function_bad3) { assert_failed_template_compile("$(hello \"This is an unclosed quoted string)", "Invalid template function reference, missing function name or imbalanced '(', error_pos='8'"); assert_compiled_template(text = "error in template: $(hello \"This is an unclosed quoted string)", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } Test(template_compile, test_unknown_function) { assert_failed_template_compile("$(unknown function)", "Unknown template function \"unknown\""); assert_compiled_template(text = "error in template: $(unknown function)", default_value = NULL, macro = M_NONE, type = LTE_MACRO, msg_ref = 0); } static void setup(void) { msg_init(FALSE); configuration = cfg_new_snippet(); log_msg_registry_init(); log_template_global_init(); plugin_register(&configuration->plugin_context, &hello_plugin, 1); template = log_template_new(configuration, NULL); start_grabbing_messages(); } static void teardown(void) { log_msg_registry_deinit(); msg_deinit(); log_template_unref(template); template = NULL; stop_grabbing_messages(); } TestSuite(template_compile, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/template/tests/test_template_on_error.c000066400000000000000000000045571450431004300260340ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "template/templates.h" #include "apphook.h" #include typedef struct _TemplateTestCase { const gchar *actual; gint expected; } TemplateTestCase; ParameterizedTestParameters(template_on_err, test_success) { static TemplateTestCase test_cases[] = { {"drop-message", ON_ERROR_DROP_MESSAGE}, {"silently-drop-message", ON_ERROR_DROP_MESSAGE | ON_ERROR_SILENT}, {"drop-property", ON_ERROR_DROP_PROPERTY}, {"silently-drop-property", ON_ERROR_DROP_PROPERTY | ON_ERROR_SILENT}, {"fallback-to-string", ON_ERROR_FALLBACK_TO_STRING}, {"silently-fallback-to-string", ON_ERROR_FALLBACK_TO_STRING | ON_ERROR_SILENT} }; return cr_make_param_array(TemplateTestCase, test_cases, sizeof(test_cases) / sizeof(test_cases[0])); } ParameterizedTest(TemplateTestCase *test_cases, template_on_err, test_success) { gint r; cr_assert(log_template_on_error_parse(test_cases->actual, &r), "Parsing '%s' works", test_cases->actual); cr_assert_eq(r, test_cases->expected, "'%s' parses down to '%d'", test_cases->actual, test_cases->expected); } Test(template_on_error, test_fail) { gint r; gchar *pattern = "do-what-i-mean"; cr_assert_not(log_template_on_error_parse(pattern, &r), "Parsing '%s' works", pattern); } TestSuite(template_on_error, .init = app_startup, .fini = app_shutdown); syslog-ng-syslog-ng-4.4.0/lib/template/tests/test_template_speed.c000066400000000000000000000042151450431004300252760ustar00rootroot00000000000000/* * Copyright (c) 2009-2018 Balabit * Copyright (c) 2009-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "libtest/stopwatch.h" #include "apphook.h" #include "cfg.h" Test(template_speed, test_template_speed) { app_startup(); init_template_tests(); setenv("TZ", "MET-1METDST", TRUE); tzset(); cfg_load_module(configuration, "syslogformat"); cfg_load_module(configuration, "basicfuncs"); perftest_template("$DATE\n"); perftest_template("<$PRI>$DATE $HOST $MSGHDR$MSG\n"); perftest_template("$DATE\n"); perftest_template("$DATE $HOST\n"); perftest_template("$DATE $HOST $MSGHDR\n"); perftest_template("$DATE $HOST $MSGHDR$MSG\n"); perftest_template("$DATE $HOST $MSGHDR$MSG value\n"); perftest_template("$DATE $HOST $MSGHDR$MSG ${APP.VALUE}\n"); perftest_template("$MSG\n"); perftest_template("$TAGS\n"); perftest_template("$(echo $MSG)\n"); perftest_template("$(+ $FACILITY_NUM $FACILITY_NUM)\n"); perftest_template("$DATE $FACILITY.$PRIORITY $HOST $MSGHDR$MSG $SEQNO\n"); perftest_template("${APP.VALUE} ${APP.VALUE2}\n"); perftest_template("$DATE ${HOST:--} ${PROGRAM:--} ${PID:--} ${MSGID:--} ${SDATA:--} $MSG\n"); app_shutdown(); } syslog-ng-syslog-ng-4.4.0/lib/template/user-function.c000066400000000000000000000075401450431004300227070ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "template/function.h" #include "plugin.h" typedef struct _UserTemplateFunction { LogTemplateFunction super; gchar *name; LogTemplate *template; } UserTemplateFunction; static gboolean user_template_function_prepare(LogTemplateFunction *s, gpointer state, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { UserTemplateFunction *self = (UserTemplateFunction *) s; g_return_val_if_fail(error == NULL || (*error) == NULL, FALSE); if (argc != 1) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "User defined template function $(%s) cannot have arguments", self->name); return FALSE; } return TRUE; } static void user_template_function_call(LogTemplateFunction *s, gpointer state, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { UserTemplateFunction *self = (UserTemplateFunction *) s; log_template_append_format_value_and_type_with_context(self->template, args->messages, args->num_messages, args->options, result, type); } static void user_template_function_free(LogTemplateFunction *s) { UserTemplateFunction *self = (UserTemplateFunction *) s; g_free(self->name); log_template_unref(self->template); g_free(self); } LogTemplateFunction * user_template_function_new(const gchar *name, LogTemplate *template) { UserTemplateFunction *self; self = g_new0(UserTemplateFunction, 1); self->super.size_of_state = 0; self->super.prepare = user_template_function_prepare; self->super.call = user_template_function_call; self->super.free_fn = user_template_function_free; self->template = log_template_ref(template); self->name = g_strdup(name); return &self->super; } typedef struct _UserTemplateFunctionPlugin { Plugin super; LogTemplate *template; } UserTemplateFunctionPlugin; static gpointer user_template_function_construct(Plugin *s) { UserTemplateFunctionPlugin *self = (UserTemplateFunctionPlugin *) s; return user_template_function_new(self->super.name, self->template); } static void user_template_function_plugin_free(Plugin *s) { UserTemplateFunctionPlugin *plugin = (UserTemplateFunctionPlugin *) s; g_free((gchar *) plugin->super.name); log_template_unref(plugin->template); g_free(s); } void user_template_function_register(GlobalConfig *cfg, const gchar *name, LogTemplate *template) { UserTemplateFunctionPlugin *plugin; plugin = g_new0(UserTemplateFunctionPlugin, 1); plugin->super.type = LL_CONTEXT_TEMPLATE_FUNC; plugin->super.name = g_strdup(name); plugin->super.parser = NULL; plugin->super.construct = user_template_function_construct; plugin->super.free_fn = user_template_function_plugin_free; plugin->template = log_template_ref(template); plugin_register(&cfg->plugin_context, &plugin->super, 1); } syslog-ng-syslog-ng-4.4.0/lib/template/user-function.h000066400000000000000000000023061450431004300227070ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TEMPLATE_USER_FUNCTION_H_INCLUDED #define TEMPLATE_USER_FUNCTION_H_INCLUDED #include "syslog-ng.h" void user_template_function_register(GlobalConfig *cfg, const gchar *name, LogTemplate *template); #endif syslog-ng-syslog-ng-4.4.0/lib/tests/000077500000000000000000000000001450431004300172635ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/tests/CMakeLists.txt000066400000000000000000000041141450431004300220230ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_cfg_lexer_subst) add_unit_test(CRITERION TARGET test_cfg_tree) add_unit_test(CRITERION TARGET test_parse_number) add_unit_test(CRITERION TARGET test_reloc) add_unit_test(CRITERION TARGET test_hostname) add_unit_test(CRITERION LIBTEST TARGET test_rcptid) add_unit_test(CRITERION LIBTEST TARGET test_lexer) add_unit_test(CRITERION LIBTEST TARGET test_pragma) add_unit_test(CRITERION TARGET test_lexer_block) add_unit_test(CRITERION TARGET test_str_format) add_unit_test(CRITERION TARGET test_str-utils) add_unit_test(CRITERION TARGET test_string_list) add_unit_test(LIBTEST CRITERION TARGET test_runid) add_unit_test(CRITERION TARGET test_pathutils) add_unit_test(CRITERION TARGET test_utf8utils) add_unit_test(CRITERION TARGET test_userdb) add_unit_test(LIBTEST CRITERION TARGET test_logqueue) add_unit_test(CRITERION TARGET test_cache) add_unit_test(CRITERION TARGET test_scratch_buffers) add_unit_test(CRITERION TARGET test_messages) add_unit_test(CRITERION TARGET test_atomic_gssize) add_unit_test(CRITERION TARGET test_window_size_counter) add_unit_test(CRITERION TARGET test_apphook) add_unit_test(CRITERION TARGET test_dynamic_window) add_unit_test(CRITERION TARGET test_logsource) add_unit_test(LIBTEST CRITERION TARGET test_logscheduler) add_unit_test(CRITERION LIBTEST TARGET test_persist_state) add_unit_test(LIBTEST CRITERION TARGET test_matcher) add_unit_test(LIBTEST CRITERION TARGET test_clone_logmsg) add_unit_test(CRITERION TARGET test_serialize) add_unit_test(LIBTEST CRITERION TARGET test_msgparse DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_dnscache) add_unit_test(CRITERION TARGET test_findcrlf) add_unit_test(CRITERION TARGET test_ringbuffer) add_unit_test(CRITERION TARGET test_hostid) add_unit_test(CRITERION TARGET test_zone) add_unit_test(CRITERION TARGET test_logwriter DEPENDS syslogformat) add_unit_test(CRITERION TARGET test_thread_wakeup) add_unit_test(CRITERION TARGET test_generic_number) SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "test_values.persist;test_values.persist-;test_run_id.persist;test_run_id.persist-") syslog-ng-syslog-ng-4.4.0/lib/tests/Makefile.am000066400000000000000000000136451450431004300213300ustar00rootroot00000000000000lib_tests_TESTS = \ lib/tests/test_cfg_lexer_subst \ lib/tests/test_lexer_block \ lib/tests/test_cfg_tree \ lib/tests/test_parse_number \ lib/tests/test_generic_number \ lib/tests/test_reloc \ lib/tests/test_hostname \ lib/tests/test_rcptid \ lib/tests/test_lexer \ lib/tests/test_pragma \ lib/tests/test_str_format \ lib/tests/test_string_list \ lib/tests/test_runid \ lib/tests/test_pathutils \ lib/tests/test_utf8utils \ lib/tests/test_userdb \ lib/tests/test_str-utils \ lib/tests/test_atomic_gssize \ lib/tests/test_window_size_counter \ lib/tests/test_apphook \ lib/tests/test_dynamic_window \ lib/tests/test_logqueue \ lib/tests/test_logsource \ lib/tests/test_persist_state \ lib/tests/test_matcher \ lib/tests/test_clone_logmsg \ lib/tests/test_serialize \ lib/tests/test_msgparse \ lib/tests/test_dnscache \ lib/tests/test_findcrlf \ lib/tests/test_ringbuffer \ lib/tests/test_hostid \ lib/tests/test_zone \ lib/tests/test_logwriter \ lib/tests/test_thread_wakeup \ lib/tests/test_logscheduler EXTRA_DIST += lib/tests/CMakeLists.txt check_PROGRAMS += ${lib_tests_TESTS} if ENABLE_TESTING noinst_PROGRAMS += \ lib/tests/test_host_resolve lib_tests_test_host_resolve_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_host_resolve_LDADD = \ $(TEST_LDADD) endif lib_tests_test_cfg_lexer_subst_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_cfg_lexer_subst_LDADD = \ $(TEST_LDADD) lib_tests_test_lexer_block_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_lexer_block_LDADD = \ $(TEST_LDADD) lib_tests_test_cfg_tree_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_cfg_tree_LDADD = \ $(TEST_LDADD) lib_tests_test_parse_number_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_parse_number_LDADD = \ $(TEST_LDADD) lib_tests_test_generic_number_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_generic_number_LDADD = \ $(TEST_LDADD) lib_tests_test_reloc_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_reloc_LDADD = \ $(TEST_LDADD) lib_tests_test_hostname_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_hostname_LDADD = \ $(TEST_LDADD) lib_tests_test_rcptid_CFLAGS = $(TEST_CFLAGS) lib_tests_test_rcptid_LDADD = \ $(TEST_LDADD) lib_tests_test_lexer_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_lexer_LDADD = \ $(TEST_LDADD) lib_tests_test_pragma_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_pragma_LDADD = \ $(TEST_LDADD) lib_tests_test_runid_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_runid_LDADD = \ $(TEST_LDADD) lib_tests_test_str_format_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_str_format_LDADD = \ $(TEST_LDADD) lib_tests_test_string_list_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_string_list_LDADD = \ $(TEST_LDADD) lib_tests_test_pathutils_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_pathutils_LDADD = \ $(TEST_LDADD) lib_tests_test_utf8utils_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_utf8utils_LDADD = \ $(TEST_LDADD) lib_tests_test_str_utils_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_str_utils_LDADD = \ $(TEST_LDADD) lib_tests_test_atomic_gssize_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_atomic_gssize_LDADD = \ $(TEST_LDADD) lib_tests_test_window_size_counter_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_window_size_counter_LDADD = \ $(TEST_LDADD) lib_tests_test_apphook_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_apphook_LDADD = \ $(TEST_LDADD) lib_tests_test_dynamic_window_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_dynamic_window_LDADD = \ $(TEST_LDADD) lib_tests_test_logqueue_CFLAGS = $(TEST_CFLAGS) lib_tests_test_logqueue_LDADD = $(TEST_LDADD) lib_tests_test_logsource_CFLAGS = $(TEST_CFLAGS) lib_tests_test_logsource_LDADD = $(TEST_LDADD) lib_tests_test_logscheduler_CFLAGS = $(TEST_CFLAGS) lib_tests_test_logscheduler_LDADD = $(TEST_LDADD) lib_tests_test_persist_state_CFLAGS = $(TEST_CFLAGS) lib_tests_test_persist_state_LDADD = $(TEST_LDADD) CLEANFILES += \ test_values.persist \ test_values.persist- \ test_run_id.persist \ test_run_id.persist- lib_tests_test_userdb_CFLAGS = $(TEST_CFLAGS) lib_tests_test_userdb_LDADD = \ $(TEST_LDADD) lib_tests_TESTS += \ lib/tests/test_cache \ lib/tests/test_scratch_buffers \ lib/tests/test_messages lib_tests_test_cache_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_cache_LDADD = \ $(TEST_LDADD) lib_tests_test_scratch_buffers_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_scratch_buffers_LDADD = \ $(TEST_LDADD) lib_tests_test_messages_CFLAGS = \ $(TEST_CFLAGS) lib_tests_test_messages_LDADD = \ $(TEST_LDADD) lib_tests_test_logwriter_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_logwriter_CFLAGS = $(TEST_CFLAGS) lib_tests_test_matcher_CFLAGS = $(TEST_CFLAGS) lib_tests_test_matcher_LDADD = $(TEST_LDADD) lib_tests_test_clone_logmsg_CFLAGS = $(TEST_CFLAGS) lib_tests_test_clone_logmsg_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_serialize_CFLAGS = $(TEST_CFLAGS) lib_tests_test_serialize_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_msgparse_CFLAGS = $(TEST_CFLAGS) lib_tests_test_msgparse_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_dnscache_CFLAGS = $(TEST_CFLAGS) lib_tests_test_dnscache_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_findcrlf_CFLAGS = $(TEST_CFLAGS) lib_tests_test_findcrlf_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_ringbuffer_CFLAGS = $(TEST_CFLAGS) lib_tests_test_ringbuffer_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_hostid_CFLAGS = $(TEST_CFLAGS) lib_tests_test_hostid_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_zone_LDADD = \ $(TEST_LDADD) $(PREOPEN_SYSLOGFORMAT) lib_tests_test_zone_CFLAGS = $(TEST_CFLAGS) lib_tests_test_thread_wakeup_CFLAGS = $(TEST_CFLAGS) lib_tests_test_thread_wakeup_LDADD = $(TEST_LDADD) EXTRA_DIST += \ lib/tests/testdata-lexer/include-test/bar.conf \ lib/tests/testdata-lexer/include-test/baz.conf \ lib/tests/testdata-lexer/include-test/foo.conf \ lib/tests/testdata-lexer/include-test/invalid~include~file.conf syslog-ng-syslog-ng-4.4.0/lib/tests/test_apphook.c000066400000000000000000000123621450431004300221330ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" Test(test_apphook, app_is_tarting_up) { cr_assert(app_is_starting_up()); cr_assert_not(app_is_shutting_down()); } static void _hook_counter(gint type, gpointer user_data) { gint *triggered_count = (gboolean *)user_data; (*triggered_count)++; } Test(test_apphook, post_daemon_hook) { gint triggered_count = 0; register_application_hook(AH_POST_DAEMONIZED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); cr_assert(app_is_starting_up()); app_post_daemonized(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, post_daemon_triggered_twice) { gint triggered_count = 0; register_application_hook(AH_POST_DAEMONIZED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_post_daemonized(); app_post_daemonized(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, pre_shutdown_hook) { gint triggered_count = 0; register_application_hook(AH_PRE_SHUTDOWN, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_pre_shutdown(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, shutdown_hook) { gint triggered_count = 0; register_application_hook(AH_SHUTDOWN, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_startup(); //This is needed for shutdown app_shutdown(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, config_changed) { gint triggered_count = 0; register_application_hook(AH_CONFIG_CHANGED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_config_changed(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, reopen_hook) { gint triggered_count = 0; register_application_hook(AH_REOPEN_FILES, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_reopen_files(); cr_assert_eq(triggered_count, 1); } static void _re_registering_hook(gint type, gpointer user_data) { _hook_counter(type, user_data); register_application_hook(type, _re_registering_hook, user_data, AHM_RUN_ONCE); } Test(test_apphook, hook_register_from_hook) { gint triggered_count = 0; register_application_hook(AH_REOPEN_FILES, _re_registering_hook, (gpointer)&triggered_count, AHM_RUN_ONCE); app_reopen_files(); cr_assert_eq(triggered_count, 1); } static void _repeated_hook(gint type, gpointer user_data) { _hook_counter(type, user_data); } Test(test_apphook, hook_run_mode_repeat_repeats_hook_invocation_multiple_times) { gint triggered_count = 0; register_application_hook(AH_REOPEN_FILES, _repeated_hook, (gpointer)&triggered_count, AHM_RUN_REPEAT); app_reopen_files(); cr_assert_eq(triggered_count, 1); app_reopen_files(); cr_assert_eq(triggered_count, 2); app_reopen_files(); cr_assert_eq(triggered_count, 3); } Test(test_apphook, hook_register_from_hook_and_other_not_triggered_hooks) { gint triggered_count = 0; register_application_hook(AH_PRE_SHUTDOWN, NULL, NULL, AHM_RUN_ONCE); register_application_hook(AH_REOPEN_FILES, _re_registering_hook, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_PRE_SHUTDOWN, NULL, NULL, AHM_RUN_ONCE); app_reopen_files(); cr_assert_eq(triggered_count, 1); } Test(test_apphook, trigger_all_state_hook) { gint triggered_count = 0; register_application_hook(AH_POST_DAEMONIZED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_RUNNING, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_PRE_SHUTDOWN, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_SHUTDOWN, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_CONFIG_CHANGED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); register_application_hook(AH_REOPEN_FILES, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); app_startup(); app_post_daemonized(); cr_assert_eq(triggered_count, 1); app_running(); cr_assert_eq(triggered_count, 2); /* check that a state that has already passed would be invoked immediately */ register_application_hook(AH_POST_DAEMONIZED, _hook_counter, (gpointer)&triggered_count, AHM_RUN_ONCE); cr_assert_eq(triggered_count, 3); app_config_changed(); app_reopen_files(); cr_assert_eq(triggered_count, 5); app_pre_shutdown(); app_shutdown(); cr_assert_eq(triggered_count, 7); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_atomic_gssize.c000066400000000000000000000045241450431004300233330ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "atomic-gssize.h" Test(test_atomic_gssize, set_min_value) { atomic_gssize min; atomic_gssize_set(&min, G_MINSSIZE); cr_assert_eq(atomic_gssize_get(&min), G_MINSSIZE); atomic_gssize_inc(&min); cr_assert_eq(atomic_gssize_get(&min), G_MINSSIZE+1); atomic_gssize_sub(&min, 2); cr_assert_eq(atomic_gssize_get(&min), G_MAXSSIZE); } Test(test_atomic_gssize, set_max_value) { atomic_gssize max; atomic_gssize_set(&max, G_MAXSSIZE); cr_assert_eq(atomic_gssize_get(&max), G_MAXSSIZE); atomic_gssize_dec(&max); cr_assert_eq(atomic_gssize_get(&max), G_MAXSSIZE - 1); gssize old = atomic_gssize_add(&max, 2); cr_assert_eq(old, G_MAXSSIZE - 1); cr_assert_eq(atomic_gssize_get(&max), G_MINSSIZE); } Test(test_atomic_gssize, use_as_unsigned) { atomic_gssize a; atomic_gssize_set(&a, G_MAXSIZE); cr_assert_eq(atomic_gssize_get_unsigned(&a), G_MAXSIZE); atomic_gssize_inc(&a); cr_assert_eq(atomic_gssize_get_unsigned(&a), 0); atomic_gssize_dec(&a); cr_assert_eq(atomic_gssize_get_unsigned(&a), G_MAXSIZE); } Test(test_atomic_gssize, or_xor_and) { atomic_gssize a; atomic_gssize_set(&a, 1); atomic_gssize_or(&a, 2); cr_assert_eq(atomic_gssize_get_unsigned(&a), 3); atomic_gssize_xor(&a, 3); cr_assert_eq(atomic_gssize_get_unsigned(&a), 0); atomic_gssize_set(&a, 3); atomic_gssize_and(&a, 2); cr_assert_eq(atomic_gssize_get_unsigned(&a), 2); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_cache.c000066400000000000000000000076111450431004300215360ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "cache.h" gint fetch_count; gint free_fn_count; void * fetch(CacheResolver *self, const gchar *key) { fetch_count++; return g_strdup_printf("almafa_%s", key); } void free_fn(CacheResolver *self) { free_fn_count++; return; } CacheResolver * dummy_cache_resolver(void) { CacheResolver *self = g_new0(CacheResolver, 1); self->resolve_elem = fetch; self->free_elem = g_free; self->free_fn = free_fn; return self; } static void assert_cache_resolve(Cache *c, const gchar *key) { gchar *value; gchar *expected_value = g_strdup_printf("almafa_%s", key); value = cache_resolve(c, key); cr_assert_str_eq(value, expected_value, "Lookup key: %s, Expected value: %s, Actual value: %s", key, value, expected_value); g_free(value); g_free(expected_value); } static void assert_cache_lookup(Cache *c, const gchar *key) { gchar *value; gchar *expected_value = g_strdup_printf("almafa_%s", key); value = cache_lookup(c, key); cr_assert_str_eq(value, expected_value, "Lookup key: %s, Expected value: %s, Actual value: %s", key, value, expected_value); g_free(expected_value); } static void assert_cache_lookup_uncached(Cache *c, const gchar *key) { fetch_count = 0; assert_cache_lookup(c, key); cr_assert_eq(fetch_count, 1, "Cache lookup expected when looking up uncached elements, but one didn't arrive key=\"%s\"", key); } static void assert_cache_lookup_cached(Cache *c, const gchar *key) { fetch_count = 0; assert_cache_lookup(c, key); cr_assert_eq(fetch_count, 0, "Cache lookup unexpected when looking up cached elements, but one did arrive key=\"%s\"", key); } Test(cache, test_write_and_read) { Cache *c; c = cache_new(dummy_cache_resolver()); assert_cache_lookup_uncached(c, "key"); assert_cache_lookup_cached(c, "key"); assert_cache_lookup_uncached(c, "key2"); assert_cache_lookup_cached(c, "key2"); assert_cache_lookup_cached(c, "key"); assert_cache_lookup_cached(c, "key2"); cache_free(c); } Test(cache, cache_clear_drops_cached_elements) { Cache *c; c = cache_new(dummy_cache_resolver()); assert_cache_lookup_uncached(c, "key"); assert_cache_lookup_cached(c, "key"); assert_cache_lookup_uncached(c, "key2"); assert_cache_lookup_cached(c, "key2"); assert_cache_lookup_cached(c, "key"); assert_cache_lookup_cached(c, "key2"); cache_clear(c); assert_cache_lookup_uncached(c, "key"); assert_cache_lookup_uncached(c, "key2"); cache_free(c); } Test(cache, cache_resolve_does_not_store_element) { Cache *c; c = cache_new(dummy_cache_resolver()); assert_cache_resolve(c, "key"); assert_cache_lookup_uncached(c, "key"); assert_cache_lookup_cached(c, "key"); } Test(cache, test_free_calls_resolver_free_fn) { Cache *c; free_fn_count = 0; c = cache_new(dummy_cache_resolver()); cache_free(c); cr_assert_eq(free_fn_count, 1, "cache_free call the free_fn %d times", free_fn_count); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_cfg_lexer_subst.c000066400000000000000000000250771450431004300236570ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "cfg-lexer-subst.h" #include "apphook.h" #include static CfgArgs * construct_cfg_args_for_args(const gchar *additional_values[]) { CfgArgs *args = cfg_args_new(); gint i; cfg_args_set(args, "arg", "arg_value"); cfg_args_set(args, "simple_string", "\"simple_string_value\""); cfg_args_set(args, "simple_qstring", "'simple_qstring_value'"); cfg_args_set(args, "escaped_string", "\"escaped_string\\\"\\r\\n\""); cr_assert(cfg_args_contains(args, "simple-string"), "normalize: when set, must contain: simple-string"); cr_assert(cfg_args_contains(args, "simple_string"), "normalize: when set, must contain: simple_string"); for (i = 0; additional_values && additional_values[i] && additional_values[i + 1]; i += 2) { cfg_args_set(args, additional_values[i], additional_values[i + 1]); } return args; } static CfgArgs * construct_cfg_args_for_defaults(void) { CfgArgs *args = cfg_args_new(); cfg_args_set(args, "arg", "default_for_arg"); cfg_args_set(args, "def", "default_for_def"); return args; } static CfgArgs * construct_cfg_args_for_globals(void) { CfgArgs *args = cfg_args_new(); cfg_args_set(args, "arg", "global_for_arg"); cfg_args_set(args, "def", "global_for_def"); cfg_args_set(args, "globl", "global_for_globl"); return args; } static CfgLexerSubst * construct_object_with_values(const gchar *additional_values[]) { return cfg_lexer_subst_new(construct_cfg_args_for_globals(), construct_cfg_args_for_defaults(), construct_cfg_args_for_args(additional_values)); } static CfgLexerSubst * construct_object(void) { return construct_object_with_values(NULL); } static gchar * duplicate_string_without_with_trailing_nonzero_bytes(const gchar *input) { gsize input_len = strlen(input); const gint canary_size = 10; gchar *input_dup = malloc(input_len + canary_size); memcpy(input_dup, input, input_len); memset(input_dup + input_len, 'A', canary_size - 1); input_dup[input_len + canary_size - 1] = 0; return input_dup; } static void _assert_invoke_result(CfgLexerSubst *subst, gchar *input_dup, gssize input_len, const gchar *expected_output) { gchar *result; gsize result_len; GError *error = NULL; result = cfg_lexer_subst_invoke(subst, input_dup, input_len, &result_len, &error); cr_assert_null(error, "Error value is non-null while no error is expected"); cr_assert_not_null(result, "value substitution returned an unexpected failure"); cr_assert_str_eq(result, expected_output, "value substitution is broken"); cr_assert_eq(result_len, strlen(expected_output), "length returned by invoke_result is invalid"); g_free(result); } static void assert_invoke_result_with_input_length_explicit(CfgLexerSubst *subst, const gchar *input, const gchar *expected_output) { gchar *input_dup; input_dup = duplicate_string_without_with_trailing_nonzero_bytes(input); _assert_invoke_result(subst, input_dup, strlen(input), expected_output); g_free(input_dup); } static void assert_invoke_result_with_zero_terminated_input(CfgLexerSubst *subst, const gchar *input, const gchar *expected_output) { gchar *input_dup; input_dup = strdup(input); _assert_invoke_result(subst, input_dup, -1, expected_output); g_free(input_dup); } static void assert_invoke_result(CfgLexerSubst *subst, const gchar *input, const gchar *expected_output) { assert_invoke_result_with_input_length_explicit(subst, input, expected_output); assert_invoke_result_with_zero_terminated_input(subst, input, expected_output); } static void assert_invoke_failure(CfgLexerSubst *subst, const gchar *input, const gchar *expected_error) { gchar *result; gsize result_len; gchar *input_dup = g_strdup(input); GError *error = NULL; result = cfg_lexer_subst_invoke(subst, input_dup, strlen(input), &result_len, &error); cr_assert_null(result, "expected failure for value substitution, but success was returned"); cr_assert_not_null(error, "expected a non-NULL error object for failure"); cr_assert_str_eq(error->message, expected_error, "error message mismatch"); g_free(input_dup); } Test(cfg_lexer_subst, test_double_backtick_replaced_with_a_single_one) { CfgLexerSubst *subst = construct_object(); assert_invoke_result(subst, "``", "`"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_single_backtick_causes_an_error) { CfgLexerSubst *subst = construct_object(); assert_invoke_failure(subst, "foo ` bar", "missing closing backtick (`) character"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_backtick_after_quoted_character_succeeds) { CfgLexerSubst *subst = construct_object(); assert_invoke_result(subst, "foo \"string \\n`arg`\" bar", "foo \"string \\narg_value\" bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_backtick_as_a_quoted_character_in_a_string_results_in_failure) { CfgLexerSubst *subst = construct_object(); assert_invoke_failure(subst, "foo \"string \\`arg`\" bar", "cannot subsitute backticked values right after a string quote character"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_value_in_normal_text_replaced_with_its_literal_value) { CfgLexerSubst *subst = construct_object(); assert_invoke_result(subst, "foo `arg` bar", "foo arg_value bar"); assert_invoke_result(subst, "foo `simple_string` bar", "foo \"simple_string_value\" bar"); assert_invoke_result(subst, "foo `simple_qstring` bar", "foo 'simple_qstring_value' bar"); assert_invoke_result(subst, "foo `escaped_string` bar", "foo \"escaped_string\\\"\\r\\n\" bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_values_are_resolution_order_args_defaults_globals_env) { CfgLexerSubst *subst = construct_object(); setenv("env", "env_for_env", TRUE); assert_invoke_result(subst, "foo `arg` bar", "foo arg_value bar"); assert_invoke_result(subst, "foo `def` bar", "foo default_for_def bar"); assert_invoke_result(subst, "foo `globl` bar", "foo global_for_globl bar"); assert_invoke_result(subst, "foo `env` bar", "foo env_for_env bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_values_are_inserted_within_strings) { CfgLexerSubst *subst = construct_object(); assert_invoke_result(subst, "foo \"`arg`\" bar", "foo \"arg_value\" bar"); assert_invoke_result(subst, "foo '`arg`' bar", "foo 'arg_value' bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_string_literals_are_inserted_into_strings_without_quotes) { const gchar *additional_values[] = { "simple_string_with_whitespace", " \"string_with_whitespace\" ", NULL, NULL }; CfgLexerSubst *subst = construct_object_with_values(additional_values); /* double quotes */ assert_invoke_result(subst, "foo \"x `simple_string` y\" bar", "foo \"x simple_string_value y\" bar"); /* apostrophes */ assert_invoke_result(subst, "foo 'x `simple_string` y' bar", "foo 'x simple_string_value y' bar"); assert_invoke_result(subst, "foo \"x `simple_string_with_whitespace` y\" bar", "foo \"x string_with_whitespace y\" bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_incorrect_strings_and_multiple_tokens_are_inserted_verbatim) { const gchar *additional_values[] = { "half_string", "\"halfstring", "tokens_that_start_with_string", "\"str\", token", "tokens_enclosed_in_strings", "\"str1\", token, \"str2\"", NULL, NULL }; CfgLexerSubst *subst = construct_object_with_values(additional_values); assert_invoke_result(subst, "foo \"x `simple_string` y\" bar", "foo \"x simple_string_value y\" bar"); assert_invoke_result(subst, "foo \"x `half_string` y\" bar", "foo \"x \"halfstring y\" bar"); assert_invoke_result(subst, "foo \"x `tokens_that_start_with_string` y\" bar", "foo \"x \"str\", token y\" bar"); assert_invoke_result(subst, "foo \"x `tokens_enclosed_in_strings` y\" bar", "foo \"x \"str1\", token, \"str2\" y\" bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_strings_with_special_chars_are_properly_encoded_in_strings) { const gchar *additional_values[] = { "string_with_characters_that_need_quoting", "\"quote: \\\", newline: \\r\\n, backslash: \\\\\"", NULL, NULL }; CfgLexerSubst *subst = construct_object_with_values(additional_values); assert_invoke_result(subst, "foo \"x `string_with_characters_that_need_quoting` y\" bar", "foo \"x quote: \\\", newline: \\r\\n, backslash: \\\\ y\" bar"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_strings_with_embedded_apostrophe_cause_an_error_when_encoding_in_qstring) { const gchar *additional_values[] = { "string_with_apostrophe", "\"'foo'\"", NULL, NULL }; CfgLexerSubst *subst = construct_object_with_values(additional_values); assert_invoke_result(subst, "foo \"x `string_with_apostrophe` y\" bar", "foo \"x 'foo' y\" bar"); assert_invoke_failure(subst, "foo 'x `string_with_apostrophe` y' bar", "cannot represent apostrophes within apostroph-enclosed string"); cfg_lexer_subst_free(subst); } Test(cfg_lexer_subst, test_tracking_string_state) { const gchar *additional_values[] = { "quoted_escaped_newline", "\"\\n\"", NULL, NULL }; CfgLexerSubst *subst = construct_object_with_values(additional_values); assert_invoke_result(subst, "\"hello\\n\" `quoted_escaped_newline`", "\"hello\\n\" \"\\n\""); assert_invoke_result(subst, "\"hello\\n\\n\" `quoted_escaped_newline`", "\"hello\\n\\n\" \"\\n\""); assert_invoke_result(subst, "\"hello\\n\\n \" `quoted_escaped_newline`", "\"hello\\n\\n \" \"\\n\""); cfg_lexer_subst_free(subst); } TestSuite(cfg_lexer_subst, .init = app_startup, .fini = app_shutdown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_cfg_tree.c000066400000000000000000000132201450431004300222420ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "cfg-tree.h" #include "apphook.h" #include "logpipe.h" /* * The Always Pipe. Always returns the same thing at init time. */ typedef struct { LogPipe super; gboolean return_value; gboolean init_called; gboolean deinit_called; } AlmightyAlwaysPipe; /* * Helper functions */ static gboolean almighty_always_pipe_init (LogPipe *s) { AlmightyAlwaysPipe *self = (AlmightyAlwaysPipe *)s; self->init_called = TRUE; return self->return_value; } static gboolean almighty_always_pipe_deinit (LogPipe *s) { AlmightyAlwaysPipe *self = (AlmightyAlwaysPipe *)s; self->deinit_called = TRUE; return TRUE; } static LogPipe * almighty_always_pipe_new (gboolean return_value) { AlmightyAlwaysPipe *self; self = g_new0 (AlmightyAlwaysPipe, 1); log_pipe_init_instance (&self->super, NULL); self->super.init = almighty_always_pipe_init; self->super.deinit = almighty_always_pipe_deinit; self->return_value = return_value; return &self->super; } static AlmightyAlwaysPipe * create_and_attach_almighty_pipe (CfgTree *tree, gboolean pipe_value) { AlmightyAlwaysPipe *pipe; pipe = (AlmightyAlwaysPipe *)almighty_always_pipe_new (pipe_value); cfg_tree_add_object (tree, log_expr_node_new_pipe (&pipe->super, NULL)); return pipe; } /* * Tests */ typedef struct _PipeParameter { gboolean always_pipe_value; gboolean tree_start_expected; gboolean tree_stop_expected; gboolean was_init_called; gboolean was_deinit_called; } PipeParameter; ParameterizedTestParameters(cfg_tree, test_pipe_init) { static PipeParameter test_data_list[] = { {.always_pipe_value = TRUE, .tree_start_expected = TRUE, .tree_stop_expected = TRUE, .was_init_called = TRUE, .was_deinit_called = TRUE}, {.always_pipe_value = FALSE, .tree_start_expected = FALSE, .tree_stop_expected = TRUE, .was_init_called = TRUE, .was_deinit_called = FALSE} }; return cr_make_param_array(PipeParameter, test_data_list, sizeof(test_data_list) / sizeof(test_data_list[0])); } ParameterizedTest(PipeParameter *test_data, cfg_tree, test_pipe_init) { CfgTree tree; AlmightyAlwaysPipe *pipe; cfg_tree_init_instance(&tree, NULL); pipe = create_and_attach_almighty_pipe(&tree, test_data->always_pipe_value); cr_assert(cfg_tree_compile (&tree)); cr_assert_eq(cfg_tree_start(&tree), test_data->tree_start_expected, "cfg_tree_start() did not return the expected value"); cr_assert_eq(cfg_tree_stop(&tree), test_data->tree_stop_expected, "cfg_tree_stop() did not return the epxected value"); cr_assert_eq(pipe->init_called, test_data->was_init_called, "->init was called state"); cr_assert_eq(pipe->deinit_called, test_data->was_deinit_called, "->deinit was called state"); cfg_tree_free_instance(&tree); } Test(cfg_tree, test_pipe_init_multi_success) { CfgTree tree; cfg_tree_init_instance (&tree, NULL); create_and_attach_almighty_pipe (&tree, TRUE); create_and_attach_almighty_pipe (&tree, TRUE); create_and_attach_almighty_pipe (&tree, TRUE); cr_assert(cfg_tree_compile (&tree)); cr_assert(cfg_tree_start (&tree), "Starting a tree of all-good nodes works"); cr_assert(cfg_tree_stop (&tree), "Stopping a tree of all-good nodes works"); cfg_tree_free_instance (&tree); } Test(cfg_tree, test_pipe_init_multi_with_bad_node) { AlmightyAlwaysPipe *pipe1, *pipe2, *pipe3; CfgTree tree; cfg_tree_init_instance (&tree, NULL); pipe1 = create_and_attach_almighty_pipe (&tree, TRUE); pipe2 = create_and_attach_almighty_pipe (&tree, FALSE); pipe3 = create_and_attach_almighty_pipe (&tree, TRUE); cr_assert(cfg_tree_compile (&tree)); cr_assert_not(cfg_tree_start (&tree), "Starting a tree of all-good nodes works"); cr_assert(cfg_tree_stop (&tree), "Stopping a tree of all-good nodes works"); cr_assert(pipe1->init_called, "The initializer of the first good pipe is called"); cr_assert(pipe2->init_called, "The initializer of the bad pipe is called"); cr_assert_not(pipe3->init_called, "The initializer of the second good pipe is NOT called"); cr_assert(pipe1->deinit_called, "The deinitializer of the first good pipe is called"); cr_assert_not(pipe2->deinit_called, "The deinitializer of the bad pipe is NOT called"); cr_assert_not(pipe3->deinit_called, "The deinitializer of the second good pipe is NOT called"); cfg_tree_free_instance (&tree); } static void setup(void) { app_startup(); } static void teardown(void) { app_shutdown(); } TestSuite(cfg_tree, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_clone_logmsg.c000066400000000000000000000107721450431004300231450ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/msg_parse_lib.h" #include "logmsg/logmsg.h" #include "serialize.h" #include "apphook.h" #include "gsockaddr.h" #include "logpipe.h" #include "cfg.h" #include "plugin.h" #include #include #include #include MsgFormatOptions parse_options; void assert_new_log_message_attributes(LogMessage *log_message) { assert_log_message_value(log_message, LM_V_HOST, "newhost"); assert_log_message_value(log_message, LM_V_HOST_FROM, "newhost"); assert_log_message_value(log_message, LM_V_MESSAGE, "newmsg"); assert_log_message_value(log_message, LM_V_PROGRAM, "newprogram"); assert_log_message_value(log_message, LM_V_PID, "newpid"); assert_log_message_value(log_message, LM_V_MSGID, "newmsgid"); assert_log_message_value(log_message, LM_V_SOURCE, "newsource"); assert_log_message_value(log_message, log_msg_get_value_handle("newvalue"), "newvalue"); } void set_new_log_message_attributes(LogMessage *log_message) { log_msg_set_value(log_message, LM_V_HOST, "newhost", -1); log_msg_set_value(log_message, LM_V_HOST_FROM, "newhost", -1); log_msg_set_value(log_message, LM_V_MESSAGE, "newmsg", -1); log_msg_set_value(log_message, LM_V_PROGRAM, "newprogram", -1); log_msg_set_value(log_message, LM_V_PID, "newpid", -1); log_msg_set_value(log_message, LM_V_MSGID, "newmsgid", -1); log_msg_set_value(log_message, LM_V_SOURCE, "newsource", -1); log_msg_set_value_by_name(log_message, "newvalue", "newvalue", -1); } void setup(void) { app_startup(); init_parse_options_and_load_syslogformat(&parse_options); } void teardown(void) { deinit_syslogformat_module(); app_shutdown(); } TestSuite(clone_logmsg, .init = setup, .fini = teardown); ParameterizedTestParameters(clone_logmsg, test_cloning_with_log_message) { const gchar *messages[] = { "<7>1 2006-10-29T01:59:59.156+01:00 mymachine.example.com evntslog - ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry...", "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [exampleSDID@0 iut=\"3\"] [eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry...", }; return cr_make_param_array(const gchar *, messages, sizeof(messages) / sizeof(const gchar *)); } ParameterizedTest(const gchar *msg, clone_logmsg, test_cloning_with_log_message) { LogMessage *original_log_message, *log_message, *cloned_log_message; regex_t bad_hostname; GSockAddr *addr = g_sockaddr_inet_new("10.10.10.10", 1010); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; parse_options.flags = LP_SYSLOG_PROTOCOL; parse_options.bad_hostname = &bad_hostname; original_log_message = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); log_msg_set_saddr(original_log_message, addr); log_message = msg_format_parse(&parse_options, (const guchar *) msg, strlen(msg)); log_msg_set_saddr(log_message, addr); log_msg_set_tag_by_name(log_message, "newtag"); path_options.ack_needed = FALSE; cloned_log_message = log_msg_clone_cow(log_message, &path_options); assert_log_messages_equal(cloned_log_message, original_log_message); set_new_log_message_attributes(cloned_log_message); assert_log_messages_equal(log_message, original_log_message); assert_new_log_message_attributes(cloned_log_message); assert_log_message_has_tag(cloned_log_message, "newtag"); g_sockaddr_unref(addr); log_msg_unref(cloned_log_message); log_msg_unref(log_message); log_msg_unref(original_log_message); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_dnscache.c000066400000000000000000000136531450431004300222460ustar00rootroot00000000000000/* * Copyright (c) 2007-2016 Balabit * Copyright (c) 2007-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "dnscache.h" #include "apphook.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include #include #include #include #include #include #include #include static const char *positive_hostname = "hostname"; static const char *negative_hostname = "negative"; static void _fill_dns_cache(DNSCache *cache, gint cache_size) { gint i; for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i); gboolean positive = i < (cache_size / 2); dns_cache_store_dynamic(cache, AF_INET, (void *) &ni, positive ? positive_hostname : negative_hostname, positive); } } static void _fill_benchmark_dns_cache(DNSCache *cache, gint cache_size) { gint i; for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i); dns_cache_store_dynamic(cache, AF_INET, (void *) &ni, positive_hostname, TRUE); } } static void _invalidate_with_sleep(guint seconds) { sleep(seconds); invalidate_cached_time(); } void assert_no_forget(DNSCache *cache, gint cache_size) { gint i; const gchar *hn = NULL; gsize hn_len; gboolean positive; gint positive_limit = cache_size / 2; for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i); hn = NULL; positive = FALSE; cr_assert(dns_cache_lookup(cache, AF_INET, (void *) &ni, &hn, &hn_len, &positive), "hmmm cache forgot the cache entry too early, i=%d, hn=%s\n", i, hn); if (i < positive_limit) { cr_assert(positive && strcmp(hn, "hostname") == 0, "hmm, cached returned an positive match, but cached name invalid, i=%d, hn=%s\n", i, hn); } else { cr_assert(!positive && strcmp(hn, "negative") == 0, "hmm, cache returned a positive match, where a negative match was expected, i=%d, hn=%s\n", i, hn); } } } void assert_forget_negative(DNSCache *cache, gint cache_size) { gint i; const gchar *hn = NULL; gsize hn_len; gboolean positive; gint positive_limit = cache_size / 2; for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i); hn = NULL; positive = FALSE; if (i < positive_limit) { cr_assert(dns_cache_lookup(cache, AF_INET, (void *) &ni, &hn, &hn_len, &positive) || !positive, "hmmm cache forgot positive entries too early, i=%d\n", i); } else { cr_assert_not(dns_cache_lookup(cache, AF_INET, (void *) &ni, &hn, &hn_len, &positive) || positive, "hmmm cache didn't forget negative entries in time, i=%d\n", i); } } } void assert_forget_all(DNSCache *cache, gint cache_size) { gint i; const gchar *hn = NULL; gsize hn_len; gboolean positive; for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i); hn = NULL; positive = FALSE; cr_assert_not(dns_cache_lookup(cache, AF_INET, (void *) &ni, &hn, &hn_len, &positive), "hmmm cache did not forget an expired entry, i=%d\n", i); } } TestSuite(dnscache, .init = app_startup, .fini = app_shutdown); Test(dnscache, test_expiration) { DNSCacheOptions options = { .cache_size = 50000, .expire = 3, .expire_failed = 1, .hosts = NULL }; DNSCache *cache = dns_cache_new(&options); gint cache_size = 10000; _fill_dns_cache(cache, cache_size); assert_no_forget(cache, cache_size); /* negative entries should expire by now, positive ones still present */ _invalidate_with_sleep(2); assert_forget_negative(cache, cache_size); /* everything should be expired by now */ _invalidate_with_sleep(2); assert_forget_all(cache, cache_size); dns_cache_free(cache); } Test(dnscache, test_run_benchmark) { DNSCacheOptions options = { .cache_size = 50000, .expire = 600, .expire_failed = 300, .hosts = NULL }; DNSCache *cache = dns_cache_new(&options); GTimeVal start, end; const gchar *hn; gsize hn_len; gboolean positive; gint i; gint cache_size = 10000; _fill_benchmark_dns_cache(cache, cache_size); g_get_current_time(&start); /* run benchmarks */ for (i = 0; i < cache_size; i++) { guint32 ni = htonl(i % cache_size); hn = NULL; dns_cache_lookup(cache, AF_INET, (void *) &ni, &hn, &hn_len, &positive); } g_get_current_time(&end); printf("DNS cache speed: %12.3f iters/sec\n", i * 1e6 / g_time_val_diff(&end, &start)); dns_cache_free(cache); } /* test case to check the LRU expiration functionality */ Test(dnscache, test_lru_lists) { DNSCacheOptions options = { .cache_size = 10, .expire = 600, .expire_failed = 300, .hosts = NULL }; DNSCache *cache = dns_cache_new(&options); gint cache_size = 100; _fill_dns_cache(cache, cache_size); dns_cache_free(cache); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_dynamic_window.c000066400000000000000000000036121450431004300235030ustar00rootroot00000000000000/* * Copyright (c) 2019 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "dynamic-window.h" Test(dynamic_window, window_stat_reset) { DynamicWindow win; dynamic_window_stat_reset(&win.stat); cr_expect_eq(win.stat.sum, 0); cr_expect_eq(win.stat.n, 0); } Test(dynamic_window, window_stat_reset_when_pool_is_set) { DynamicWindow win; dynamic_window_set_pool(&win, NULL); cr_expect_eq(win.stat.sum, 0); cr_expect_eq(win.stat.n, 0); } Test(dynamic_window, window_stat_avg) { DynamicWindow win; dynamic_window_stat_reset(&win.stat); dynamic_window_stat_update(&win.stat, 12); dynamic_window_stat_update(&win.stat, 4); cr_expect_eq(dynamic_window_stat_get_avg(&win.stat), 8); cr_expect_eq(dynamic_window_stat_get_number_of_samples(&win.stat), 2); cr_expect_eq(dynamic_window_stat_get_sum(&win.stat), 16); cr_expect_eq(dynamic_window_stat_get_avg(&win.stat), dynamic_window_stat_get_sum(&win.stat) / dynamic_window_stat_get_number_of_samples(&win.stat)); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_findcrlf.c000066400000000000000000000135531450431004300222640ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "find-crlf.h" #include #include struct findcrlf_params { gchar *msg; gsize msg_len; gsize eom_ofs; }; ParameterizedTestParameters(findcrlf, test) { static struct findcrlf_params params[] = { { "a\nb\nc\n", 6, 1 }, { "ab\nb\nc\n", 7, 2 }, { "abc\nb\nc\n", 8, 3 }, { "abcd\nb\nc\n", 9, 4 }, { "abcde\nb\nc\n", 10, 5 }, { "abcdef\nb\nc\n", 11, 6 }, { "abcdefg\nb\nc\n", 12, 7 }, { "abcdefgh\nb\nc\n", 13, 8 }, { "abcdefghi\nb\nc\n", 14, 9 }, { "abcdefghij\nb\nc\n", 15, 10 }, { "abcdefghijk\nb\nc\n", 16, 11 }, { "abcdefghijkl\nb\nc\n", 17, 12 }, { "abcdefghijklm\nb\nc\n", 18, 13 }, { "abcdefghijklmn\nb\nc\n", 19, 14 }, { "abcdefghijklmno\nb\nc\n", 20, 15 }, { "abcdefghijklmnop\nb\nc\n", 21, 16 }, { "abcdefghijklmnopq\nb\nc\n", 22, 17 }, { "abcdefghijklmnopqr\nb\nc\n", 23, 18 }, { "abcdefghijklmnopqrs\nb\nc\n", 24, 19 }, { "abcdefghijklmnopqrst\nb\nc\n", 25, 20 }, { "abcdefghijklmnopqrstu\nb\nc\n", 26, 21 }, { "abcdefghijklmnopqrstuv\nb\nc\n", 27, 22 }, { "abcdefghijklmnopqrstuvw\nb\nc\n", 28, 23 }, { "abcdefghijklmnopqrstuvwx\nb\nc\n", 29, 24 }, { "abcdefghijklmnopqrstuvwxy\nb\nc\n", 30, 25 }, { "abcdefghijklmnopqrstuvwxyz\nb\nc\n", 31, 26 }, { "a\0b\0c\0", 6, 1 }, { "ab\0b\0c\0", 7, 2 }, { "abc\0b\0c\0", 8, 3 }, { "abcd\0b\0c\0", 9, 4 }, { "abcde\0b\0c\0", 10, 5 }, { "abcdef\0b\0c\0", 11, 6 }, { "abcdefg\0b\0c\0", 12, 7 }, { "abcdefgh\0b\0c\0", 13, 8 }, { "abcdefghi\0b\0c\0", 14, 9 }, { "abcdefghij\0b\0c\0", 15, 10 }, { "abcdefghijk\0b\0c\0", 16, 11 }, { "abcdefghijkl\0b\0c\0", 17, 12 }, { "abcdefghijklm\0b\0c\0", 18, 13 }, { "abcdefghijklmn\0b\0c\0", 19, 14 }, { "abcdefghijklmno\0b\0c\0", 20, 15 }, { "abcdefghijklmnop\0b\0c\0", 21, 16 }, { "abcdefghijklmnopq\0b\0c\0", 22, 17 }, { "abcdefghijklmnopqr\0b\0c\0", 23, 18 }, { "abcdefghijklmnopqrs\0b\0c\0", 24, 19 }, { "abcdefghijklmnopqrst\0b\0c\0", 25, 20 }, { "abcdefghijklmnopqrstu\0b\0c\0", 26, 21 }, { "abcdefghijklmnopqrstuv\0b\0c\0", 27, 22 }, { "abcdefghijklmnopqrstuvw\0b\0c\0", 28, 23 }, { "abcdefghijklmnopqrstuvwx\0b\0c\0", 29, 24 }, { "abcdefghijklmnopqrstuvwxy\0b\0c\0", 30, 25 }, { "abcdefghijklmnopqrstuvwxyz\0b\0c\0", 31, 26 }, { "a\rb\rc\r", 6, 1 }, { "ab\rb\rc\r", 7, 2 }, { "abc\rb\rc\r", 8, 3 }, { "abcd\rb\rc\r", 9, 4 }, { "abcde\rb\rc\r", 10, 5 }, { "abcdef\rb\rc\r", 11, 6 }, { "abcdefg\rb\rc\r", 12, 7 }, { "abcdefgh\rb\rc\r", 13, 8 }, { "abcdefghi\rb\rc\r", 14, 9 }, { "abcdefghij\rb\rc\r", 15, 10 }, { "abcdefghijk\rb\rc\r", 16, 11 }, { "abcdefghijkl\rb\rc\r", 17, 12 }, { "abcdefghijklm\rb\rc\r", 18, 13 }, { "abcdefghijklmn\rb\rc\r", 19, 14 }, { "abcdefghijklmno\rb\rc\r", 20, 15 }, { "abcdefghijklmnop\rb\rc\r", 21, 16 }, { "abcdefghijklmnopq\rb\rc\r", 22, 17 }, { "abcdefghijklmnopqr\rb\rc\r", 23, 18 }, { "abcdefghijklmnopqrs\rb\rc\r", 24, 19 }, { "abcdefghijklmnopqrst\rb\rc\r", 25, 20 }, { "abcdefghijklmnopqrstu\rb\rc\r", 26, 21 }, { "abcdefghijklmnopqrstuv\rb\rc\r", 27, 22 }, { "abcdefghijklmnopqrstuvw\rb\rc\r", 28, 23 }, { "abcdefghijklmnopqrstuvwx\rb\rc\r", 29, 24 }, { "abcdefghijklmnopqrstuvwxy\rb\rc\r", 30, 25 }, { "abcdefghijklmnopqrstuvwxyz\rb\rc\r", 31, 26 }, { "a", 1, -1 }, { "ab", 2, -1 }, { "abc", 3, -1 }, { "abcd", 4, -1 }, { "abcde", 5, -1 }, { "abcdef", 6, -1 }, { "abcdefg", 7, -1 }, { "abcdefgh", 8, -1 }, { "abcdefghi", 9, -1 }, { "abcdefghij", 10, -1 }, { "abcdefghijk", 11, -1 }, { "abcdefghijkl", 12, -1 }, { "abcdefghijklm", 13, -1 }, { "abcdefghijklmn", 14, -1 }, { "abcdefghijklmno", 15, -1 }, { "abcdefghijklmnop", 16, -1 }, { "abcdefghijklmnopq", 17, -1 }, { "abcdefghijklmnopqr", 18, -1 }, { "abcdefghijklmnopqrs", 19, -1 }, { "abcdefghijklmnopqrst", 20, -1 }, { "abcdefghijklmnopqrstu", 21, -1 }, { "abcdefghijklmnopqrstuv", 22, -1 }, { "abcdefghijklmnopqrstuvw", 23, -1 }, { "abcdefghijklmnopqrstuvwx", 24, -1 }, { "abcdefghijklmnopqrstuvwxy", 25, -1 }, { "abcdefghijklmnopqrstuvwxyz", 26, -1 } }; return cr_make_param_array(struct findcrlf_params, params, sizeof (params) / sizeof(struct findcrlf_params)); } ParameterizedTest(struct findcrlf_params *params, findcrlf, test) { gchar *eom = find_cr_or_lf_or_nul(params->msg, params->msg_len); cr_expect_not(params->eom_ofs == -1 && eom != NULL, "EOM returned is not NULL, which was expected. eom_ofs=%d, eom=%s\n", (gint) params->eom_ofs, eom); if (params->eom_ofs == -1) return; cr_expect_not(eom - params->msg != params->eom_ofs, "EOM is at wrong location. msg=%s, eom_ofs=%d, eom=%s\n", params->msg, (gint) params->eom_ofs, eom); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_generic_number.c000066400000000000000000000063751450431004300234650ustar00rootroot00000000000000/* * Copyright (c) 2022 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "generic-number.h" #include Test(generic_number, test_set_signed_int_retrieves_the_value_specified) { GenericNumber gn; gn_set_int64(&gn, 1); cr_assert_eq(gn_as_int64(&gn), 1); gn_set_int64(&gn, -1); cr_assert_eq(gn_as_int64(&gn), -1); gn_set_int64(&gn, G_MAXINT64); cr_assert_eq(gn_as_int64(&gn), G_MAXINT64); gn_set_int64(&gn, G_MININT64); cr_assert_eq(gn_as_int64(&gn), G_MININT64); } Test(generic_number, test_set_double_retrieves_the_value_specified) { GenericNumber gn; gn_set_double(&gn, 1.0, -1); cr_assert_float_eq(gn_as_double(&gn), 1.0, DBL_EPSILON); gn_set_double(&gn, -1.0, -1); cr_assert_float_eq(gn_as_double(&gn), -1.0, DBL_EPSILON); } Test(generic_number, test_integer_is_converted_to_double) { GenericNumber gn; gn_set_int64(&gn, -5000); cr_assert_float_eq(gn_as_double(&gn), -5000.0, DBL_EPSILON); } Test(generic_number, test_double_is_converted_to_integer_by_rounding) { GenericNumber gn; gn_set_double(&gn, 1.5, -1); cr_assert_eq(gn_as_int64(&gn), 2); gn_set_double(&gn, -1.5, -1); cr_assert_eq(gn_as_int64(&gn), -2); } Test(generic_number, test_double_outside_of_the_int64_range_is_represented_as_extremal_values) { GenericNumber gn; gn_set_double(&gn, ((gdouble) G_MAXINT64) + 1.0, -1); cr_assert_eq(gn_as_int64(&gn), G_MAXINT64); gn_set_double(&gn, ((gdouble) G_MAXINT64) + 1e6, -1); cr_assert_eq(gn_as_int64(&gn), G_MAXINT64); gn_set_double(&gn, ((gdouble) G_MININT64) - 1e6, -1); cr_assert_eq(gn_as_int64(&gn), G_MININT64); gn_set_double(&gn, ((gdouble) G_MININT64) - 1.0, -1); cr_assert_eq(gn_as_int64(&gn), G_MININT64); } Test(generic_number, test_set_nan_becomes_a_nan) { GenericNumber gn; gn_set_nan(&gn); cr_assert(gn_is_nan(&gn)); /* NAN requires _GNU_SOURCE */ gn_set_double(&gn, (gdouble) NAN, -1); cr_assert(gn_is_nan(&gn)); } Test(generic_number, test_nan_operation_is_zero_triggers_an_abort, .signal=SIGABRT) { GenericNumber gn; gn_set_nan(&gn); gn_is_zero(&gn); cr_assert(FALSE, "Should not be reached"); } Test(generic_number, test_nan_operation_compare_triggers_an_abort, .signal=SIGABRT) { GenericNumber gn1, gn2; gn_set_nan(&gn1); gn_set_double(&gn2, 0.0, -1); gn_compare(&gn1, &gn2); cr_assert(FALSE, "Should not be reached"); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_host_resolve.c000066400000000000000000000211561450431004300232070ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* NOTE: this is not run automatically in make check as it relies on DNS, * you have to invoke it manually if your workstation has internet * connectivity. */ #include #include "host-resolve.h" #include "apphook.h" #include "dnscache.h" #include "gsocket.h" #include "hostname.h" #include "cfg.h" #include static HostResolveOptions host_resolve_options; static void assert_sockaddr_to_hostname(GSockAddr *sa, const gchar *expected) { const gchar *result; gsize result_len = 9999; result = resolve_sockaddr_to_hostname(&result_len, sa, &host_resolve_options); g_sockaddr_unref(sa); cr_assert_str_eq(result, expected, "resolved name mismatch"); cr_assert_eq(result_len, strlen(result), "returned length is not true"); } static void assert_ip_to_short_hostname(const gchar *ip, const gchar *expected) { host_resolve_options.use_fqdn = FALSE; assert_sockaddr_to_hostname(g_sockaddr_inet_new(ip, 0), expected); } static void assert_ip_to_fqdn_hostname(const gchar *ip, const gchar *expected) { host_resolve_options.use_fqdn = TRUE; assert_sockaddr_to_hostname(g_sockaddr_inet_new(ip, 0), expected); } #if SYSLOG_NG_ENABLE_IPV6 static void assert_ip6_to_short_hostname(const gchar *ip, const gchar *expected) { host_resolve_options.use_fqdn = FALSE; assert_sockaddr_to_hostname(g_sockaddr_inet6_new(ip, 0), expected); } static void assert_ip6_to_fqdn_hostname(const gchar *ip, const gchar *expected) { host_resolve_options.use_fqdn = TRUE; assert_sockaddr_to_hostname(g_sockaddr_inet6_new(ip, 0), expected); } #else static void assert_ip6_to_short_hostname(const gchar *ip, const gchar *expected) { } static void assert_ip6_to_fqdn_hostname(const gchar *ip, const gchar *expected) { } #endif static void assert_hostname_to_sockaddr(gint family, const gchar *hostname, const gchar *expected_ip) { GSockAddr *sa = NULL; gchar ip[64]; gboolean result; result = resolve_hostname_to_sockaddr(&sa, family, hostname); if (sa) { g_sockaddr_format(sa, ip, sizeof(ip), GSA_ADDRESS_ONLY); g_sockaddr_unref(sa); } cr_assert(result, "unexpected error return"); cr_assert_not_null(sa, "sockaddr can't be NULL for successful returns"); cr_assert_str_eq(ip, expected_ip, "resolved address mismatch"); } static void assert_hostname_to_sockaddr_fails(gint family, const gchar *hostname) { GSockAddr *sa = NULL; gboolean result; result = resolve_hostname_to_sockaddr(&sa, family, hostname); g_sockaddr_unref(sa); cr_assert_null(sa, "returned sockaddr is non-NULL"); cr_assert_not(result, "unexpected success returned"); } static void assert_hostname_to_hostname_len(gsize buflen, const gchar *hostname, const gchar *expected) { const gchar *result; gsize result_len = 9999; result = resolve_hostname_to_hostname(&result_len, hostname, &host_resolve_options); cr_assert_str_eq(result, expected, "hostname to hostname result mismatch"); cr_assert_eq(result_len, strlen(result), "returned length is not true"); } static void assert_hostname_to_hostname(const gchar *hostname, const gchar *expected) { assert_hostname_to_hostname_len(256, hostname, expected); } #define for_all_resolve_cases() \ for (host_resolve_options.use_dns_cache = 0; host_resolve_options.use_dns_cache < 2; host_resolve_options.use_dns_cache++) \ for (host_resolve_options.normalize_hostnames = 0; host_resolve_options.normalize_hostnames < 2; host_resolve_options.normalize_hostnames++) Test(resolve_hostname, test_resolvable_ip_results_in_hostname) { host_resolve_options.use_dns = TRUE; for_all_resolve_cases() { /* a.root-servers.net, will probably not go away as its IP is registered to bind hints file */ assert_ip_to_short_hostname("198.41.0.4", "a"); assert_ip_to_fqdn_hostname("198.41.0.4", "a.root-servers.net"); assert_ip6_to_short_hostname("2001:503:ba3e::2:30", "a"); assert_ip6_to_fqdn_hostname("2001:503:ba3e::2:30", "a.root-servers.net"); } } Test(resolve_hostname, test_unresolvable_ip_results_in_ip) { fprintf(stderr, "The testcase %s takes a lot of time, it is advisable to turn it\n" "off for short iterations and reenable it at the end of the session.\n" "The easiest way to disable it is to comment out its invocation that\n" "looks like HOST_RESOLVE_TESTCASE(test_unresolvable_ip_results_in_ip);\n" "But please, please, please don't commit the disabling of that testcase.\n", __FUNCTION__); host_resolve_options.use_dns = TRUE; for_all_resolve_cases() { /* 198.41.0.251 is on the same network as a.root-servers.net, but is * not resolvable as of now. It is a good candidate for the negative tests * as it responds quite fast. * * NOTE: this might become resolve once in the future, in that case * this testcase will fail. Search for an IP address that has a * responding DNS server but has no A record. */ assert_ip_to_short_hostname("198.41.0.251", "198.41.0.251"); assert_ip_to_fqdn_hostname("198.41.0.251", "198.41.0.251"); assert_ip6_to_short_hostname("2001:503:ba3e::2:31", "2001:503:ba3e::2:31"); assert_ip6_to_fqdn_hostname("2001:503:ba3e::2:31", "2001:503:ba3e::2:31"); } } Test(resolve_hostname, test_sockaddr_without_dns_resolution_results_in_ip) { host_resolve_options.use_dns = FALSE; for_all_resolve_cases() { /* a.root-servers.net, will probably not go away as its IP is registered to bind hints file */ assert_ip_to_short_hostname("198.41.0.4", "198.41.0.4"); assert_ip_to_fqdn_hostname("198.41.0.4", "198.41.0.4"); assert_ip6_to_short_hostname("2001:503:ba3e::2:30", "2001:503:ba3e::2:30"); assert_ip6_to_fqdn_hostname("2001:503:ba3e::2:30", "2001:503:ba3e::2:30"); } } Test(resolve_hostname, test_unix_domain_sockaddr_results_in_the_local_hostname) { const gchar *local_host; host_resolve_options.use_fqdn = TRUE; local_host = get_local_hostname_fqdn(); assert_sockaddr_to_hostname(g_sockaddr_unix_new(NULL), local_host); assert_sockaddr_to_hostname(NULL, local_host); } Test(resolve_hostname, test_resolvable_hostname_results_in_sockaddr) { assert_hostname_to_sockaddr(AF_INET, "a.root-servers.net", "198.41.0.4"); assert_hostname_to_sockaddr(AF_INET, "", "0.0.0.0"); #if SYSLOG_NG_ENABLE_IPV6 assert_hostname_to_sockaddr(AF_INET6, "a.root-servers.net", "2001:503:ba3e::2:30"); assert_hostname_to_sockaddr(AF_INET6, "", "::"); #endif } Test(resolve_hostname, test_unresolvable_hostname_results_in_error) { assert_hostname_to_sockaddr_fails(AF_INET, "foo.bar.baz"); } Test(resolve_hostname, test_short_hostname_is_converted_to_fqdn_if_use_fqdn_is_set) { host_resolve_options.use_fqdn = TRUE; /* force the use of custom domain to make asserts easier. the * non-custom-domain case is tested by test-hostname.c */ hostname_reinit("bardomain"); assert_hostname_to_hostname("foo", "foo.bardomain"); } Test(resolve_hostname, test_fqdn_hostname_is_converted_to_short_if_use_fqdn_is_unset) { host_resolve_options.use_fqdn = FALSE; assert_hostname_to_hostname("foo.bardomain", "foo"); } Test(resolve_hostname, test_hostname_is_normalized_if_normalize_hostnames_is_set) { host_resolve_options.use_fqdn = TRUE; host_resolve_options.normalize_hostnames = TRUE; assert_hostname_to_hostname("Foo.BarDomain", "foo.bardomain"); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); host_resolve_options_defaults(&host_resolve_options); host_resolve_options_init(&host_resolve_options, &configuration->host_resolve_options); hostname_reinit(NULL); } static void teardown(void) { host_resolve_options_destroy(&host_resolve_options); cfg_free(configuration); app_shutdown(); } TestSuite(resolve_hostname, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_hostid.c000066400000000000000000000075411450431004300217670ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2014 Laszlo Budai * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "syslog-ng.h" #include "host-id.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "cfg.h" #include "mainloop.h" #include #include #include static GlobalConfig * _create_cfg(void) { GlobalConfig *cfg = cfg_new_snippet(); return cfg; } static PersistState * _create_persist_state(const gchar *persist_file) { PersistState *state = persist_state_new(persist_file); cr_assert(persist_state_start(state), "Error starting persist state object [%s]", persist_file); return state; } static guint32 _load_hostid_from_persist(const gchar *persist_file) { PersistState *state = _create_persist_state(persist_file); gsize size; guint8 version; PersistEntryHandle handle = persist_state_lookup_entry(state, HOST_ID_PERSIST_KEY, &size, &version); cr_assert_neq(handle, 0, "cannot find hostid in persist file"); HostIdState *host_id_state = persist_state_map_entry(state, handle); guint32 result = host_id_state->host_id; persist_state_unmap_entry(state, handle); persist_state_free(state); return result; } static void _init_mainloop_with_persist_file(const gchar *persist_file) { GlobalConfig *cfg = _create_cfg(); cr_assert(main_loop_initialize_state(cfg, persist_file), "main_loop_initialize_state failed"); cfg_free(cfg); } static void _init_mainloop_with_newly_created_persist_file(const gchar *persist_file) { unlink(persist_file); _init_mainloop_with_persist_file(persist_file); } static void _create_persist_file_with_hostid(const gchar *persist_file, guint32 hostid) { unlink(persist_file); PersistState *state = _create_persist_state(persist_file); PersistEntryHandle handle = persist_state_alloc_entry(state, HOST_ID_PERSIST_KEY, sizeof(HostIdState)); HostIdState *host_id_state = persist_state_map_entry(state, handle); host_id_state->host_id = hostid; persist_state_unmap_entry(state, handle); persist_state_commit(state); persist_state_free(state); } TestSuite(hostid, .init = app_startup, .fini = app_shutdown); #ifndef __hpux Test(hostid, test_if_hostid_generated_when_persist_file_not_exists) { const gchar *persist_file = "test_hostid1.persist"; guint32 hostid; _init_mainloop_with_newly_created_persist_file(persist_file); hostid = _load_hostid_from_persist(persist_file); cr_assert_eq(hostid, host_id_get(), "read hostid(%u) differs from the newly generated hostid(%u)", hostid, host_id_get()); unlink(persist_file); } Test(hostid, test_if_hostid_remain_unchanged_when_persist_file_exists) { const gchar *persist_file = "test_hostid2.persist"; const int hostid = 323; _create_persist_file_with_hostid(persist_file, hostid); _init_mainloop_with_persist_file(persist_file); cr_assert_eq(host_id_get(), hostid, "loaded hostid(%d) differs from expected (%d)", host_id_get(), hostid); unlink(persist_file); } #endif syslog-ng-syslog-ng-4.4.0/lib/tests/test_hostname.c000066400000000000000000000154701450431004300223130ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "hostname.h" #include "apphook.h" #include #include /* * NOTE: on WRAP_GETHOSTNAME below * * If WRAP_GETHOSTNAME is 1, this test will mock the gethostname() call in * order to run on all systems. When gethostname() is mocked, it will * always return an FQDN as a hostname. This in turn means, that the use of * DNS in detecting the FQDN is completely avoided. * * This means, that if WRAP_GETHOSTNAME is set to 1, it will run on all * systems, but some of the production code will not be tested. If it is * set to 0, it'll only run on a host whose name is "bzorp.balabit", which * happens to be my notebook. * * I was thinking of mocking the DNS calls too, but that gets more and more * difficult, so I was left with this macro that I can change whenever I'm * working on the DNS related parts of the hostname.c file. */ #define WRAP_GETHOSTNAME 1 #ifdef WRAP_GETHOSTNAME static int (*__wrap_gethostname)(char *buf, size_t buflen); #define gethostname __wrap_gethostname #include "hostname.c" #undef gethostname static int __fqdn_gethostname(char *buf, size_t buflen) { strncpy(buf, "bzorp.balabit", buflen); return 0; } #else #include "hostname.c" #endif #ifdef WRAP_GETHOSTNAME #define wrap_gethostname() (__wrap_gethostname = __fqdn_gethostname) #else #define wrap_gethostname() #endif /* this is hostname-unix specific and will probably be made conditional once the win32 bits are in */ /* NOTE: we are testing a private function */ static const gchar * _invoke_extract_fqdn_from_hostent(gchar *primary_host, gchar **aliases) { struct hostent hostent; memset(&hostent, 0, sizeof(hostent)); hostent.h_name = primary_host; hostent.h_aliases = aliases; return _extract_fqdn_from_hostent(&hostent); } typedef struct _HostNameList { gchar *domain_override; gchar *host_name; gchar *expected; } HostNameList; ParameterizedTestParameters(test_hostname, test_hostname_fqdn_conversion) { static HostNameList host_name_list[] = { {NULL, "foo.bar", "foo.bar"}, {NULL, "foo", "foo.balabit"}, {NULL, "bzorp", "bzorp.balabit"}, {NULL, "bzorp.balabit", "bzorp.balabit"}, {"bardomain", "bzorp", "bzorp.bardomain"}, {"bardomain", "bzorp.balabit", "bzorp.bardomain"}, {"bardomain", "foo", "foo.bardomain"}, {"bardomain", "foo.bar", "foo.bardomain"} }; return cr_make_param_array(HostNameList, host_name_list, sizeof(host_name_list) / sizeof(host_name_list[0])); } ParameterizedTest(HostNameList *host_name_list, test_hostname, test_hostname_fqdn_conversion) { gchar buf[256]; wrap_gethostname(); hostname_reinit(host_name_list->domain_override); g_strlcpy(buf, host_name_list->host_name, sizeof(buf)); convert_hostname_to_fqdn(buf, sizeof(buf)); cr_assert_str_eq(buf, host_name_list->expected, "hostname values mismatch"); } ParameterizedTestParameters(test_hostname, test_hostname_short_conversion) { static HostNameList host_name_list[] = { {NULL, "foo", "foo"}, {NULL, "foo.bar", "foo"}, {NULL, "foo.bardomain", "foo"}, {"bardomain", "foo", "foo"}, {"bardomain", "foo.bar", "foo"}, {"bardomain", "foo.bardomain", "foo"}, }; return cr_make_param_array(HostNameList, host_name_list, sizeof(host_name_list) / sizeof(host_name_list[0])); } ParameterizedTest(HostNameList *host_name_list, test_hostname, test_hostname_short_conversion) { gchar buf[256]; wrap_gethostname(); hostname_reinit(host_name_list->domain_override); g_strlcpy(buf, host_name_list->host_name, sizeof(buf)); convert_hostname_to_short_hostname(buf, sizeof(buf)); cr_assert_str_eq(buf, host_name_list->expected, "hostname values mismatch"); } ParameterizedTestParameters(test_hostname, test_hostname_fqdn) { static HostNameList host_name_list[] = { {NULL, NULL, "bzorp.balabit"}, {"bardomain", NULL, "bzorp.bardomain"}, }; return cr_make_param_array(HostNameList, host_name_list, sizeof(host_name_list) / sizeof(host_name_list[0])); } ParameterizedTest(HostNameList *host_name_list, test_hostname, test_hostname_fqdn) { const gchar *host; wrap_gethostname(); hostname_reinit(host_name_list->domain_override); host = get_local_hostname_fqdn(); cr_assert_str_eq(host, host_name_list->expected, "hostname values mismatch"); } ParameterizedTestParameters(test_hostname, test_hostname_short) { static HostNameList host_name_list[] = { {NULL, NULL, "bzorp"}, {"bardomain", NULL, "bzorp"}, }; return cr_make_param_array(HostNameList, host_name_list, sizeof(host_name_list) / sizeof(host_name_list[0])); } ParameterizedTest(HostNameList *host_name_list, test_hostname, test_hostname_short) { const gchar *host; wrap_gethostname(); hostname_reinit(host_name_list->domain_override); host = get_local_hostname_short(); cr_assert_str_eq(host, host_name_list->expected, "hostname values mismatch"); } Test(test_hostname, test_extract_fqdn_from_hostent_uses_primary_name_if_it_is_an_fqdn) { gchar *aliases[] = { "bzorp", "bzorp.lan", NULL }; cr_assert_str_eq(_invoke_extract_fqdn_from_hostent("bzorp.balabit", aliases), "bzorp.balabit", "_extract_fqdn didn't return the requested hostname"); } Test(test_hostname, test_extract_fqdn_from_hostent_finds_the_first_fqdn_in_aliases_if_primary_is_short) { gchar *aliases[] = { "bzorp", "bzorp.lan", NULL }; cr_assert_str_eq(_invoke_extract_fqdn_from_hostent("bzorp", aliases), "bzorp.lan", "_extract_fqdn didn't return the requested hostname"); } Test(test_hostname, test_extract_fqdn_from_hostent_returns_NULL_when_no_fqdn_is_found) { gchar *aliases[] = { "bzorp", "foobar", NULL }; cr_assert_null(_invoke_extract_fqdn_from_hostent("bzorp", aliases), "_extract_fqdn returned non-NULL when we expected failure"); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_lexer.c000066400000000000000000000417511450431004300216150ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-cfg-parser.h" #include "libtest/grab-logging.h" #include "cfg-lexer.h" #include "cfg-grammar.h" #include "apphook.h" #define TESTDATA_DIR TOP_SRCDIR "/lib/tests/testdata-lexer" CfgParserMock *parser = NULL; static void _input(const gchar *input) { cfg_parser_mock_input(parser, input); } static void _next_token(void) { cfg_parser_mock_next_token(parser); } static CFG_STYPE * _current_token(void) { return parser->yylval; } static CFG_LTYPE * _current_lloc(void) { return parser->yylloc; } #define assert_token_type(expected) \ cr_assert_eq(_current_token()->type, expected, "Unexpected token type %d != %d", _current_token()->type, expected); #define assert_parser_string(expected) \ _next_token(); \ assert_token_type(LL_STRING); \ cr_assert_str_eq(_current_token()->cptr, expected, "Unexpected string value parsed >>>%s<<< != >>>%s<<<", _current_token()->cptr, expected); #define assert_parser_token(expected) \ _next_token(); \ assert_token_type(expected); #define assert_parser_block(expected) \ _next_token(); \ assert_token_type(LL_BLOCK); \ cr_assert_str_eq(_current_token()->cptr, expected, "Unexpected block value parsed >>>%s<<< != >>>%s<<<", _current_token()->cptr, expected); #define assert_parser_error() \ _next_token(); \ assert_token_type(LL_ERROR); #define assert_parser_pragma() \ _next_token(); \ assert_token_type(LL_PRAGMA); #define assert_parser_number(expected) \ _next_token(); \ assert_token_type(LL_NUMBER); \ cr_assert_eq(_current_token()->num, expected, "Unexpected number parsed %" G_GINT64_FORMAT " != %" G_GINT64_FORMAT, (gint64) _current_token()->num, (gint64) expected); #define assert_parser_float(expected) \ _next_token(); \ assert_token_type(LL_FLOAT); \ cr_assert_float_eq(_current_token()->fnum, expected, 1e-7, "Unexpected float parsed %lf != %lf", _current_token()->fnum, expected); #define assert_parser_identifier(expected) \ _next_token(); \ assert_token_type(LL_IDENTIFIER); \ cr_assert_str_eq(_current_token()->cptr, expected, "Unexpected identifier parsed >>>%s<<< != >>>%s<<<", _current_token()->cptr, expected); #define assert_parser_char(expected) \ _next_token(); \ cr_assert_eq(_current_token()->type, expected, "Unexpected character parsed %c != %c", _current_token()->type, expected); #define assert_location(line, column) \ cr_assert_eq(_current_lloc()->first_line, line, \ "The line number in the location information " \ "does not match the expected value, %d != %d", _current_lloc()->first_line, line); \ cr_assert_eq(_current_lloc()->first_column, column, \ "The column number in the location information " \ "does not match the expected value, %d != %d", _current_lloc()->first_column, column); #define assert_location_range(_first_line, _first_column, _last_line, _last_column) \ assert_location(_first_line, _first_column); \ cr_assert_eq(_current_lloc()->last_line, _last_line, \ "The last_line number in the location information " \ "does not match the expected value, %d != %d", _current_lloc()->last_line, _last_line); \ cr_assert_eq(_current_lloc()->last_column, _last_column, \ "The last_column number in the location information " \ "does not match the expected value, %d != %d", _current_lloc()->last_column, _last_column); static gchar * _format_location_tag_message(void) { EVTCONTEXT *ctx; EVTREC *rec; char *msg; ctx = evt_ctx_init("test", EVT_FAC_USER); rec = evt_rec_init(ctx, EVT_PRI_WARNING, "test"); evt_rec_add_tag(rec, cfg_lexer_format_location_tag(parser->lexer, _current_lloc())); msg = evt_format(rec); evt_rec_free(rec); evt_ctx_free(ctx); return msg; } #define assert_location_tag(expected) \ ({ \ char *msg = _format_location_tag_message(); \ const gchar *tag_repr; \ tag_repr = strstr(msg, "; "); \ tag_repr = tag_repr ? tag_repr + 2 : NULL; \ cr_assert_str_eq(tag_repr, expected, "Formatted location tag does not match %s <> %s", tag_repr, expected); \ free(msg); \ \ }) Test(lexer, test_string) { _input("\"test\""); assert_parser_string("test"); _input("\"test\\x0a\""); assert_parser_string("test\n"); _input("\"test\\o011\""); assert_parser_string("test\t"); _input("\"test\\n\\r\\a\\t\\v\\c\""); assert_parser_string("test\n\r\a\t\vc"); } Test(lexer, test_unquoted_string) { _input("test"); assert_parser_identifier("test"); _input("..test"); assert_parser_token(LL_DOTDOT); _input(".test"); assert_parser_token('.'); assert_parser_identifier("test"); } Test(lexer, test_qstring) { _input("'test'"); assert_parser_string("test"); _input("'\"test\\n\\r\"'"); assert_parser_string("\"test\\n\\r\""); } Test(lexer, block_token_is_taken_literally_between_a_pair_of_enclosing_characters) { _input(" { hello }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" hello "); assert_location_range(1, 1, 1, 11); _input(" { hello\nworld }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" hello\nworld "); assert_location_range(1, 1, 2, 8); _input(" { hello\\\nworld }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" hello\\\nworld "); assert_location_range(1, 1, 2, 8); _input(" { 'hello' }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" 'hello' "); assert_location_range(1, 1, 1, 13); _input(" { 'hello\nworld' }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" 'hello\nworld' "); assert_location_range(1, 1, 2, 9); _input(" { 'hello\\\nworld' }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" 'hello\\\nworld' "); assert_location_range(1, 1, 2, 9); _input(" { \"hello\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello\" "); assert_location_range(1, 1, 1, 13); _input(" { \"hello\nworld\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello\nworld\" "); assert_location_range(1, 1, 2, 9); _input(" { \"hello\\\nworld\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello\\\nworld\" "); assert_location_range(1, 1, 2, 9); _input(" { \"hello \\a\\n\\r\\t\\v\\x40\\o100 world\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello \\a\\n\\r\\t\\v\\x40\\o100 world\" "); assert_location_range(1, 1, 1, 39); _input(" { \"hello \\\" world\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello \\\" world\" "); assert_location_range(1, 1, 1, 22); } Test(lexer, block_new_lines_in_text_leading_to_the_opening_bracket_are_tracked_properly) { _input("\n\n\n{ \"hello\\\nworld\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello\\\nworld\" "); assert_location_range(4, 1, 5, 9); } Test(lexer, block_closing_brackets_in_embedded_strings_or_comments_dont_close_the_block) { _input(" { 'hello}' }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" 'hello}' "); _input(" { \"hello}\" }"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block(" \"hello}\" "); _input(" {\nfoo# hello}\nbar\n}"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block("\nfoo# hello}\nbar\n"); } Test(lexer, block_imbalanced_closing_dont_close_the_block) { _input(" {foo {hello} bar}"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block("foo {hello} bar"); } Test(lexer, block_complex_input) { _input("\t \n{'hello world' \"test value\" {other_block} other\text}"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_block("'hello world' \"test value\" {other_block} other\text"); } Test(lexer, block_input_without_opening_character_is_reported_as_an_error) { start_grabbing_messages(); _input("this is a block that does not start with an opening brace"); cfg_lexer_start_block_state(parser->lexer, "{}"); assert_parser_error(); assert_grabbed_log_contains("Expected opening bracket as block boundary"); stop_grabbing_messages(); } Test(lexer, block_empty_input_in_parens_is_processed_as_a_NULL_pointer) { _input("()"); cfg_lexer_start_block_state(parser->lexer, "()"); _next_token(); assert_token_type(LL_BLOCK); cr_assert(_current_token()->cptr == NULL, "%p", _current_token()->cptr); } Test(lexer, block_empty_string_in_parens_input_is_processed_as_an_empty_string) { _input("('')"); cfg_lexer_start_block_state(parser->lexer, "()"); assert_parser_block(""); _input("(\"\")"); cfg_lexer_start_block_state(parser->lexer, "()"); assert_parser_block(""); } Test(lexer, at_version_stores_config_version_in_parsed_version_in_hex_form) { parser->lexer->ignore_pragma = FALSE; start_grabbing_messages(); cfg_set_version_without_validation(configuration, 0); _input("@version: 3.1\n\ bar\n"); assert_parser_identifier("bar"); cr_assert_eq(configuration->user_version, 0x0301, "@version parsing mismatch, value %04x expected %04x", configuration->user_version, 0x0301); assert_grabbed_log_contains("Configuration file format is too old"); reset_grabbed_messages(); cfg_set_version_without_validation(configuration, 0); _input("@version: 3.5\n\ baz\n"); assert_parser_identifier("baz"); cr_assert_eq(configuration->user_version, 0x0305, "@version parsing mismatch, value %04x expected %04x", configuration->user_version, 0x0305); assert_grabbed_log_contains("Configuration file format is too old"); } Test(lexer, current_version) { parser->lexer->ignore_pragma = FALSE; cfg_set_version_without_validation(configuration, 0); _input("@version: current\n\ foo\n"); assert_parser_identifier("foo"); cr_assert_eq(configuration->user_version, VERSION_VALUE_CURRENT, "@version parsing mismatch, value %04x expected %04x", configuration->user_version, VERSION_VALUE_CURRENT); } Test(lexer, test_lexer_others) { _input("#This is a full line comment\nfoobar"); assert_parser_identifier("foobar"); _input("():;{}|"); assert_parser_char('('); assert_parser_char(')'); assert_parser_char(':'); assert_parser_char(';'); assert_parser_char('{'); assert_parser_char('}'); assert_parser_char('|'); _input("4.2 12 0x50 011 +12 -12 -4.2 +4.2"); assert_parser_float(4.2); assert_parser_number(12); assert_parser_number(80 /*0x50*/); assert_parser_number(9 /*011 */); assert_parser_number(12); assert_parser_number(-12); assert_parser_float(-4.2); assert_parser_float(4.2); _input("test_value"); assert_parser_identifier("test_value"); _input(".."); assert_parser_token(LL_DOTDOT); } Test(lexer, test_location_tracking) { _input("test another\nfoo\nbar\n"); _next_token(); assert_location(1, 1); _next_token(); assert_location(1, 6); _next_token(); assert_location(2, 1); _next_token(); assert_location(3, 1); assert_location_tag("location='#test-buffer:3:1'"); } Test(lexer, test_multiline_string_literals) { _input("\"test another\\\nfoo\"\nbar"); assert_parser_string("test anotherfoo"); assert_location(1, 1); assert_parser_identifier("bar"); assert_location(3, 1); _input("\"test another\nfoo\"\nbar"); assert_parser_string("test another\nfoo"); assert_location(1, 1); assert_parser_identifier("bar"); assert_location(3, 1); } Test(lexer, test_multiline_qstring_literals) { _input("'test another\nfoo'\nbar"); assert_parser_string("test another\nfoo"); assert_location(1, 1); assert_parser_identifier("bar"); assert_location(3, 1); _input("'test another\\\nfoo'\nbar"); assert_parser_string("test another\\\nfoo"); assert_location(1, 1); assert_parser_identifier("bar"); assert_location(3, 1); } Test(lexer, defined_variables_are_substituted_when_enclosed_in_backticks) { parser->lexer->ignore_pragma = FALSE; _input("@define var1 value1\n\ @define var2 value2\n\ value0"); assert_parser_identifier("value0"); /* we need to supply the variables to be substituted in a separate * _input() call as their resolution happens when 1) read from a file, 2) * included */ _input("`var1`\n\ `var2`\n"); assert_parser_identifier("value1"); assert_parser_identifier("value2"); } Test(lexer, include_file_expands_the_content_of_that_file_in_the_token_stream) { parser->lexer->ignore_pragma = FALSE; _input("@include \"" TESTDATA_DIR "/include-test/foo.conf\"\n"); assert_parser_identifier("foo"); } Test(lexer, include_wildcard_files_expands_the_content_of_all_files_in_the_token_stream_in_alphabetical_order) { parser->lexer->ignore_pragma = FALSE; _input("@include \"" TESTDATA_DIR "/include-test/*.conf\"\n"); assert_parser_identifier("bar"); assert_parser_identifier("baz"); assert_parser_identifier("foo"); } Test(lexer, include_directory_expands_the_content_of_all_files_in_that_directory_in_alphabetical_ordre) { parser->lexer->ignore_pragma = FALSE; _input("@include \"" TESTDATA_DIR "/include-test\"\n"); assert_parser_identifier("bar"); assert_parser_identifier("baz"); assert_parser_identifier("foo"); } Test(lexer, include_finds_files_in_include_path) { parser->lexer->ignore_pragma = FALSE; _input("@define include-path \"" TESTDATA_DIR "/include-test\"\n\ @include foo.conf\n"); assert_parser_identifier("foo"); } Test(lexer, include_finds_wildcards_files_in_include_path) { parser->lexer->ignore_pragma = FALSE; _input("@define include-path \"" TESTDATA_DIR "/include-test\"\n\ @include \"*.conf\"\n"); assert_parser_identifier("bar"); assert_parser_identifier("baz"); assert_parser_identifier("foo"); } static gboolean _fake_generator_generate(CfgBlockGenerator *self, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference) { g_string_append(result, "fake_generator_content"); return TRUE; } CfgBlockGenerator * fake_generator_new(void) { CfgBlockGenerator *self = g_new0(CfgBlockGenerator, 1); cfg_block_generator_init_instance(self, LL_CONTEXT_ROOT, "fake-generator"); self->generate = _fake_generator_generate; return self; } Test(lexer, generator_plugins_are_expanded) { CfgLexer *lexer = parser->lexer; CfgBlockGenerator *gen = fake_generator_new(); cfg_lexer_register_generator_plugin(&configuration->plugin_context, gen); parser->lexer->ignore_pragma = FALSE; cfg_lexer_push_context(parser->lexer, main_parser.context, main_parser.keywords, main_parser.name); _input("fake-generator();\n"); assert_parser_identifier("fake_generator_content"); cfg_lexer_pop_context(lexer); } Test(lexer, context_name_lookup) { for (int i=LL_CONTEXT_MAX-1; i >= 1; --i) { cr_assert_eq(i, cfg_lexer_lookup_context_type_by_name(cfg_lexer_lookup_context_name_by_type(i))); } } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); parser = cfg_parser_mock_new(); } static void teardown(void) { cfg_parser_mock_free(parser); cfg_free(configuration); configuration = NULL; app_shutdown(); } TestSuite(lexer, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_lexer_block.c000066400000000000000000000061041450431004300227600ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "cfg-lexer.h" #include "cfg-args.h" #include "cfg-block.h" #include "cfg-lexer.h" #include "cfg.h" CFG_LTYPE yyloc; GString *result; static void setup(void) { result = g_string_sized_new(100); yyloc.name = "config-file"; yyloc.first_line = yyloc.first_column = 1; yyloc.last_line = yyloc.last_column = 1; configuration = cfg_new_snippet(); msg_init(TRUE); } static void teardown(void) { msg_deinit(); cfg_free(configuration); g_string_free(result, TRUE); } TestSuite(test_block, .init = setup, .fini = teardown); Test(test_block, mandatory_arguments) { CfgArgs *arg_defs = cfg_args_new(); cfg_args_set(arg_defs, "mandatory-param", NULL); CfgBlockGenerator *generator = cfg_block_new(cfg_lexer_lookup_context_type_by_name("block"), "block_with_mandatory_options", "`mandatory_param`", arg_defs, &yyloc); CfgArgs *args = cfg_args_new(); cr_assert_not(generator->generate(generator, configuration, args, result, ""), "mandatory parameter missing"); cfg_args_set(args, "mandatory-param", "value"); cr_assert(generator->generate(generator, configuration, args, result, "")); cr_assert_str_eq(result->str, "value"); cfg_args_unref(args); cfg_block_generator_unref(generator); } Test(test_block, varargs) { CfgArgs *arg_defs = cfg_args_new(); CfgBlockGenerator *generator = cfg_block_new(cfg_lexer_lookup_context_type_by_name("block"), "block_to_test_varargs", "`varargs_param`", arg_defs, &yyloc); CfgArgs *args = cfg_args_new(); cfg_args_set(args, "varargs_param", "value"); cr_assert_not(generator->generate(generator, configuration, args, result, ""), "varargs not set yet"); cfg_args_accept_varargs(arg_defs); cr_assert(generator->generate(generator, configuration, args, result, "")); cr_assert_str_eq(result->str, "value"); cfg_args_unref(args); cfg_block_generator_unref(generator); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_logqueue.c000066400000000000000000000345241450431004300223240ustar00rootroot00000000000000/* * Copyright (c) 2008-2016 Balabit * Copyright (c) 2019 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/msg_parse_lib.h" #include "libtest/queue_utils_lib.h" #include "logqueue.h" #include "logqueue-fifo.h" #include "logpipe.h" #include "apphook.h" #include "plugin.h" #include "mainloop.h" #include "mainloop-io-worker.h" #include "timeutils/misc.h" #include "stats/stats-cluster-single.h" #include #include #include #include #include #define OVERFLOW_SIZE 10000 #define FEEDERS 1 #define MESSAGES_PER_FEEDER 30000 #define MESSAGES_SUM (FEEDERS * MESSAGES_PER_FEEDER) #define TEST_RUNS 10 GMutex tlock; glong sum_time; static gpointer _threaded_feed(gpointer args) { LogQueue *q = args; gint i; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; LogMessage *msg, *tmpl; GTimeVal start, end; glong diff; /* emulate main loop for LogQueue */ main_loop_worker_thread_start(MLW_ASYNC_WORKER); tmpl = log_msg_new_empty(); g_get_current_time(&start); for (i = 0; i < MESSAGES_PER_FEEDER; i++) { msg = log_msg_clone_cow(tmpl, &path_options); log_msg_add_ack(msg, &path_options); msg->ack_func = test_ack; log_queue_push_tail(q, msg, &path_options); if ((i & 0xFF) == 0) main_loop_worker_invoke_batch_callbacks(); } main_loop_worker_invoke_batch_callbacks(); g_get_current_time(&end); diff = g_time_val_diff(&end, &start); g_mutex_lock(&tlock); sum_time += diff; g_mutex_unlock(&tlock); log_msg_unref(tmpl); main_loop_worker_thread_stop(); return NULL; } static gpointer _threaded_consume(gpointer st) { LogQueue *q = (LogQueue *) st; LogMessage *msg; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; gint msg_count = 0; /* just to make sure time is properly cached */ while (msg_count < MESSAGES_SUM) { gint slept = 0; msg = NULL; while((msg = log_queue_pop_head(q, &path_options)) == NULL) { struct timespec ns; /* sleep 1 msec */ ns.tv_sec = 0; ns.tv_nsec = 1000000; nanosleep(&ns, NULL); slept++; if (slept > 10000) { /* slept for more than 10 seconds */ fprintf(stderr, "The wait for messages took too much time, msg_count=%d\n", msg_count); return GUINT_TO_POINTER(1); } } log_msg_ack(msg, &path_options, AT_PROCESSED); log_msg_unref(msg); msg_count++; } return NULL; } static gpointer _output_thread(gpointer args) { main_loop_worker_thread_start(MLW_THREADED_OUTPUT_WORKER); struct timespec ns; /* sleep 1 msec */ ns.tv_sec = 0; ns.tv_nsec = 1000000; nanosleep(&ns, NULL); main_loop_worker_thread_stop(); return NULL; } void setup(void) { app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); configuration = cfg_new_snippet(); configuration->stats_options.level = 1; cr_assert(cfg_init(configuration), "cfg_init failed!"); } void teardown(void) { cfg_free(configuration); app_shutdown(); } TestSuite(logqueue, .init = setup, .fini = teardown); Test(logqueue, test_zero_diskbuf_and_normal_acks) { LogQueue *q; gint i; StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); q = log_queue_fifo_new(OVERFLOW_SIZE, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); cr_assert_eq(atomic_gssize_racy_get(&q->metrics.shared.queued_messages->value), 0); fed_messages = 0; acked_messages = 0; feed_some_messages(q, 1); cr_assert_eq(stats_counter_get(q->metrics.shared.queued_messages), 1); cr_assert_neq(stats_counter_get(q->metrics.shared.memory_usage), 0); gint size_when_single_msg = stats_counter_get(q->metrics.shared.memory_usage); for (i = 0; i < 10; i++) feed_some_messages(q, 10); cr_assert_eq(stats_counter_get(q->metrics.shared.queued_messages), 101); cr_assert_eq(stats_counter_get(q->metrics.shared.memory_usage), 101*size_when_single_msg); send_some_messages(q, fed_messages, TRUE); cr_assert_eq(fed_messages, acked_messages, "did not receive enough acknowledgements: fed_messages=%d, acked_messages=%d", fed_messages, acked_messages); log_queue_unref(q); } Test(logqueue, test_zero_diskbuf_alternating_send_acks) { LogQueue *q; gint i; q = log_queue_fifo_new(OVERFLOW_SIZE, NULL, STATS_LEVEL0, NULL, NULL); fed_messages = 0; acked_messages = 0; for (i = 0; i < 10; i++) { feed_some_messages(q, 10); send_some_messages(q, 10, TRUE); } cr_assert_eq(fed_messages, acked_messages, "did not receive enough acknowledgements: fed_messages=%d, acked_messages=%d", fed_messages, acked_messages); log_queue_unref(q); } Test(logqueue, test_with_threads) { LogQueue *q; GThread *thread_feed[FEEDERS], *thread_consume; GThread *other_threads[FEEDERS]; gint i, j; main_loop_worker_allocate_thread_space(FEEDERS * 2); main_loop_worker_finalize_thread_space(); for (i = 0; i < TEST_RUNS; i++) { fprintf(stderr, "starting testrun: %d\n", i); q = log_queue_fifo_new(MESSAGES_SUM, NULL, STATS_LEVEL0, NULL, NULL); for (j = 0; j < FEEDERS; j++) { fprintf(stderr, "starting feed thread %d\n", j); other_threads[j] = g_thread_new(NULL, _output_thread, NULL); thread_feed[j] = g_thread_new(NULL, _threaded_feed, q); } thread_consume = g_thread_new(NULL, _threaded_consume, q); for (j = 0; j < FEEDERS; j++) { fprintf(stderr, "waiting for feed thread %d\n", j); g_thread_join(thread_feed[j]); g_thread_join(other_threads[j]); } g_thread_join(thread_consume); log_queue_unref(q); } fprintf(stderr, "Feed speed: %.2lf\n", (double) TEST_RUNS * MESSAGES_SUM * 1000000 / sum_time); } Test(logqueue, log_queue_fifo_rewind_all_and_memory_usage) { StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); LogQueue *q = log_queue_fifo_new(OVERFLOW_SIZE, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); feed_some_messages(q, 1); gint size_when_single_msg = stats_counter_get(q->metrics.shared.memory_usage); feed_some_messages(q, 9); cr_assert_eq(stats_counter_get(q->metrics.shared.memory_usage), 10*size_when_single_msg); send_some_messages(q, 10, FALSE); cr_assert_eq(stats_counter_get(q->metrics.shared.memory_usage), 0); log_queue_rewind_backlog_all(q); cr_assert_eq(stats_counter_get(q->metrics.shared.memory_usage), 10*size_when_single_msg); log_queue_unref(q); } Test(logqueue, log_queue_fifo_should_drop_only_non_flow_controlled_messages, .description = "Flow-controlled messages should never be dropped") { LogPathOptions flow_controlled_path = LOG_PATH_OPTIONS_INIT; flow_controlled_path.flow_control_requested = TRUE; LogPathOptions non_flow_controlled_path = LOG_PATH_OPTIONS_INIT; non_flow_controlled_path.flow_control_requested = FALSE; gint fifo_size = 5; StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); LogQueue *q = log_queue_fifo_new(fifo_size, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); fed_messages = 0; acked_messages = 0; feed_empty_messages(q, &flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, 1); feed_empty_messages(q, &flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, 2); feed_empty_messages(q, &flow_controlled_path, fifo_size); cr_assert_eq(stats_counter_get(q->metrics.shared.dropped_messages), 3); gint queued_messages = stats_counter_get(q->metrics.shared.queued_messages); send_some_messages(q, queued_messages, TRUE); cr_assert_eq(fed_messages, acked_messages, "did not receive enough acknowledgements: fed_messages=%d, acked_messages=%d", fed_messages, acked_messages); log_queue_unref(q); } static gpointer _flow_control_feed_thread(gpointer args) { LogQueue *q = args; gint fifo_size = 5; LogPathOptions flow_controlled_path = LOG_PATH_OPTIONS_INIT; flow_controlled_path.flow_control_requested = TRUE; LogPathOptions non_flow_controlled_path = LOG_PATH_OPTIONS_INIT; non_flow_controlled_path.flow_control_requested = FALSE; main_loop_worker_thread_start(MLW_ASYNC_WORKER); fed_messages = 0; acked_messages = 0; feed_empty_messages(q, &flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, 1); feed_empty_messages(q, &flow_controlled_path, fifo_size); feed_empty_messages(q, &non_flow_controlled_path, 2); feed_empty_messages(q, &flow_controlled_path, fifo_size); main_loop_worker_invoke_batch_callbacks(); main_loop_worker_thread_stop(); return NULL; } Test(logqueue, log_queue_fifo_should_drop_only_non_flow_controlled_messages_threaded, .description = "Flow-controlled messages should never be dropped (using input queues with threads") { gint fifo_size = 5; main_loop_worker_allocate_thread_space(1); main_loop_worker_finalize_thread_space(); StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); LogQueue *q = log_queue_fifo_new(fifo_size, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); GThread *thread = g_thread_new(NULL, _flow_control_feed_thread, q); g_thread_join(thread); cr_assert_eq(stats_counter_get(q->metrics.shared.dropped_messages), 3); gint queued_messages = stats_counter_get(q->metrics.shared.queued_messages); send_some_messages(q, queued_messages, TRUE); cr_assert_eq(fed_messages, acked_messages, "did not receive enough acknowledgements: fed_messages=%d, acked_messages=%d", fed_messages, acked_messages); log_queue_unref(q); } Test(logqueue, log_queue_fifo_multiple_queues) { const gint fifo_size = 1; LogPathOptions options = LOG_PATH_OPTIONS_INIT; StatsClusterKeyBuilder *driver_sck_builder = stats_cluster_key_builder_new(); StatsClusterKeyBuilder *queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(queue_sck_builder, stats_cluster_label("log_queue_fifo_multiple_queues", "1")); LogQueue *queue_1 = log_queue_fifo_new(fifo_size, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(queue_sck_builder, stats_cluster_label("log_queue_fifo_multiple_queues", "2")); LogQueue *queue_2 = log_queue_fifo_new(fifo_size, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); cr_assert_eq(stats_counter_get(queue_1->metrics.shared.queued_messages), 0); cr_assert_eq(stats_counter_get(queue_1->metrics.owned.queued_messages), 0); cr_assert_eq(stats_counter_get(queue_2->metrics.shared.queued_messages), 0); cr_assert_eq(stats_counter_get(queue_2->metrics.owned.queued_messages), 0); log_queue_push_tail(queue_1, log_msg_new_empty(), &options); cr_assert_eq(stats_counter_get(queue_1->metrics.shared.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_1->metrics.owned.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_2->metrics.shared.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_2->metrics.owned.queued_messages), 0); log_queue_push_tail(queue_2, log_msg_new_empty(), &options); cr_assert_eq(stats_counter_get(queue_1->metrics.shared.queued_messages), 2); cr_assert_eq(stats_counter_get(queue_1->metrics.owned.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_2->metrics.shared.queued_messages), 2); cr_assert_eq(stats_counter_get(queue_2->metrics.owned.queued_messages), 1); log_queue_unref(queue_1); cr_assert_eq(stats_counter_get(queue_2->metrics.shared.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_2->metrics.owned.queued_messages), 1); stats_cluster_key_builder_free(queue_sck_builder); queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(queue_sck_builder, stats_cluster_label("queue", "1")); queue_1 = log_queue_fifo_new(fifo_size, NULL, STATS_LEVEL0, driver_sck_builder, queue_sck_builder); cr_assert_eq(stats_counter_get(queue_1->metrics.shared.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_1->metrics.owned.queued_messages), 0); cr_assert_eq(stats_counter_get(queue_2->metrics.shared.queued_messages), 1); cr_assert_eq(stats_counter_get(queue_2->metrics.owned.queued_messages), 1); log_queue_unref(queue_2); cr_assert_eq(stats_counter_get(queue_1->metrics.shared.queued_messages), 0); cr_assert_eq(stats_counter_get(queue_1->metrics.owned.queued_messages), 0); log_queue_unref(queue_1); stats_cluster_key_builder_free(driver_sck_builder); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_logscheduler.c000066400000000000000000000060541450431004300231530ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "logscheduler.h" #include "apphook.h" typedef struct TestPipe { LogPipe super; GMutex lock; GQueue *messages; gsize messages_count; } TestPipe; static void test_pipe_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { TestPipe *self = (TestPipe *) s; g_mutex_lock(&self->lock); g_queue_push_tail(self->messages, msg); self->messages_count++; g_mutex_unlock(&self->lock); } static void test_pipe_free(LogPipe *s) { TestPipe *self = (TestPipe *) s; g_queue_free_full(self->messages, (GDestroyNotify) log_msg_unref); g_mutex_clear(&self->lock); log_pipe_free_method(s); } TestPipe * test_pipe_new(GlobalConfig *cfg) { TestPipe *self = g_new0(TestPipe, 1); log_pipe_init_instance(&self->super, cfg); self->super.queue = test_pipe_queue; self->super.free_fn = test_pipe_free; self->messages = g_queue_new(); g_mutex_init(&self->lock); return self; } TestPipe * _construct_test_pipe(void) { TestPipe *pipe = test_pipe_new(configuration); cr_assert(log_pipe_init(&pipe->super)); return pipe; } void _destroy_test_pipe(TestPipe *pipe) { log_pipe_deinit(&pipe->super); log_pipe_unref(&pipe->super); } Test(logscheduler, test_log_scheduler_can_be_constructed) { LogSchedulerOptions options; TestPipe *test_pipe = _construct_test_pipe(); LogScheduler *s; log_scheduler_options_defaults(&options); log_scheduler_options_init(&options, configuration); s = log_scheduler_new(&options, &test_pipe->super); LogMessage *msg = create_sample_message(); LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; log_scheduler_push(s, msg, &path_options); msg = create_sample_message(); log_scheduler_push(s, msg, &path_options); cr_assert(test_pipe->messages_count == 2); log_scheduler_free(s); _destroy_test_pipe(test_pipe); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); cr_assert(cfg_init(configuration)); } static void teardown(void) { cfg_free(configuration); } TestSuite(logscheduler, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_logsource.c000066400000000000000000000345641450431004300225040ustar00rootroot00000000000000/* * Copyright (c) 2019 One Identity * Copyright (c) 2019 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "logsource.h" #include "logmsg/logmsg.h" #include "logpipe.h" #include "cfg.h" #include "apphook.h" #include "dynamic-window-pool.h" #include #include #define TEST_SOURCE_GROUP "test_source_group" #define TEST_STATS_ID "test_stats_id" GlobalConfig *cfg; LogSourceOptions source_options; void setup(void) { cfg = cfg_new_snippet(); log_source_options_defaults(&source_options); app_startup(); } void teardown(void) { app_shutdown(); log_source_options_destroy(&source_options); cfg_free(cfg); } typedef struct TestSource { LogSource super; gsize wakeup_count; } TestSource; void test_source_wakeup(LogSource *s) { TestSource *source = (TestSource *) s; source->wakeup_count++; } LogSource * test_source_init(LogSourceOptions *options) { TestSource *source = g_new0(TestSource, 1); log_source_init_instance(&source->super, cfg); source->super.wakeup = test_source_wakeup; log_source_options_init(options, cfg, TEST_SOURCE_GROUP); log_source_set_options(&source->super, options, TEST_STATS_ID, NULL, TRUE, NULL); cr_assert(log_pipe_init(&source->super.super)); return &source->super; } void test_source_destroy(LogSource *source) { log_pipe_deinit(&source->super); log_pipe_unref(&source->super); } typedef struct TestPipe { LogPipe super; GQueue *messages; gsize messages_count; } TestPipe; static void test_pipe_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { TestPipe *pipe = (TestPipe *) s; g_queue_push_tail(pipe->messages, msg); pipe->messages_count++; } TestPipe * test_pipe_init(void) { TestPipe *pipe = g_new0(TestPipe, 1); log_pipe_init_instance(&pipe->super, cfg); pipe->super.queue = test_pipe_queue; pipe->messages = g_queue_new(); cr_assert(log_pipe_init(&pipe->super)); return pipe; } void test_pipe_ack_messages(TestPipe *pipe, gsize ack_count) { for (gsize i = 0; i < ack_count; ++i) { LogMessage *msg = g_queue_pop_head(pipe->messages); cr_assert(msg); pipe->messages_count--; LogPathOptions path_options = { .ack_needed = TRUE }; log_msg_drop(msg, &path_options, AT_PROCESSED); } } void test_pipe_destroy(TestPipe *pipe) { log_pipe_deinit(&pipe->super); g_queue_free(pipe->messages); log_pipe_unref(&pipe->super); } const gchar * resolve_sockaddr_to_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options) { static const gchar *test_hostname = "resolved-test-host"; *result_len = strlen(test_hostname); return test_hostname; } typedef struct _MangleHostnameParams { gboolean keep_hostname; gboolean chain_hostnames; const gchar *input_host; const gchar *expected_hostname; guint32 msg_flags; } MangleHostnameParams; ParameterizedTestParameters(log_source, test_mangle_hostname) { static MangleHostnameParams test_params[] = { { .keep_hostname = TRUE, .chain_hostnames = FALSE, "msg-test-host", "msg-test-host" }, { .keep_hostname = TRUE, .chain_hostnames = FALSE, NULL, "resolved-test-host" }, { .keep_hostname = TRUE, .chain_hostnames = FALSE, "", "resolved-test-host" }, { .keep_hostname = TRUE, .chain_hostnames = TRUE, "msg-test-host", "msg-test-host" }, { .keep_hostname = FALSE, .chain_hostnames = TRUE, NULL, "resolved-test-host/resolved-test-host" }, { .keep_hostname = FALSE, .chain_hostnames = TRUE, "", "resolved-test-host/resolved-test-host" }, { .keep_hostname = FALSE, .chain_hostnames = FALSE, "msg-test-host", "resolved-test-host" }, { .keep_hostname = FALSE, .chain_hostnames = TRUE, "msg-test-host", "msg-test-host/resolved-test-host" }, { .keep_hostname = FALSE, .chain_hostnames = TRUE, "msg-test-host", TEST_SOURCE_GROUP "@resolved-test-host", .msg_flags = LF_LOCAL }, }; return cr_make_param_array(MangleHostnameParams, test_params, G_N_ELEMENTS(test_params)); } ParameterizedTest(MangleHostnameParams *test_params, log_source, test_mangle_hostname) { source_options.keep_hostname = test_params->keep_hostname; source_options.chain_hostnames = test_params->chain_hostnames; LogSource *source = test_source_init(&source_options); LogMessage *msg = log_msg_new_empty(); if (test_params->input_host) log_msg_set_value(msg, LM_V_HOST, test_params->input_host, -1); msg->flags |= test_params->msg_flags; log_source_mangle_hostname(source, msg); const gchar *actual_hostname = log_msg_get_value(msg, LM_V_HOST, NULL); cr_assert_str_eq(actual_hostname, test_params->expected_hostname); log_msg_unref(msg); test_source_destroy(source); } Test(log_source, test_chain_hostname_truncates_long_chained_hostnames) { source_options.chain_hostnames = TRUE; LogSource *source = test_source_init(&source_options); LogMessage *msg = log_msg_new_empty(); const gsize long_hostname_size = 512; gchar long_hostname[long_hostname_size]; memset(long_hostname, 'Z', long_hostname_size); log_msg_set_value(msg, LM_V_HOST, long_hostname, long_hostname_size); log_source_mangle_hostname(source, msg); const gchar *actual_hostname = log_msg_get_value(msg, LM_V_HOST, NULL); gsize expected_hostname_len = 255; cr_assert_eq(strlen(actual_hostname), expected_hostname_len); cr_assert_arr_eq(actual_hostname, long_hostname, expected_hostname_len); log_msg_unref(msg); test_source_destroy(source); } Test(log_source, test_host_and_program_override) { source_options.host_override = g_strdup("test-host-override"); source_options.program_override = g_strdup("test-program-override"); LogSource *source = test_source_init(&source_options); LogMessage *msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_HOST, "hostname-to-override", -1); log_msg_set_value(msg, LM_V_PROGRAM, "program-to-override", -1); log_msg_ref(msg); log_source_post(source, msg); const gchar *actual_hostname = log_msg_get_value(msg, LM_V_HOST, NULL); cr_expect_str_eq(actual_hostname, source_options.host_override); const gchar *actual_program = log_msg_get_value(msg, LM_V_PROGRAM, NULL); cr_expect_str_eq(actual_program, source_options.program_override); log_msg_unref(msg); test_source_destroy(source); } Test(log_source, test_source_tags) { GList *tags = NULL; tags = g_list_prepend(tags, g_strdup("tag1")); tags = g_list_prepend(tags, g_strdup("tag2")); log_source_options_set_tags(&source_options, tags); LogSource *source = test_source_init(&source_options); LogMessage *msg = log_msg_new_empty(); log_msg_ref(msg); log_source_post(source, msg); cr_expect(log_msg_is_tag_by_name(msg, "tag1")); cr_expect(log_msg_is_tag_by_name(msg, "tag2")); cr_expect(log_msg_is_tag_by_name(msg, ".source." TEST_SOURCE_GROUP)); log_msg_unref(msg); test_source_destroy(source); } static void _post_messages(LogSource *source, gsize messages_to_send) { for (gsize i = 0; i < messages_to_send; ++i) { LogMessage *msg = log_msg_new_empty(); log_source_post(source, msg); } } Test(log_source, test_suspend) { source_options.init_window_size = 3; LogSource *source = test_source_init(&source_options); TestPipe *next_pipe = test_pipe_init(); log_pipe_append(&source->super, &next_pipe->super); cr_assert_eq(log_source_get_init_window_size(source), 3); cr_assert(log_source_free_to_send(source)); _post_messages(source, 1); cr_assert(log_source_free_to_send(source)); _post_messages(source, 2); cr_assert_not(log_source_free_to_send(source)); test_pipe_ack_messages(next_pipe, 2); cr_assert(log_source_free_to_send(source)); test_pipe_ack_messages(next_pipe, 1); cr_assert(log_source_free_to_send(source)); test_pipe_destroy(next_pipe); test_source_destroy(source); } Test(log_source, test_wakeup) { source_options.init_window_size = 3; LogSource *source = test_source_init(&source_options); TestPipe *next_pipe = test_pipe_init(); log_pipe_append(&source->super, &next_pipe->super); _post_messages(source, 3); cr_expect_not(log_source_free_to_send(source)); test_pipe_ack_messages(next_pipe, 1); cr_assert_eq(((TestSource *) source)->wakeup_count, 1); _post_messages(source, 1); cr_expect_not(log_source_free_to_send(source)); test_pipe_ack_messages(next_pipe, 3); cr_assert_eq(((TestSource *) source)->wakeup_count, 2); test_pipe_destroy(next_pipe); test_source_destroy(source); } Test(log_source, test_forced_suspend_and_wakeup) { LogSource *source = test_source_init(&source_options); cr_assert(log_source_free_to_send(source)); log_source_flow_control_suspend(source); cr_assert_not(log_source_free_to_send(source)); log_source_flow_control_adjust_when_suspended(source, 1); cr_assert_not(log_source_free_to_send(source)); cr_assert_eq(((TestSource *) source)->wakeup_count, 0); log_source_flow_control_adjust(source, 1); cr_assert(log_source_free_to_send(source)); cr_assert_eq(((TestSource *) source)->wakeup_count, 1); test_source_destroy(source); } static gboolean test_mangle_callback_forbidden(GlobalConfig *config, LogMessage *msg, gpointer user_data) { return strstr(log_msg_get_value(msg, LM_V_MESSAGE, NULL), "forbidden") == NULL; } static gboolean test_mangle_callback_tag(GlobalConfig *config, LogMessage *msg, gpointer user_data) { log_msg_set_tag_by_name(msg, "tagged"); return TRUE; } static void expect_forbidden_message_dropped(LogSource *source) { LogMessage *msg = log_msg_new_internal(LOG_INFO | LOG_SYSLOG, "This is a forbidden message"); log_msg_ref(msg); log_source_post(source, msg); cr_expect_not(log_msg_is_tag_by_name(msg, "tagged"), "Message should not be tagged, the message should have been dropped in test_mangle_callback_forbidden"); log_msg_unref(msg); } static void expect_regular_message_forwarded(LogSource *source) { LogMessage *msg = log_msg_new_internal(LOG_INFO | LOG_SYSLOG, "Message"); log_msg_ref(msg); log_source_post(source, msg); cr_expect(log_msg_is_tag_by_name(msg, "tagged")); log_msg_unref(msg); } Test(log_source, test_mangle_callback) { register_source_mangle_callback(cfg, test_mangle_callback_forbidden); register_source_mangle_callback(cfg, test_mangle_callback_tag); LogSource *source = test_source_init(&source_options); TestPipe *next_pipe = test_pipe_init(); log_pipe_append(&source->super, &next_pipe->super); expect_forbidden_message_dropped(source); cr_assert_eq(next_pipe->messages_count, 0); expect_regular_message_forwarded(source); cr_assert_eq(next_pipe->messages_count, 1); test_pipe_ack_messages(next_pipe, 1); test_pipe_destroy(next_pipe); test_source_destroy(source); } static DynamicWindowPool * test_dynamic_window_pool_init(gsize pool_size) { DynamicWindowPool *pool = dynamic_window_pool_new(pool_size); pool->balanced_window = pool_size; dynamic_window_pool_init(pool); return pool; } Test(log_source, test_dynamic_window_is_disabled_by_default) { LogSource *source = test_source_init(&source_options); cr_assert_not(log_source_is_dynamic_window_enabled(source)); test_source_destroy(source); } Test(log_source, test_dynamic_window) { source_options.init_window_size = 0; LogSource *source = test_source_init(&source_options); log_source_set_name(source, "test-source-name"); cr_assert_not(log_source_free_to_send(source)); const gsize pool_size = 1000; DynamicWindowPool *pool = test_dynamic_window_pool_init(pool_size); log_source_enable_dynamic_window(source, pool); cr_assert(log_source_is_dynamic_window_enabled(source)); /* currently unused */ log_source_dynamic_window_update_statistics(source); pool->balanced_window = 200; log_source_dynamic_window_realloc(source); cr_assert(log_source_free_to_send(source), "Source should not be suspended as it should own free dynamic window slots"); cr_assert_eq(pool->free_window, pool->pool_size - pool->balanced_window); dynamic_window_pool_unref(pool); test_source_destroy(source); } static void _try_to_reclaim_all_dynamic_window_slots(LogSource *source, DynamicWindowPool *pool) { pool->balanced_window = 0; log_source_dynamic_window_realloc(source); } Test(log_source, test_dynamic_window_reclaim) { source_options.init_window_size = 1; LogSource *source = test_source_init(&source_options); TestPipe *next_pipe = test_pipe_init(); log_pipe_append(&source->super, &next_pipe->super); const gsize pool_size = 10; DynamicWindowPool *pool = test_dynamic_window_pool_init(pool_size); log_source_enable_dynamic_window(source, pool); log_source_dynamic_window_realloc(source); const gsize num_of_pending_messages = pool->pool_size + source_options.init_window_size; _post_messages(source, num_of_pending_messages); cr_assert_not(log_source_free_to_send(source), "Source should be suspended, its window is filled with pending messages"); _try_to_reclaim_all_dynamic_window_slots(source, pool); cr_assert_not(log_source_free_to_send(source)); cr_assert_eq(pool->free_window, 0, "Incorrect free pool size; window should not be released, the source has pending messages"); test_pipe_ack_messages(next_pipe, num_of_pending_messages); _try_to_reclaim_all_dynamic_window_slots(source, pool); cr_assert(log_source_free_to_send(source), "The initial static window should be available"); cr_assert_eq(pool->free_window, pool->pool_size, "Incorrect free pool size; window should be reclaimed"); dynamic_window_pool_unref(pool); test_pipe_destroy(next_pipe); test_source_destroy(source); } TestSuite(log_source, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_logwriter.c000066400000000000000000000232111450431004300225030ustar00rootroot00000000000000/* * Copyright (c) 2009-2016 Balabit * Copyright (c) 2009-2014 Viktor Juhasz * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "logwriter.h" #include "logmsg/logmsg.h" #include "template/templates.h" #include "apphook.h" #include "cfg.h" #include "plugin.h" #include "logqueue-fifo.h" #include "timeutils/misc.h" #include "msg-format.h" #include #include #include #include #include MsgFormatOptions parse_options; const gchar *MSG_SYSLOG_STR = "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 iut=\"3\" " "eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry..."; const gchar *EXPECTED_MSG_SYSLOG_STR = "<132>1 2006-10-29T01:59:59+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" " "eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry...\n"; const gchar *EXPECTED_MSG_SYSLOG_STR_T = "<132>1 2006-10-29T01:59:59+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" " "eventID=\"1011\"][examplePriority@0 class=\"high\"] ID47 BOMAn application event log entry...\n"; const gchar *EXPECTED_MSG_SYSLOG_STR_T_TRUNCATE = "<132>1 2006-10-29T01:59:59+01:00 mymachine evntslog 3535 ID47"; const gchar *EXPECTED_MSG_SYSLOG_TO_BSD_STR = "<132>Oct 29 01:59:59 mymachine evntslog[3535]: BOMAn application event log entry...\n"; const gchar *EXPECTED_MSG_SYSLOG_TO_FILE_STR = "Oct 29 01:59:59 mymachine evntslog[3535]: BOMAn application event log entry...\n"; const gchar *MSG_SYSLOG_EMPTY_STR = "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 " "iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"]"; const gchar *EXPECTED_MSG_SYSLOG_EMPTY_STR = "<132>1 2006-10-29T01:59:59+01:00 mymachine evntslog 3535 ID47 " "[exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \n"; const gchar *EXPECTED_MSG_SYSLOG_EMPTY_STR_T = "<132>1 2006-10-29T01:59:59+01:00 mymachine evntslog 3535 ID47 " "[exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] ID47\n"; const gchar *MSG_BSD_STR = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép"; const gchar *EXPECTED_MSG_BSD_STR = "Feb 11 10:34:56 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép\n"; const gchar *EXPECTED_MSG_BSD_STR_TRUNCATE = "Feb 11 10:34:56 bzorp syslog-ng[23323]:"; const gchar *EXPECTED_MSG_BSD_STR_T = "155 23323 árvíztűrőtükörfúrógép"; const gchar *EXPECTED_MSG_BSD_STR_T_TRUNCATE = "155 23323 árvíztűrő"; const gchar *EXPECTED_MSG_BSD_TO_SYSLOG_STR = "<155>1 2006-02-11T10:34:56+01:00 bzorp syslog-ng 23323 - - árvíztűrőtükörfúrógép\n"; const gchar *EXPECTED_MSG_BSD_TO_PROTO_STR = "<155>Feb 11 10:34:56 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép\n"; const gchar *EXPECTED_MSG_BSD_TO_PROTO_STR_TRUNCATE = "<155>Feb 11 10:34:56 bz"; const gchar *MSG_ZERO_PRI = "<0>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép"; const gchar *EXPECTED_MSG_ZERO_PRI_STR = "<0>Feb 11 10:34:56 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép\n"; const gchar *EXPECTED_MSG_ZERO_PRI_STR_T = "0"; const gchar *MSG_BSD_EMPTY_STR = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:"; const gchar *EXPECTED_MSG_BSD_EMPTY_STR = "<155>Feb 11 10:34:56 bzorp syslog-ng[23323]:\n"; const gchar *EXPECTED_MSG_BSD_EMPTY_STR_T = "23323"; typedef struct _LogWriterTestCase { const gchar *msg; const gboolean is_rfc5424; const gchar *template; const guint writer_flags; gint truncate_size; const gchar *expected_value; } LogWriterTestCase; LogMessage * init_msg(const gchar *msg_string, gboolean use_syslog_protocol) { LogMessage *msg; if (use_syslog_protocol) parse_options.flags |= LP_SYSLOG_PROTOCOL; else parse_options.flags &= ~LP_SYSLOG_PROTOCOL; msg = msg_format_parse(&parse_options, (const guchar *) msg_string, strlen(msg_string)); log_msg_set_value_by_name(msg, "APP.VALUE", "value", 5); log_msg_set_match(msg, 0, "whole-match", 11); log_msg_set_match(msg, 1, "first-match", 11); /* fix some externally or automatically defined values */ log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", 9); msg->timestamps[LM_TS_RECVD].ut_sec = 1139684315; msg->timestamps[LM_TS_RECVD].ut_usec = 639000; msg->timestamps[LM_TS_RECVD].ut_gmtoff = get_local_timezone_ofs(1139684315); return msg; } void _tear_down(LogWriter *writer, LogMessage *msg, LogQueue *queue, GString *result_msg, LogWriterOptions *writer_options) { cr_expect(log_pipe_deinit((LogPipe *)writer)); log_pipe_unref((LogPipe *) writer); log_msg_unref(msg); log_queue_unref(queue); g_string_free(result_msg, TRUE); log_writer_options_destroy(writer_options); } void _assert_logwriter_output(LogWriterTestCase c) { LogTemplate *templ = NULL; LogWriter *writer = NULL; GString *result_msg = g_string_sized_new(128); GError *error = NULL; LogMessage *msg = NULL; LogWriterOptions opt = {0}; LogQueue *queue; TimeZoneInfo *tzinfo = time_zone_info_new(NULL); log_writer_options_defaults(&opt); opt.template_options.time_zone_info[LTZ_SEND]=tzinfo; log_writer_options_init(&opt, configuration, LWO_NO_MULTI_LINE | LWO_NO_STATS); if (c.truncate_size > 0) opt.truncate_size = c.truncate_size; if (c.template) { templ = log_template_new(configuration, "dummy"); cr_assert(log_template_compile(templ, c.template, &error)); opt.template = templ; } msg = init_msg(c.msg, c.is_rfc5424); queue = log_queue_fifo_new(1000, NULL, STATS_LEVEL0, NULL, NULL); writer = log_writer_new(c.writer_flags, configuration); log_writer_set_options(writer, NULL, &opt, NULL, NULL); log_writer_set_queue(writer, queue); cr_assert(log_pipe_init((LogPipe *)writer), "LogWriter initialization failed"); log_writer_format_log(writer, msg, result_msg); cr_assert_str_eq(result_msg->str, c.expected_value, "Expected: %s, actual: %s (truncate_size:%d)", c.expected_value, result_msg->str, c.truncate_size); _tear_down(writer, msg, queue, result_msg, &opt); } Test(logwriter, test_logwriter) { configuration = cfg_new_snippet(); LogWriterTestCase test_cases[] = { {MSG_SYSLOG_STR, TRUE, NULL, LW_SYSLOG_PROTOCOL, 0, EXPECTED_MSG_SYSLOG_STR}, {MSG_SYSLOG_STR, TRUE, "$MSGID $MSG", LW_SYSLOG_PROTOCOL, 0, EXPECTED_MSG_SYSLOG_STR_T}, {MSG_SYSLOG_STR, TRUE, "$MSGID $MSG", LW_SYSLOG_PROTOCOL, strlen(EXPECTED_MSG_SYSLOG_STR_T_TRUNCATE), EXPECTED_MSG_SYSLOG_STR_T_TRUNCATE}, // test that truncate doesn't apply on smaller messages {MSG_SYSLOG_STR, TRUE, "$MSGID $MSG", LW_SYSLOG_PROTOCOL, strlen(EXPECTED_MSG_SYSLOG_STR_T), EXPECTED_MSG_SYSLOG_STR_T}, {MSG_SYSLOG_EMPTY_STR, TRUE, NULL, LW_SYSLOG_PROTOCOL, 0, EXPECTED_MSG_SYSLOG_EMPTY_STR}, {MSG_SYSLOG_EMPTY_STR, TRUE, "$MSGID", LW_SYSLOG_PROTOCOL, 0, EXPECTED_MSG_SYSLOG_EMPTY_STR_T}, {MSG_SYSLOG_STR, TRUE, NULL, LW_FORMAT_PROTO, 0, EXPECTED_MSG_SYSLOG_TO_BSD_STR}, {MSG_SYSLOG_STR, TRUE, NULL, LW_FORMAT_FILE, 0, EXPECTED_MSG_SYSLOG_TO_FILE_STR}, {MSG_BSD_STR, FALSE, NULL, LW_FORMAT_FILE, 0, EXPECTED_MSG_BSD_STR}, {MSG_BSD_STR, FALSE, NULL, LW_FORMAT_FILE, strlen(EXPECTED_MSG_BSD_STR_TRUNCATE), EXPECTED_MSG_BSD_STR_TRUNCATE}, {MSG_BSD_STR, FALSE, NULL, LW_FORMAT_FILE, strlen(EXPECTED_MSG_BSD_STR), EXPECTED_MSG_BSD_STR}, {MSG_BSD_STR, FALSE, "$PRI $PID $MSG", LW_FORMAT_FILE, 0, EXPECTED_MSG_BSD_STR_T}, {MSG_BSD_STR, FALSE, "$PRI $PID $MSG", LW_FORMAT_FILE, strlen(EXPECTED_MSG_BSD_STR_T_TRUNCATE), EXPECTED_MSG_BSD_STR_T_TRUNCATE}, {MSG_BSD_STR, FALSE, NULL, LW_FORMAT_PROTO, 0, EXPECTED_MSG_BSD_TO_PROTO_STR}, {MSG_BSD_STR, FALSE, NULL, LW_FORMAT_PROTO, strlen(EXPECTED_MSG_BSD_TO_PROTO_STR_TRUNCATE), EXPECTED_MSG_BSD_TO_PROTO_STR_TRUNCATE}, {MSG_BSD_STR, FALSE, NULL, LW_SYSLOG_PROTOCOL, 0, EXPECTED_MSG_BSD_TO_SYSLOG_STR}, {MSG_BSD_EMPTY_STR, FALSE, NULL, LW_FORMAT_PROTO, 0, EXPECTED_MSG_BSD_EMPTY_STR}, {MSG_BSD_EMPTY_STR, FALSE, "$PID", LW_FORMAT_PROTO, 0, EXPECTED_MSG_BSD_EMPTY_STR_T}, {MSG_ZERO_PRI, FALSE, NULL, LW_FORMAT_PROTO, 0, EXPECTED_MSG_ZERO_PRI_STR}, {MSG_ZERO_PRI, FALSE, "$PRI", LW_FORMAT_PROTO, 0, EXPECTED_MSG_ZERO_PRI_STR_T}, }; gint i, nr_of_cases; app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); cfg_load_module(configuration, "syslogformat"); msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); nr_of_cases = sizeof(test_cases) / sizeof(test_cases[0]); for (i = 0; i < nr_of_cases; i++) _assert_logwriter_output(test_cases[i]); msg_format_options_destroy(&parse_options); app_shutdown(); iv_deinit(); cfg_free(configuration); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_matcher.c000066400000000000000000000514531450431004300221210ustar00rootroot00000000000000/* * Copyright (c) 2008-2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/msg_parse_lib.h" #include "libtest/cr_template.h" #include "logmatcher.h" #include "apphook.h" #include "plugin.h" #include "cfg.h" #include "scratch-buffers.h" #include #include static LogMessage * _create_log_message(const gchar *log) { LogMessage *msg; gchar buf[1024]; NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ"); gssize msglen; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, log, -1); /* NOTE: we test how our matchers cope with non-zero terminated values. We don't change message_len, only the value */ g_snprintf(buf, sizeof(buf), "%sAAAAAAAAAAAA", log_msg_get_value(msg, LM_V_MESSAGE, &msglen)); log_msg_set_value_by_name(msg, "MESSAGE2", buf, -1); /* add a non-zero terminated indirect value which contains the whole message */ log_msg_set_value_indirect(msg, nonasciiz, log_msg_get_value_handle("MESSAGE2"), 0, msglen); return msg; } static LogMatcher * _construct_matcher(gint matcher_flags, LogMatcher *(*construct)(const LogMatcherOptions *options)) { LogMatcherOptions matcher_options; log_matcher_options_defaults(&matcher_options); matcher_options.flags = matcher_flags; return construct(&matcher_options); } void testcase_match(const gchar *log, const gchar *pattern, gboolean expected_result, LogMatcher *m) { LogMessage *msg; gboolean result; NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ"); gssize msglen; const gchar *value; msg = _create_log_message(log); log_matcher_compile(m, pattern, NULL); value = log_msg_get_value(msg, nonasciiz, &msglen); result = log_matcher_match(m, msg, nonasciiz, value, msglen); cr_assert_eq(result, expected_result, "pattern=%s, result=%d, expected=%d\n", pattern, result, expected_result); log_matcher_unref(m); log_msg_unref(msg); } void testcase_replace(const gchar *log, const gchar *re, gchar *replacement, const gchar *expected_result, LogMatcher *m) { LogMessage *msg; LogTemplate *r; gchar *result; gssize length; gssize msglen; NVHandle nonasciiz = log_msg_get_value_handle("NON-ASCIIZ"); const gchar *value; msg = _create_log_message(log); log_matcher_compile(m, re, NULL); r = log_template_new(configuration, NULL); cr_assert(log_template_compile(r, replacement, NULL)); NVTable *nv_table = nv_table_ref(msg->payload); value = log_msg_get_value(msg, nonasciiz, &msglen); result = log_matcher_replace(m, msg, nonasciiz, value, msglen, r, &length); value = log_msg_get_value(msg, nonasciiz, &msglen); nv_table_unref(nv_table); cr_assert_arr_eq((result ? result : value), expected_result, (result ? length : msglen), "pattern=%s, result=%.*s, expected=%s\n", re, (int) length, (result ? result : value), expected_result); g_free(result); log_template_unref(r); log_matcher_unref(m); log_msg_unref(msg); } void setup(void) { app_startup(); configuration = cfg_new_snippet(); } void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); cfg_free(configuration); } TestSuite(matcher, .init = setup, .fini = teardown); Test(matcher, pcre_regexp, .description = "PCRE regexp") { testcase_replace("árvíztűrőtükörfúrógép", "árvíz", "favíz", "favíztűrőtükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("árvíztűrőtükörfúrógép", "^tűrő", "faró", "árvíztűrőtükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("árvíztűrőtükörfúrógép", "tűrő", "", "árvíztükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("wikiwiki", "wi", "", "kiki", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("wikiwiki", "wi", "kuku", "kukukikukuki", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); } Test(matcher, back_ref) { testcase_replace("wikiwiki", "(wiki)\\1", "", "", _construct_matcher(LMF_STORE_MATCHES, log_matcher_pcre_re_new)); } Test(matcher, empty_global, .description = "empty match with global flag") { testcase_replace("aa bb", "c*", "#", "#a#a# #b#b#", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa bb", "a*", "#", "## #b#b#", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa bb", "c*", "#", "#a#a# #b#b#", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa bb", "a*", "?", "?? ?b?b?", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa", "aa|b*", "@", "@@", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa", "aa|b*", "@", "@", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("aa", "b*|aa", "@", "@@@", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("aa", "b*|aa", "@", "@aa", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("wikiwiki", "wi", "", "kiki", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); testcase_replace("wikiwiki", "wi", "kuku", "kukukikukuki", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); } Test(matcher, disable_jit) { testcase_replace("árvíztűrőtükörfúrógép", "árvíz", "favíz", "favíztűrőtükörfúrógép", _construct_matcher(LMF_DISABLE_JIT, log_matcher_pcre_re_new)); } Test(matcher, string_match) { testcase_replace("árvíztűrőtükörfúrógép", "árvíz", "favíz", "favíztűrőtükörfúrógép", _construct_matcher(LMF_PREFIX, log_matcher_string_new)); testcase_replace("árvíztűrőtükörfúrógép", "tűrő", "faró", "árvízfarótükörfúrógép", _construct_matcher(LMF_SUBSTRING, log_matcher_string_new)); testcase_replace("árvíztűrőtükörfúrógép", "tűrő", "", "árvíztükörfúrógép", _construct_matcher(LMF_SUBSTRING, log_matcher_string_new)); testcase_replace("árvíztűrőtükörfúrógép", "árvíztűrőtükörfúrógép", "almafa", "almafa", _construct_matcher(0, log_matcher_string_new)); testcase_replace("", "valami-amivel-nem-szabadna-matchelni", "almafa", "", _construct_matcher(0, log_matcher_string_new)); testcase_match("val", "valami-amivel-nem-szabadna-matchelni", FALSE, _construct_matcher(0, log_matcher_string_new)); testcase_match("", "valami-amivel-nem-szabadna-matchelni", FALSE, _construct_matcher(0, log_matcher_string_new)); testcase_match("", "valami-amivel-nem-szabadna-matchelni", 0, _construct_matcher(LMF_PREFIX, log_matcher_string_new)); testcase_match("", "valami-amivel-nem-szabadna-matchelni", 0, _construct_matcher(LMF_SUBSTRING, log_matcher_string_new)); testcase_match("match", "match", TRUE, _construct_matcher(0, log_matcher_string_new)); testcase_match("match", "ma", TRUE, _construct_matcher(LMF_PREFIX, log_matcher_string_new)); testcase_match("match", "tch", TRUE, _construct_matcher(LMF_SUBSTRING, log_matcher_string_new)); testcase_replace("abcdef", "ABCDEF", "qwerty", "qwerty", _construct_matcher(LMF_PREFIX | LMF_ICASE, log_matcher_string_new)); testcase_replace("abcdef", "BCD", "qwerty", "aqwertyef", _construct_matcher(LMF_SUBSTRING | LMF_ICASE, log_matcher_string_new)); } Test(matcher, glob_match) { testcase_match("árvíztűrőtükörfúrógép", "árvíz*", TRUE, _construct_matcher(0, log_matcher_glob_new)); testcase_match("árvíztűrőtükörfúrógép", "*fúrógép", TRUE, _construct_matcher(0, log_matcher_glob_new)); testcase_match("árvíztűrőtükörfúrógép", "*fúró*", TRUE, _construct_matcher(0, log_matcher_glob_new)); testcase_match("árvíztűrőtükörfúrógép", "tükör", FALSE, _construct_matcher(0, log_matcher_glob_new)); testcase_match("árvíztűrőtükörfúrógép", "viziló", FALSE, _construct_matcher(0, log_matcher_glob_new)); } Test(matcher, iso88592_never, .description = "match in iso-8859-2 never matches") { testcase_match("\xe1rv\xedzt\xfbr\xf5t\xfck\xf6rf\xfar\xf3g\xe9p", "\xe1rv\xed*", FALSE, _construct_matcher(0, log_matcher_glob_new)); } Test(matcher, replace) { testcase_replace("árvíztűrőtükörfúrógép", "árvíz", "favíz", "favíztűrőtükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("árvíztűrőtükörfúrógép", "^tűrő", "faró", "árvíztűrőtükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("árvíztűrőtükörfúrógép", "tűrő", "", "árvíztükörfúrógép", _construct_matcher(0, log_matcher_pcre_re_new)); testcase_replace("wikiwiki", "(wiki)\\1", "", "", _construct_matcher(0, log_matcher_pcre_re_new)); /* back ref with perl style $1 */ testcase_replace("wikiwiki", "(wiki).+", "#$1#", "#wiki#", _construct_matcher(0, log_matcher_pcre_re_new)); } Test(matcher, pcre812_incompatibility, .description = "tests a pcre 8.12 incompatibility") { testcase_replace("wikiwiki", "([[:digit:]]{1,3}\\.){3}[[:digit:]]{1,3}", "foo", "wikiwiki", _construct_matcher(LMF_GLOBAL, log_matcher_pcre_re_new)); } Test(matcher, test_matcher_sets_num_matches_upon_successful_matching) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; const gchar *msg_payload = "kiwi-wiki"; msg = _create_log_message(msg_payload); cr_assert_eq(msg->num_matches, 0); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(kiwi).*", NULL); /* initial match, number of capture groups is 2: $0, $1 */ gssize value_len; const gchar *value = log_msg_get_value(msg, LM_V_MESSAGE, &value_len); result = log_matcher_match(m, msg, LM_V_MESSAGE, value, value_len); cr_assert(result); assert_log_message_value(msg, LM_V_MESSAGE, msg_payload); assert_log_message_match_value(msg, 0, value); assert_log_message_match_value(msg, 1, "kiwi"); cr_assert_eq(msg->num_matches, 2); /* another match, number of capture groups is 3, producing $0, $1, $2 */ log_matcher_compile(m, "^(ki)(wi).*", NULL); value = log_msg_get_value(msg, LM_V_MESSAGE, &value_len); result = log_matcher_match(m, msg, LM_V_MESSAGE, value, value_len); cr_assert(result); assert_log_message_value(msg, LM_V_MESSAGE, msg_payload); assert_log_message_match_value(msg, 0, value); assert_log_message_match_value(msg, 1, "ki"); assert_log_message_match_value(msg, 2, "wi"); cr_assert_eq(msg->num_matches, 3); /* another match, decreasing the number of matches, going back to 2 capture groups */ log_matcher_compile(m, "^(kiwi).*", NULL); value = log_msg_get_value(msg, LM_V_MESSAGE, &value_len); result = log_matcher_match(m, msg, LM_V_MESSAGE, value, value_len); cr_assert(result); assert_log_message_value(msg, LM_V_MESSAGE, msg_payload); assert_log_message_match_value(msg, 0, value); assert_log_message_match_value(msg, 1, "kiwi"); cr_assert_eq(msg->num_matches, 2); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_matcher_captures_into_indirect_values) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; const gchar *msg_payload = "kiwi-wiki"; msg = _create_log_message(msg_payload); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(?kiwi).*", NULL); result = log_matcher_match_value(m, msg, LM_V_MESSAGE); cr_assert(result); assert_log_message_match_value(msg, 1, "kiwi"); assert_log_message_value_by_name(msg, "foobar", "kiwi"); assert_log_message_value_is_indirect(msg, log_msg_get_value_handle("foobar")); assert_log_message_value_is_indirect(msg, log_msg_get_value_handle("1")); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_matcher_builtins_are_captured_into_direct_values) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; const gchar *msg_payload = "kiwi-wiki"; msg = _create_log_message(msg_payload); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(?kiwi).*", NULL); result = log_matcher_match_value(m, msg, LM_V_MESSAGE); cr_assert(result); assert_log_message_match_value(msg, 1, "kiwi"); assert_log_message_value_by_name(msg, "PID", "kiwi"); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("PID")); assert_log_message_value_is_indirect(msg, log_msg_get_value_handle("1")); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_matcher_matches_against_macros_are_captured_directly) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; msg = create_empty_message(); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(?10\\.11\\.)12\\.13", NULL); result = log_matcher_match_value(m, msg, log_msg_get_value_handle("SOURCEIP")); cr_assert(result); assert_log_message_match_value(msg, 1, "10.11."); assert_log_message_value_by_name(msg, "foobar", "10.11."); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("foobar")); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("1")); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_matcher_matches_against_matches_are_captured_directly) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; msg = create_empty_message(); log_msg_set_match(msg, 1, "kiwi-wiki", -1); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(?kiwi).*", NULL); result = log_matcher_match_value(m, msg, log_msg_get_value_handle("1")); cr_assert(result); assert_log_message_match_value(msg, 1, "kiwi"); assert_log_message_value_by_name(msg, "foobar", "kiwi"); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("foobar")); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("1")); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_matcher_matches_against_buffers_are_captured_directly) { LogMatcherOptions matcher_options; LogMessage *msg; gboolean result; msg = create_empty_message(); log_matcher_options_defaults(&matcher_options); matcher_options.flags = LMF_STORE_MATCHES; LogMatcher *m = log_matcher_pcre_re_new(&matcher_options); log_matcher_compile(m, "^(?kiwi).*", NULL); result = log_matcher_match_buffer(m, msg, "kiwi-wiki", 9); cr_assert(result); assert_log_message_match_value(msg, 1, "kiwi"); assert_log_message_value_by_name(msg, "foobar", "kiwi"); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("foobar")); assert_log_message_value_is_direct(msg, log_msg_get_value_handle("1")); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_replace_works_correctly_if_capture_group_overwrites_the_input_in_a_match_variable) { gssize value_len; gssize result_len; LogTemplate *replace_template; const gchar *test_message = "foo bar baz"; const gchar *expected_result = "oo bar baz"; const gchar *match_pattern = "^(\\w)"; const gchar *replace_pattern = ""; LogMatcher *m = _construct_matcher(0, log_matcher_pcre_re_new); log_matcher_compile(m, match_pattern, NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, "1", test_message, -1); replace_template = log_template_new(configuration, NULL); cr_assert(log_template_compile(replace_template, replace_pattern, NULL)); NVHandle input_handle = log_msg_get_value_handle("1"); const gchar *input = log_msg_get_value(msg, input_handle, &value_len); NVTable *payload = nv_table_ref(msg->payload); gchar *result = log_matcher_replace(m, msg, input_handle, input, value_len, replace_template, &result_len); nv_table_unref(payload); cr_log_info("replace result value: %s, length(%ld)", result, result_len); cr_assert_arr_eq(result, expected_result, strlen(expected_result), "replace failed; result: %s (length %ld), expected: %s (length %ld)", result, result_len, expected_result, strlen(expected_result)); g_free(result); log_template_unref(replace_template); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_replace_works_correctly_if_named_capture_group_overwrites_the_input) { gssize value_len; gssize result_len; LogTemplate *replace_template; const gchar *test_message = "foo bar baz"; const gchar *expected_result = "foo bar RRR"; const gchar *match_pattern = "(?(baz))"; const gchar *replace_pattern = "RRR"; LogMatcher *m = _construct_matcher(0, log_matcher_pcre_re_new); log_matcher_compile(m, match_pattern, NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, "TMP", test_message, -1); replace_template = log_template_new(configuration, NULL); cr_assert(log_template_compile(replace_template, replace_pattern, NULL)); NVHandle input_handle = log_msg_get_value_handle("TMP"); const gchar *input = log_msg_get_value(msg, input_handle, &value_len); NVTable *payload = nv_table_ref(msg->payload); gchar *result = log_matcher_replace(m, msg, input_handle, input, value_len, replace_template, &result_len); nv_table_unref(payload); cr_log_info("replace result value: %s, length(%ld)", result, result_len); cr_assert_arr_eq(result, expected_result, strlen(expected_result), "replace failed; result: %s (length %ld), expected: %s (length %ld)", result, result_len, expected_result, strlen(expected_result)); g_free(result); log_template_unref(replace_template); log_matcher_unref(m); log_msg_unref(msg); } Test(matcher, test_replace_works_correctly_if_input_is_a_match_value_that_gets_truncated) { gssize value_len; gssize result_len; LogTemplate *replace_template; const gchar *test_message = "foo bar baz"; const gchar *expected_result = "foo RRR baz"; const gchar *match_pattern = "(bar)"; const gchar *replace_pattern = "RRR"; LogMatcher *m = _construct_matcher(0, log_matcher_pcre_re_new); log_matcher_compile(m, match_pattern, NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, "2", test_message, -1); replace_template = log_template_new(configuration, NULL); cr_assert(log_template_compile(replace_template, replace_pattern, NULL)); NVHandle input_handle = log_msg_get_value_handle("2"); const gchar *input = log_msg_get_value(msg, input_handle, &value_len); NVTable *payload = nv_table_ref(msg->payload); gchar *result = log_matcher_replace(m, msg, input_handle, input, value_len, replace_template, &result_len); nv_table_unref(payload); cr_log_info("replace result value: %s, length(%ld)", result, result_len); cr_assert_arr_eq(result, expected_result, strlen(expected_result), "replace failed; result: %s (length %ld), expected: %s (length %ld)", result, result_len, expected_result, strlen(expected_result)); g_free(result); log_template_unref(replace_template); log_matcher_unref(m); log_msg_unref(msg); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_messages.c000066400000000000000000000076111450431004300223020ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "messages.h" #include "apphook.h" #include "logmsg/logmsg.h" #include TestSuite(test_messages, .init = app_startup, .fini = app_shutdown); void simple_test_asserter(LogMessage *msg) { cr_assert_str_eq(log_msg_get_value_by_name(msg, "MESSAGE", NULL), "simple test;"); log_msg_unref(msg); } Test(test_messages, simple_test) { msg_set_post_func(simple_test_asserter); msg_error("simple test"); } void test_errno_asserter(LogMessage *msg) { gchar expected_message[100]; g_snprintf(expected_message, sizeof(expected_message), "test errno; error='%s (%d)'", strerror(5), 5); cr_assert_str_eq(log_msg_get_value_by_name(msg, "MESSAGE", NULL), expected_message); log_msg_unref(msg); } Test(test_messages, test_errno) { errno = 5; msg_set_post_func(test_errno_asserter); msg_error("test errno", evt_tag_error("error")); } void test_errno_capture_asserter(LogMessage *msg) { gchar pattern[100]; g_snprintf(pattern, sizeof(pattern), "error='%s (%d)'", strerror(9), 9); const gchar *msg_content = log_msg_get_value_by_name(msg, "MESSAGE", NULL); cr_assert(g_strstr_len(msg_content, -1, pattern), "searching: >>%s<< in >>%s<<", pattern, msg_content); log_msg_unref(msg); } Test(test_messages, test_errno_capture) { errno = 9; msg_set_post_func(test_errno_capture_asserter); msg_error("test errno capture", (errno=10, evt_tag_error("error"))); } Test(test_messages, test_msg_set_log_level_sets_flags_correctly) { verbose_flag = FALSE; debug_flag = FALSE; trace_flag = FALSE; msg_set_log_level(0); cr_assert_not(verbose_flag); cr_assert_not(debug_flag); cr_assert_not(trace_flag); cr_assert_eq(msg_get_log_level(), 0); msg_set_log_level(1); cr_assert(verbose_flag); cr_assert_not(debug_flag); cr_assert_not(trace_flag); cr_assert_eq(msg_get_log_level(), 1); msg_set_log_level(2); cr_assert(verbose_flag); cr_assert(debug_flag); cr_assert_not(trace_flag); cr_assert_eq(msg_get_log_level(), 2); msg_set_log_level(3); cr_assert(verbose_flag); cr_assert(debug_flag); cr_assert(trace_flag); cr_assert_eq(msg_get_log_level(), 3); /* this does nothing */ msg_set_log_level(-1); cr_assert(verbose_flag); cr_assert(debug_flag); cr_assert(trace_flag); cr_assert_eq(msg_get_log_level(), 3); msg_set_log_level(0); cr_assert_not(verbose_flag); cr_assert_not(debug_flag); cr_assert_not(trace_flag); cr_assert_eq(msg_get_log_level(), 0); /* this does nothing */ msg_set_log_level(-1); cr_assert_not(verbose_flag); cr_assert_not(debug_flag); cr_assert_not(trace_flag); cr_assert_eq(msg_get_log_level(), 0); } Test(test_messages, test_msg_apply_config_log_level_sets_log_level_if_unset) { msg_apply_config_log_level(3); cr_assert_eq(msg_get_log_level(), 3); } Test(test_messages, test_msg_apply_config_log_level_is_ignored_if_already_set) { msg_apply_cmdline_log_level(1); msg_apply_config_log_level(3); cr_assert_eq(msg_get_log_level(), 1); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_msgparse.c000066400000000000000000001260721450431004300223170ustar00rootroot00000000000000/* * Copyright (c) 2007-2016 Balabit * Copyright (c) 2007-2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/msg_parse_lib.h" #include "libtest/fake-time.h" #include "logmsg/logmsg.h" #include "serialize.h" #include "apphook.h" #include "gsockaddr.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include "cfg.h" #include "plugin.h" #include #include #include #include struct sdata_pair { const gchar *name; const gchar *value; }; struct sdata_pair ignore_sdata_pairs[] = { { NULL, NULL } }; struct sdata_pair empty_sdata_pairs[] = { { NULL, NULL } }; MsgFormatOptions parse_options; static unsigned long _absolute_value(signed long diff) { if (diff < 0) return -diff; else return diff; } static void _simulate_log_readers_effect_on_timezone_offset(LogMessage *message) { if (message->timestamps[LM_TS_STAMP].ut_gmtoff == -1) message->timestamps[LM_TS_STAMP].ut_gmtoff = get_local_timezone_ofs(message->timestamps[LM_TS_STAMP].ut_sec); } static LogMessage * _parse_log_message(gchar *raw_message_str, gint parse_flags, gchar *bad_hostname_re) { LogMessage *message; regex_t bad_hostname; parse_options.flags = parse_flags; parse_options.sdata_param_value_max = 255; if (bad_hostname_re) { cr_assert_eq(regcomp(&bad_hostname, bad_hostname_re, REG_NOSUB | REG_EXTENDED), 0, "Unexpected failure of regcomp(); bad_hostname_re='%s'", bad_hostname_re); parse_options.bad_hostname = &bad_hostname; } message = msg_format_parse(&parse_options, (const guchar *) raw_message_str, strlen(raw_message_str)); if (bad_hostname_re) { regfree(parse_options.bad_hostname); parse_options.bad_hostname = NULL; } _simulate_log_readers_effect_on_timezone_offset(message); return message; } void assert_log_message_sdata_pairs(LogMessage *message, struct sdata_pair *expected_sd_pairs) { gint i; for (i = 0; expected_sd_pairs && expected_sd_pairs[i].name != NULL; i++) { const gchar *actual_value = log_msg_get_value_by_name(message, expected_sd_pairs[i].name, NULL); cr_assert_str_eq(actual_value, expected_sd_pairs[i].value); } } struct msgparse_params { gchar *msg; gint parse_flags; gchar *bad_hostname_re; gint expected_pri; unsigned long expected_stamp_sec; unsigned long expected_stamp_usec; unsigned long expected_stamp_ofs; const gchar *expected_host; const gchar *expected_program; const gchar *expected_msg; const gchar *expected_sd_str; const gchar *expected_pid; const gchar *expected_msgid; struct sdata_pair *expected_sd_pairs; }; void setup(void) { app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); init_parse_options_and_load_syslogformat(&parse_options); /* Fri Feb 8 09:37:49 CET 2019 */ fake_time(1549615069); } void teardown(void) { deinit_syslogformat_module(); app_shutdown(); } TestSuite(msgparse, .init = setup, .fini = teardown); void test_log_messages_can_be_parsed(struct msgparse_params *param) { LogMessage *parsed_message; UnixTime *parsed_timestamp; time_t now; GString *sd_str; parsed_message = _parse_log_message(param->msg, param->parse_flags, param->bad_hostname_re); parsed_timestamp = &(parsed_message->timestamps[LM_TS_STAMP]); if (param->expected_stamp_sec) { if (param->expected_stamp_sec != 1) cr_assert_eq(parsed_timestamp->ut_sec, param->expected_stamp_sec, "Unexpected timestamp, value=%ld, expected=%ld, msg=%s", parsed_timestamp->ut_sec, param->expected_stamp_sec, param->msg); cr_assert_eq(parsed_timestamp->ut_usec, param->expected_stamp_usec, "Unexpected microseconds"); cr_assert_eq(parsed_timestamp->ut_gmtoff, param->expected_stamp_ofs, "Unexpected timezone offset"); } else { now = cached_g_current_time_sec(); cr_assert(_absolute_value(parsed_timestamp->ut_sec - now) <= 5, "Expected parsed message timestamp to be set to now; now='%d', timestamp->tv_sec='%d'", (gint)now, (gint)parsed_timestamp->ut_sec); } cr_assert_eq(parsed_message->pri, param->expected_pri, "Unexpected message priority %d != %d", parsed_message->pri, param->expected_pri); assert_log_message_value(parsed_message, LM_V_HOST, param->expected_host); assert_log_message_value(parsed_message, LM_V_PROGRAM, param->expected_program); assert_log_message_value(parsed_message, LM_V_MESSAGE, param->expected_msg); if (param->expected_pid) assert_log_message_value(parsed_message, LM_V_PID, param->expected_pid); if (param->expected_msgid) assert_log_message_value(parsed_message, LM_V_MSGID, param->expected_msgid); if (param->expected_sd_str) { sd_str = g_string_sized_new(0); log_msg_format_sdata(parsed_message, sd_str, 0); cr_assert_str_eq(sd_str->str, param->expected_sd_str, "Unexpected formatted SData"); g_string_free(sd_str, TRUE); } assert_log_message_sdata_pairs(parsed_message, param->expected_sd_pairs); log_msg_unref(parsed_message); } void run_parameterized_test(struct msgparse_params *params) { struct msgparse_params *param = params; for (; param->msg != NULL; ++param) test_log_messages_can_be_parsed(param); } Test(msgparse, test_parse_longer_than_32_sd_id) { struct sdata_pair expected_sd_pairs_test_long_sd_id[] = { { ".SDATA.timeQuality.isSynced", "0"}, { ".SDATA.1234567890123456789012345678901234.i", "long_33"}, { NULL, NULL }, }; struct msgparse_params params[] = { { "<5>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [timeQuality isSynced=\"0\"][1234567890123456789012345678901234 i=\"long_33\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 5, //pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", //host "evntslog", //app "An application event log entry...", // msg "[timeQuality isSynced=\"0\"][1234567890123456789012345678901234 i=\"long_33\"]", // sd str, 0, // processid 0, // msgid, expected_sd_pairs_test_long_sd_id }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_bad_sd_data_unescaped) { struct msgparse_params params[] = { { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\"\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "syslog-ng", //app "Error processing log message: <132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\">@<\"ok\"] An application event log entry...", // msg "", //sd_str 0,//processid 0,//msgid empty_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_timestamp) { struct msgparse_params params[] = { { "<15> openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 15, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<15>Jan 1 01:00:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 15, // pri 1546300800, 0, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<15>Jan 10 01:00:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 15, // pri 1547078400, 0, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<13>Jan 1 14:40:51 alma korte: message", 0, NULL, 13, 1546350051, 0, 3600, "", "alma", "korte: message", NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>2006-11-10T10:43:21.156+02:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1163148201, 156000, 7200, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-11-10T10:43:21.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1163151801, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-11-10T10:43:21.15600000000000000000000000000000000000000000000000000000000000+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1163151801, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-11-10T10:43:21.15600000000 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1163151801, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-03-26T01:59:59.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1143334799, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-03-26T02:00:00.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1143334800, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-03-26T03:00:00.156+02:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1143334800, 156000, 7200, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-10-29T01:00:00.156+02:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162076400, 156000, 7200, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-10-29T01:59:59.156+02:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162079999, 156000, 7200, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+02:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162080000, 156000, 7200, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>1 - bzorp openvpn 2499 - - PTHREAD support initialized", LP_SYSLOG_PROTOCOL, NULL, 7, // pri 1549615069, 123000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_foreign_timezone) { struct msgparse_params params[] = { { "<7>2006-10-29T01:00:00.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162080000, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-10-29T01:59:59.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_hostname) { struct msgparse_params params[] = { { "<7>2006-10-29T02:00:00.156+01:00 %bzorp openvpn[2499]: PTHREAD support initialized", LP_CHECK_HOSTNAME | LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "%bzorp", // openvpn "openvpn[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", LP_CHECK_HOSTNAME | LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "bzorp", // host "openvpn", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_timestamp_others) { struct msgparse_params params[] = { { "<7>2006-10-29T02:00:00.156+01:00 bzorp openvpn[2499]: PTHREAD support initialized", 0, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "bzorp", // program "openvpn[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+01:00 ", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "", // openvpn "", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+01:00", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "", // openvpn "", // msg NULL, NULL, NULL, ignore_sdata_pairs }, /* some stuff forget the 'T' in the ISO timestamp */ { "<7>2006-10-29 02:00:00.156+01:00", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "", // openvpn "", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>2006-10-29T02:00:00.156+01:00 ctld snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, "^ctld", 7, // pri 1162083600, 156000, 3600, // timestamp (sec/usec/zone) "", // host "ctld", // openvpn "snmpd[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7> Aug 29 02:00:00.156 ctld snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, "^ctld", 7, // pri 1, 156000, 7200, // timestamp (sec/usec/zone) "", // host "ctld", // openvpn "snmpd[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7> Aug 29 02:00:00.156789 ctld snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, "^ctld", 7, // pri 1, 156789, 7200, // timestamp (sec/usec/zone) "", // host "ctld", // openvpn "snmpd[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7> Aug 29 02:00:00. ctld snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, "^ctld", 7, // pri 1, 0, 7200, // timestamp (sec/usec/zone) "", // host "ctld", // openvpn "snmpd[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7> Aug 29 02:00:00 ctld snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, "^ctld", 7, // pri 1, 0, 7200, // timestamp (sec/usec/zone) "", // host "ctld", // openvpn "snmpd[2499]: PTHREAD support initialized", // msg NULL, NULL, NULL, ignore_sdata_pairs }, { "<7>Aug 29 02:00:00 bzorp ctld/snmpd[2499]: PTHREAD support initialized", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1, 0, 7200, // timestamp (sec/usec/zone) "bzorp", // host "ctld/snmpd", // openvpn "PTHREAD support initialized", // msg NULL, "2499", NULL, ignore_sdata_pairs }, { "<190>Apr 15 2007 21:28:13: %PIX-6-302014: Teardown TCP connection 1688438 for bloomberg-net:1.2.3.4/8294 to inside:5.6.7.8/3639 duration 0:07:01 bytes 16975 TCP FINs", LP_EXPECT_HOSTNAME, "^%", 190, 1176665293, 0, 7200, "", "%PIX-6-302014", "Teardown TCP connection 1688438 for bloomberg-net:1.2.3.4/8294 to inside:5.6.7.8/3639 duration 0:07:01 bytes 16975 TCP FINs", NULL, NULL, NULL, ignore_sdata_pairs }, /* Dell switch */ { "<190>NOV 22 00:00:33 192.168.33.8-1 CMDLOGGER[165319912]: cmd_logger_api.c(83) 13518 %% CLI:192.168.32.100:root:User logged in", LP_EXPECT_HOSTNAME, NULL, 190, 1574377233, 0, 3600, "192.168.33.8-1", "CMDLOGGER", "cmd_logger_api.c(83) 13518 %% CLI:192.168.32.100:root:User logged in", NULL, NULL, NULL, ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_0) { struct sdata_pair expected_sd_pairs_test_0[] = { { ".SDATA.timeQuality.isSynced", "1"}, { NULL, NULL }, }; struct msgparse_params params[] = { { "<190>.Apr 15 2007 21:28:13: %PIX-6-302014: Teardown TCP connection 1688438 for bloomberg-net:1.2.3.4/8294 to inside:5.6.7.8/3639 duration 0:07:01 bytes 16975 TCP FINs", LP_EXPECT_HOSTNAME, "^%", 190, 1176665293, 0, 7200, "", "%PIX-6-302014", "Teardown TCP connection 1688438 for bloomberg-net:1.2.3.4/8294 to inside:5.6.7.8/3639 duration 0:07:01 bytes 16975 TCP FINs", NULL, NULL, NULL, expected_sd_pairs_test_0 }, { "<190>Apr 15 2007 21:28:13 %ASA: this is a Cisco ASA timestamp", LP_EXPECT_HOSTNAME, "^%", 190, 1176665293, 0, 7200, "", "%ASA", "this is a Cisco ASA timestamp", NULL, NULL, NULL, ignore_sdata_pairs }, { "<190>Apr 15 21:28:13 2007 linksys app: msg", LP_EXPECT_HOSTNAME, NULL, 190, 1176665293, 0, 7200, "linksys", "app", "msg", NULL, NULL, NULL, ignore_sdata_pairs }, { "<38>Sep 22 10:11:56 Message forwarded from cdaix66: sshd[679960]: Accepted publickey for nagios from 1.9.1.1 port 42096 ssh2", LP_EXPECT_HOSTNAME, NULL, 38, 1, 0, 7200, "cdaix66", "sshd", "Accepted publickey for nagios from 1.9.1.1 port 42096 ssh2", NULL, NULL, NULL, NULL }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_1) { struct sdata_pair expected_sd_pairs_test_1[] = { { ".SDATA.exampleSDID@0.iut", "3"}, { ".SDATA.exampleSDID@0.eventSource", "Application"}, { ".SDATA.exampleSDID@0.eventID", "1011"}, { ".SDATA.examplePriority@0.class", "high"}, { NULL, NULL } }; struct msgparse_params params[] = { { "<7>1 2006-10-29T01:59:59.156+01:00 mymachine.example.com evntslog - ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \xEF\xBB\xBF" "An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 7, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine.example.com", // host "evntslog", //app "An application event log entry...", // msg "[exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"]", //sd_str "",//processid "ID47",//msgid expected_sd_pairs_test_1 }, { "<7>1 2006-10-29T01:59:59.156Z mymachine.example.com evntslog - ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \xEF\xBB\xBF" "An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 7, // pri 1162087199, 156000, 0, // timestamp (sec/usec/zone) "mymachine.example.com", // host "evntslog", //app "An application event log entry...", // msg "[exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"]", //sd_str "",//processid "ID47",//msgid expected_sd_pairs_test_1 }, { "<7>1 2006-10-29T01:59:59.156123Z mymachine.example.com evntslog - ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \xEF\xBB\xBF" "An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 7, // pri 1162087199, 156123, 0, // timestamp (sec/usec/zone) "mymachine.example.com", // host "evntslog", //app "An application event log entry...", // msg "[exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"]", //sd_str "",//processid "ID47",//msgid expected_sd_pairs_test_1 }, { "<7>1 2006-10-29T01:59:59.156Z mymachine.example.com evntslog - ID47 [ exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \xEF\xBB\xBF" "An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "syslog-ng", //app "Error processing log message: <7>1 2006-10-29T01:59:59.156Z mymachine.example.com evntslog - ID47 >@<[ exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] \xEF\xBB\xBF" "An application event log entry...", // msg "", NULL,//processid NULL,//msgid empty_sdata_pairs }, { "<34>1 1987-01-01T12:00:27.000087+00:20 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.", LP_SYSLOG_PROTOCOL, NULL, 34, 536499627, 87, 1200, "192.0.2.1", "myproc", "%% It's time to make the do-nuts.", "", "8710", "", ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_2) { struct sdata_pair expected_sd_pairs_test_2[] = { { ".SDATA.exampleSDID@0.iut", "3"}, { NULL, NULL } }; struct msgparse_params params[] = { { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [exampleSDID@0 iut=\"3\"] [eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "[eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] An application event log entry...", // msg "[exampleSDID@0 iut=\"3\"]", //sd_str "",//processid "",//msgid expected_sd_pairs_test_2 }, { "<7>Aug 29 02:00:00 bzorp ctld/snmpd[2499]:", LP_EXPECT_HOSTNAME, NULL, 7, // pri 1, 0, 7200, // timestamp (sec/usec/zone) "bzorp", // host "ctld/snmpd", // openvpn "", // msg NULL, "2499", NULL, ignore_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_3) { struct sdata_pair expected_sd_pairs_test_3[] = { { ".SDATA.origin.ip", "exchange.macartney.esbjerg"}, { ".SDATA.meta.sequenceId", "191732"}, { ".SDATA.EventData@18372.4.Data", "MSEXCHANGEOWAAPPPOOL.CONFIG\" -W \"\" -M 1 -AP \"MSEXCHANGEOWAAPPPOOL5244fileserver.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 mail.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 maindc.macartney.esbjerg CD- 1 6 6 0 0 1 1 6 1 " }, { NULL, NULL } }; struct msgparse_params params[] = { { "<134>1 2009-10-16T11:51:56+02:00 exchange.macartney.esbjerg MSExchange_ADAccess 20208 - [origin ip=\"exchange.macartney.esbjerg\"][meta sequenceId=\"191732\" sysUpTime=\"68807696\"][EventData@18372.4 Data=\"MSEXCHANGEOWAAPPPOOL.CONFIG\\\" -W \\\"\\\" -M 1 -AP \\\"MSEXCHANGEOWAAPPPOOL5244fileserver.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 mail.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 maindc.macartney.esbjerg CD- 1 6 6 0 0 1 1 6 1 \"][Keywords@18372.4 Keyword=\"Classic\"] ApplicationMSExchangeADAccess: message", LP_SYSLOG_PROTOCOL, NULL, 134, // pri 1255686716, 0, 7200, // timestamp (sec/usec/zone) "exchange.macartney.esbjerg", // host "MSExchange_ADAccess", //app "ApplicationMSExchangeADAccess: message", // msg "[origin ip=\"exchange.macartney.esbjerg\"][meta sequenceId=\"191732\" sysUpTime=\"68807696\"][EventData@18372.4 Data=\"MSEXCHANGEOWAAPPPOOL.CONFIG\\\" -W \\\"\\\" -M 1 -AP \\\"MSEXCHANGEOWAAPPPOOL5244fileserver.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 mail.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 maindc.macartney.esbjerg CD- 1 6 6 0 0 1 1 6 1 \"][Keywords@18372.4 Keyword=\"Classic\"]", //sd_str "20208",//processid "",//msgid expected_sd_pairs_test_3 }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_long) { struct sdata_pair expected_sd_pairs_test_5[] = { { ".SDATA.a.i", "]\"\\"}, { NULL, NULL } }; struct sdata_pair expected_sd_pairs_test_5b[] = { { ".SDATA.a.i", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, { NULL, NULL } }; struct sdata_pair expected_sd_pairs_test_5c[] = { { ".SDATA.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.i", "long_33"}, { NULL, NULL } }; struct sdata_pair expected_sd_pairs_test_5d[] = { { ".SDATA.a.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "long_33"}, { NULL, NULL } }; struct sdata_pair expected_sd_pairs_test_5e[] = { { ".SDATA.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "long_33"}, { NULL, NULL } }; struct msgparse_params params[] = { { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\"\\]\\\"\\\\\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[a i=\"\\]\\\"\\\\\"]", //sd_str "",//processid "",//msgid expected_sd_pairs_test_5 }, // parse longer than 32 sd id { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa i=\"long_33\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa i=\"long_33\"]", //sd_str 0,//processid 0,//msgid expected_sd_pairs_test_5c }, // parse longer than 32 sd name { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\"long_33\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\"long_33\"]", //sd_str 0,//processid 0,//msgid expected_sd_pairs_test_5d }, // parse longer than 32 sd id and name together { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\"long_33\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=\"long_33\"]", //sd_str 0,//processid 0,//msgid expected_sd_pairs_test_5e }, // parse longer than 255 sd id { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa i=\"long\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "syslog-ng", //app "Error processing log message: <132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>@1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[a i=\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"]", //sd_str "",//processid "",//msgid expected_sd_pairs_test_5b }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_unescaped_too_long_message_parts) { struct sdata_pair expected_sd_pairs_test_6[] = { { ".SDATA.a.i", "ok"}, { NULL, NULL } }; struct msgparse_params params[] = { // too long hostname { "<132>1 2006-10-29T01:59:59.156+01:00 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa evntslog - - [a i=\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", //host "syslog-ng", //app "Error processing log message: <132>1 2006-10-29T01:59:59.156+01:00 >@1 2006-10-29T01:59:59.156+01:00 mymachine aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - - [a i=\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", //app "An application event log entry...", // msg "[a i=\"ok\"]", //sd_str 0,//processid 0,//msgid expected_sd_pairs_test_6 }, // failed to parse to long procid { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - [a i=\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[a i=\"ok\"]", //sd_str "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",//processid 0,//msgid expected_sd_pairs_test_6 }, // failed to parse to long msgid { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa [a i=\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 132, // pri 1162083599, 156000, 3600, // timestamp (sec/usec/zone) "mymachine", // host "evntslog", //app "An application event log entry...", // msg "[a i=\"ok\"]", //sd_str 0,//processid "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",//msgid expected_sd_pairs_test_6 }, // unescaped ] { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\"]ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "syslog-ng", //app "Error processing log message: <132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\">@<]ok\"] An application event log entry...", // msg "", //sd_str 0,//processid 0,//msgid empty_sdata_pairs }, // unescaped '\' // bad sd data unescaped " { "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\"\"ok\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 43, // pri 0, 0, 0, // timestamp (sec/usec/zone) "", // host "syslog-ng", //app "Error processing log message: <132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog - - [a i=\">@<\"ok\"] An application event log entry...", // msg "", //sd_str 0,//processid 0,//msgid 0 }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_tz_known) { struct sdata_pair expected_sd_pairs_test_7a[] = { { NULL, NULL } }; struct msgparse_params params[] = { //Testing syslog protocol message parsing if tzKnown=0 because there is no timezone information { "<134>1 2009-10-16T11:51:56 exchange.macartney.esbjerg MSExchange_ADAccess 20208 - - An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 134, // pri 1255686716, 0, 7200, // timestamp (sec/usec/zone) "exchange.macartney.esbjerg", // host "MSExchange_ADAccess", //app "An application event log entry...", // msg "",//sd_str "20208",//processid "",//msgid expected_sd_pairs_test_7a }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_enterprise_id) { struct sdata_pair expected_sd_pairs_test_8[] = { { ".SDATA.origin.enterpriseId", "1.3.6.1.4.1"}, { NULL, NULL } }; struct msgparse_params params[] = { { "<134>1 2009-10-16T11:51:56+02:00 exchange.macartney.esbjerg MSExchange_ADAccess 20208 - [origin enterpriseId=\"1.3.6.1.4.1\"] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 134, // pri 1255686716, 0, 7200, // timestamp (sec/usec/zone) "exchange.macartney.esbjerg", // host "MSExchange_ADAccess", //app "An application event log entry...", // msg "[origin enterpriseId=\"1.3.6.1.4.1\"]",//sd_str "20208",//processid "",//msgid expected_sd_pairs_test_8 }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_expected_sd_pairs_without_sd_param) { struct sdata_pair expected_sd_pairs_test_9[] = { { ".SDATA.origin.enterpriseId", "1.3.6.1.4.1"}, { NULL, NULL } }; struct msgparse_params params[] = { //Testing syslog protocol message parsing if SDATA contains only SD-ID without SD-PARAM //KNOWN BUG: 20459 { "<134>1 2009-10-16T11:51:56+02:00 exchange.macartney.esbjerg MSExchange_ADAccess 20208 - [origin enterpriseId=\"1.3.6.1.4.1\"][nosdnvpair] An application event log entry...", LP_SYSLOG_PROTOCOL, NULL, 134, // pri 1255686716, 0, 7200, // timestamp (sec/usec/zone) "exchange.macartney.esbjerg", // host "MSExchange_ADAccess", //app "An application event log entry...", // msg "[origin enterpriseId=\"1.3.6.1.4.1\"][nosdnvpair]",//sd_str "20208",//processid "",//msgid expected_sd_pairs_test_9 }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_ip_in_host) { struct msgparse_params params[] = { (struct msgparse_params) { .msg = "<0>Jan 10 01:00:00 1.2.3.4 prg0", .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_host = "1.2.3.4" }, (struct msgparse_params) { .msg = "<0>Jan 10 01:00:00 0000:BABA:BA00:DAB:BABA:BABA:BABA:BAB0 prg0", .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_host = "0000:BABA:BA00:DAB:BABA:BABA:BABA:BAB0" }, (struct msgparse_params) { .msg = "<0>Jan 10 01:00:00 0001:BABA:BA00:DAB::BAB0 prg0", .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_host = "0001:BABA:BA00:DAB::BAB0" }, { .msg = "<0>Jan 10 01:00:00 0002:: prg0: msgtxt", .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_host = "0002::", .expected_msg = "msgtxt" }, (struct msgparse_params) { .msg = "<0>Jan 10 01:00:00 prg0", // No ip no msg .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_host = "" }, (struct msgparse_params) { .msg = "<0>Jan 10 01:00:00 prg0: msgtxt", // program name with message, no ip .expected_stamp_sec = 1547078400, .expected_stamp_ofs = 3600, .expected_program = "prg0", .expected_msg = "msgtxt" }, (struct msgparse_params) { .msg = "<0>91: *Oct 07 03:10:04: mydevice.com %CRYPTO-4-RECVD_PKT_INV_SPI: decaps: rec'd IPSEC packet has invalid spi for destaddr=150.1.1.1, prot=50, spi=0x72662541(1919296833), srcaddr=150.3.1.3", .parse_flags = LP_EXPECT_HOSTNAME, .expected_stamp_sec = 1570410604, .expected_stamp_ofs = 7200, .expected_program = "%CRYPTO-4-RECVD_PKT_INV_SPI", .expected_host = "mydevice.com", .expected_msg = "decaps: rec'd IPSEC packet has invalid spi for destaddr=150.1.1.1, prot=50, spi=0x72662541(1919296833), srcaddr=150.3.1.3" }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_simple_message) { struct msgparse_params params[] = { { "some message", LP_EXPECT_HOSTNAME, NULL, 13, 0, 0, 0, "", "some", "message", "", 0, 0, empty_sdata_pairs }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_no_header_flag) { struct msgparse_params params[] = { { .msg = "<189>some message", .parse_flags = LP_NO_HEADER, .expected_pri = 189, .expected_program = "", .expected_host = "", .expected_msg = "some message", }, {NULL} }; run_parameterized_test(params); } Test(msgparse, test_no_rfc3164_fallback_flag) { struct msgparse_params params[] = { { .msg = "<189>some message", .parse_flags = LP_SYSLOG_PROTOCOL | LP_NO_RFC3164_FALLBACK, .expected_pri = 43, .expected_program = "syslog-ng", .expected_host = "", .expected_msg = "Error processing log message: <189>some message", }, {NULL} }; run_parameterized_test(params); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_parse_number.c000066400000000000000000000143261450431004300231560ustar00rootroot00000000000000/* * Copyright (c) 2013-2018 Balabit * Copyright (c) 2013 Gergely Nagy * Copyright (c) 2018 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "parse-number.h" #include static void assert_parse_with_suffix(const gchar *str, gint64 expected) { gint64 n; gboolean res; res = parse_int64_with_suffix(str, &n); cr_assert_eq(res, TRUE, "Parsing (w/ suffix) %s failed", str); cr_assert_eq(n, expected, "Parsing (w/ suffix) %s failed", str); } static void assert_parse_with_suffix_fails(const gchar *str) { gint64 n; gboolean res; res = parse_int64_with_suffix(str, &n); cr_assert_eq(res, FALSE, "Parsing (w/ suffix) %s succeeded, while expecting failure", str); } static void assert_parse(const gchar *str, gint64 expected) { gint64 n; gboolean res; res = parse_int64_base_any(str, &n); cr_assert_eq(res, TRUE, "Parsing (w/o suffix) %s failed", str); cr_assert_eq(n, expected, "Parsing (w/o suffix) %s failed", str); } static void assert_parse_fails(const gchar *str) { gint64 n; gboolean res; res = parse_int64_base_any(str, &n); cr_assert_eq(res, FALSE, "Parsing (w/o suffix) %s succeeded, while expecting failure", str); } static void assert_parse_dec(const gchar *str, gint64 expected) { gint64 n; gboolean res; res = parse_int64(str, &n); cr_assert_eq(res, TRUE, "Parsing (w/o suffix) %s failed", str); cr_assert_eq(n, expected, "Parsing (w/o suffix) %s failed", str); } static void assert_parse_dec_fails(const gchar *str) { gint64 n; gboolean res; res = parse_int64(str, &n); cr_assert_eq(res, FALSE, "Parsing (w/o suffix) %s succeeded, while expecting failure", str); } Test(parse_number, test_simple_numbers_are_parsed_properly) { assert_parse("1234", 1234); assert_parse("+1234", 1234); assert_parse("-1234", -1234); } Test(parse_number, test_c_like_prefixes_select_base) { assert_parse("0x20", 32); assert_parse("0xFF", 255); assert_parse("-0x09", -9); assert_parse("020", 16); assert_parse("-010", -8); assert_parse_fails("08"); assert_parse_fails("0A"); assert_parse("20", 20); assert_parse_fails("FF"); assert_parse_fails("1FF"); } Test(parse_number_dec, test_simple_numbers_are_parsed_properly) { assert_parse_dec("1234", 1234); assert_parse_dec("+1234", 1234); assert_parse_dec("-1234", -1234); } Test(parse_number_dec, test_c_like_prefixes_select_base) { assert_parse_dec_fails("1F20"); assert_parse_dec_fails("0x20"); assert_parse_dec_fails("0xFF"); assert_parse_dec_fails("-0x09"); assert_parse_dec("020", 20); assert_parse_dec("-010", -10); assert_parse_dec("08", 8); assert_parse_fails("0A"); assert_parse_dec("20", 20); assert_parse_dec_fails("FF"); } Test(parse_number_with_suffix, test_simple_numbers_are_parsed_properly) { assert_parse_with_suffix("1234", 1234); assert_parse_with_suffix("+1234", 1234); assert_parse_with_suffix("-1234", -1234); } Test(parse_number_with_suffix, test_c_like_prefixes_are_not_supported) { assert_parse_with_suffix_fails("0x20"); assert_parse_with_suffix("020", 20); assert_parse_with_suffix("-010", -10); assert_parse_with_suffix_fails("FF"); } Test(parse_number_with_suffix, test_exponent_suffix_is_parsed_properly) { assert_parse_with_suffix("1K", 1000); assert_parse_with_suffix("1k", 1000); assert_parse_with_suffix("1m", 1000 * 1000); assert_parse_with_suffix("1M", 1000 * 1000); assert_parse_with_suffix("1G", 1000 * 1000 * 1000); assert_parse_with_suffix("1g", 1000 * 1000 * 1000); } Test(parse_number_with_suffix, test_byte_units_are_accepted) { assert_parse_with_suffix("1b", 1); assert_parse_with_suffix("1B", 1); assert_parse_with_suffix("1Kb", 1000); assert_parse_with_suffix("1kB", 1000); assert_parse_with_suffix("1mb", 1000 * 1000); assert_parse_with_suffix("1MB", 1000 * 1000); assert_parse_with_suffix("1Gb", 1000 * 1000 * 1000); assert_parse_with_suffix("1gB", 1000 * 1000 * 1000); } Test(parse_number_with_suffix, test_base2_is_selected_by_an_i_modifier) { assert_parse_with_suffix("1Kib", 1024); assert_parse_with_suffix("1kiB", 1024); assert_parse_with_suffix("1Ki", 1024); assert_parse_with_suffix("1kI", 1024); assert_parse_with_suffix("1mib", 1024 * 1024); assert_parse_with_suffix("1MiB", 1024 * 1024); assert_parse_with_suffix("1Gib", 1024 * 1024 * 1024); assert_parse_with_suffix("1giB", 1024 * 1024 * 1024); assert_parse_with_suffix("1024giB", 1024LL * 1024LL * 1024LL * 1024LL); } Test(parse_number_with_suffix, test_invalid_formats_are_not_accepted) { assert_parse_with_suffix_fails("1234Z"); assert_parse_with_suffix_fails("1234kZ"); assert_parse_with_suffix_fails("1234kdZ"); assert_parse_with_suffix_fails("1234kiZ"); assert_parse_fails("1234kiZ"); } Test(parse_generic_number, test_string_is_properly_represented_as_a_generic_number) { GenericNumber gn; parse_generic_number("123", &gn); cr_assert(gn.type == GN_INT64); cr_assert(gn.value.raw_int64 == 123); parse_generic_number("-123", &gn); cr_assert(gn.type == GN_INT64); cr_assert(gn.value.raw_int64 == -123); parse_generic_number("-123.0", &gn); cr_assert(gn.type == GN_DOUBLE); cr_assert_float_eq(gn.value.raw_double, -123.0, DBL_EPSILON); parse_generic_number("9223372036854775808", &gn); cr_assert(gn.type == GN_DOUBLE); cr_assert_float_eq(gn.value.raw_double, 9223372036854775808.0, DBL_EPSILON); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_pathutils.c000066400000000000000000000061651450431004300225130ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "pathutils.h" #include #include #include #include Test(test_pathutils, test_is_file_directory) { int fd = open("test.file", O_CREAT | O_RDWR, 0644); cr_assert_not(fd < 0, "open error"); ssize_t done = write(fd, "a", 1); cr_assert_eq(done, 1, "write error"); int error = close(fd); cr_assert_not(error, "close error"); cr_assert_not(is_file_directory("test.file"), "File is not a directory!"); cr_assert(is_file_directory("./"), "File is a directory!"); error = unlink("test.file"); cr_assert_not(error, "unlink error"); } Test(test_pathutils, test_is_regular) { int fd = open("test2.file", O_CREAT | O_RDWR, 0644); int error = close(fd); cr_assert_not(error, "close error"); cr_assert(is_file_regular("test2.file"), "this is a regular file"); cr_assert_not(is_file_regular("./"), "this is not a regular file"); error = unlink("test2.file"); cr_assert_not(error, "unlink error"); } Test(test_pathutils, test_is_file_device) { cr_assert(is_file_device("/dev/null"), "not recognized device file"); } Test(test_pathutils, test_find_file_in_path) { gchar *file; file = find_file_in_path("/dev", "null", G_FILE_TEST_EXISTS); cr_assert_str_eq(file, "/dev/null"); g_free(file); file = find_file_in_path("/home:/dev:/root", "null", G_FILE_TEST_EXISTS); cr_assert_str_eq(file, "/dev/null"); g_free(file); } Test(test_pathutils, test_get_filename_extension) { cr_assert_str_eq(get_filename_extension("test.foo"), "foo", "wrong file name extension returned"); cr_assert_str_eq(get_filename_extension("/test/test.foo.bar"), "bar", "wrong file name extension returned"); cr_assert_str_eq(get_filename_extension("/test/.test/test.foo.bar"), "bar", "wrong file name extension returned"); cr_assert_null(get_filename_extension("/test"), "wrong file name extension returned"); cr_assert_null(get_filename_extension("test."), "wrong file name extension returned"); cr_assert_null(get_filename_extension(""), "wrong file name extension returned"); cr_assert_null(get_filename_extension(NULL), "wrong file name extension returned"); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_persist_state.c000066400000000000000000000310701450431004300233600ustar00rootroot00000000000000/* * Copyright (c) 2023 One Identity LLC. * Copyright (c) 2010-2016 Balabit * Copyright (c) 2010-2014 Balázs Scheidler * Copyright (c) 2014 Viktor Tusa * Copyright (c) 2020 One Identity * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/persist_lib.h" #include "persist-state.h" #include "apphook.h" #include #include #include #include #include #include typedef struct _TestState { guint32 value; } TestState; static void _write_test_file_for_test_in_use_handle(gboolean in_use_handle, const gchar *filename) { PersistState *state = clean_and_create_persist_state_for_test(filename); PersistEntryHandle handle = persist_state_alloc_entry(state, "alma", sizeof(TestState)); TestState *test_state = (TestState *) persist_state_map_entry(state, handle); test_state->value = 0xDEADBEEF; persist_state_unmap_entry(state, handle); if (!in_use_handle) persist_state_remove_entry(state, "alma"); commit_and_free_persist_state(state); } static void _foreach_callback_assertions(gchar *name, gint size, gpointer entry, gpointer userdata) { cr_assert_str_eq((gchar *) userdata, "test_userdata", "Userdata is not passed correctly to foreach func!"); cr_assert_str_eq(name, "test", "Name of persist entry does not match!"); TestState *state = (TestState *) entry; cr_assert_eq(state->value, 3, "Content of state does not match!"); cr_assert_eq(size, sizeof(TestState), "Size of state does not match!"); } TestSuite(persist_state, .init = app_startup, .fini = app_shutdown); #ifndef __hpux Test(persist_state, test_persist_state_open_success_on_invalid_file) { const gchar *persist_file = "test_invalid_magic.persist"; PersistState *state; int fd; unlink(persist_file); fd = open(persist_file, O_CREAT | O_RDWR, 0777); ssize_t ret = write(fd, "aaa", 3); cr_assert_eq(ret, 3, "Write error on invalid persist file: %s", strerror(errno)); close(fd); state = persist_state_new(persist_file); cr_assert(persist_state_start(state), "persist_state_start returned with false!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_open_fails_on_invalid_file_with_dump) { const gchar *persist_file = "test_invalid_magic_d.persist"; PersistState *state; int fd; unlink(persist_file); fd = open(persist_file, O_CREAT | O_RDWR, 0777); ssize_t ret = write(fd, "aaa", 3); cr_assert_eq(ret, 3, "Write error on invalid persist file: %s", strerror(errno)); close(fd); state = persist_state_new(persist_file); cr_assert_not(persist_state_start_dump(state), "persist_state_start_dump returned with success when persist file was invalid!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_open_failes_when_file_open_fails) { const gchar *persist_file = "test_invalid_magic_of.persist"; PersistState *state; unlink(persist_file); state = persist_state_new(persist_file); cr_assert_not(persist_state_start_dump(state), "persist_state_start_dump returned with success when persist file open failed!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_in_use_handle_is_loaded) { const gchar *persist_file = "test_in_use.persist"; PersistState *state; guint8 version; gsize size; PersistEntryHandle handle; unlink(persist_file); _write_test_file_for_test_in_use_handle(TRUE, persist_file); state = create_persist_state_for_test(persist_file); handle = persist_state_lookup_entry(state, "alma", &size, &version); cr_assert_neq(handle, 0, "lookup failed when looking for simple entry with in_use = TRUE!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_not_in_use_handle_is_not_loaded) { const gchar *persist_file = "test_in_use_hn.persist"; PersistState *state; guint8 version; gsize size; PersistEntryHandle handle; unlink(persist_file); _write_test_file_for_test_in_use_handle(FALSE, persist_file); state = create_persist_state_for_test(persist_file); handle = persist_state_lookup_entry(state, "alma", &size, &version); cr_assert_eq(handle, 0, "lookup succeeded when looking for simple entry with in_use = FALSE!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_not_in_use_handle_is_loaded_in_dump_mode) { const gchar *persist_file = "test_in_use_dm.persist"; PersistState *state; guint8 version; gsize size; PersistEntryHandle handle; unlink(persist_file); _write_test_file_for_test_in_use_handle(FALSE, persist_file); state = persist_state_new(persist_file); persist_state_start_dump(state); handle = persist_state_lookup_entry(state, "alma", &size, &version); cr_assert_neq(handle, 0, "lookup failed in dump mode when looking for simple entry with in_use = FALSE!"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_remove_entry) { guint8 version; gsize size; PersistState *state = clean_and_create_persist_state_for_test("test_persist_state_remove_entry.persist"); PersistEntryHandle handle = persist_state_alloc_entry(state, "test", sizeof(TestState)); handle = persist_state_lookup_entry(state, "test", &size, &version); cr_assert_neq(handle, 0, "lookup failed before removing entry"); persist_state_remove_entry(state, "test"); state = restart_persist_state(state); handle = persist_state_lookup_entry(state, "test", &size, &version); cr_assert_eq(handle, 0, "lookup succeeded after removing entry"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_string_alloc_test) { guint8 version; gsize size_1; gsize size_2; PersistEntryHandle handle_1; PersistEntryHandle handle_2; PersistState *state = clean_and_create_persist_state_for_test("test_persist_state_string_alloc.persist"); persist_state_alloc_string(state, "test", "test_longer", -1); handle_1 = persist_state_lookup_entry(state, "test", &size_1, &version); persist_state_alloc_string(state, "test", "test_short", -1); handle_2 = persist_state_lookup_entry(state, "test", &size_2, &version); cr_assert_eq(size_1, size_2, "allocation sizes do not match"); cr_assert_eq(handle_1, handle_2, "allocation handles do not match"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_foreach_entry) { PersistState *state = clean_and_create_persist_state_for_test("test_persist_foreach.persist"); PersistEntryHandle handle = persist_state_alloc_entry(state, "test", sizeof(TestState)); TestState *test_state = persist_state_map_entry(state, handle); test_state->value = 3; persist_state_unmap_entry(state, handle); persist_state_foreach_entry(state, _foreach_callback_assertions, "test_userdata"); cancel_and_destroy_persist_state(state); } Test(persist_state, test_values) { PersistState *state; gint i, j; gchar *data; state = clean_and_create_persist_state_for_test("test_values.persist"); for (i = 0; i < 1000; i++) { gchar buf[16]; PersistEntryHandle handle; g_snprintf(buf, sizeof(buf), "testkey%d", i); if (!(handle = persist_state_alloc_entry(state, buf, 128))) { fprintf(stderr, "Error allocating value in the persist file: %s\n", buf); exit(1); } data = persist_state_map_entry(state, handle); for (j = 0; j < 128; j++) { data[j] = (i % 26) + 'A'; } persist_state_unmap_entry(state, handle); } for (i = 0; i < 1000; i++) { gchar buf[16]; PersistEntryHandle handle; gsize size; guint8 version; g_snprintf(buf, sizeof(buf), "testkey%d", i); if (!(handle = persist_state_lookup_entry(state, buf, &size, &version))) { fprintf(stderr, "Error retrieving value from the persist file: %s\n", buf); exit(1); } data = persist_state_map_entry(state, handle); for (j = 0; j < 128; j++) { if (data[j] != (i % 26) + 'A') { fprintf(stderr, "Invalid data in persistent entry\n"); exit(1); } } persist_state_unmap_entry(state, handle); } state = restart_persist_state(state); for (i = 0; i < 1000; i++) { gchar buf[16]; PersistEntryHandle handle; gsize size; guint8 version; g_snprintf(buf, sizeof(buf), "testkey%d", i); if (!(handle = persist_state_lookup_entry(state, buf, &size, &version))) { fprintf(stderr, "Error retrieving value from the persist file: %s\n", buf); exit(1); } if (size != 128 || version != 4) { fprintf(stderr, "Error retrieving value from the persist file: %s, invalid size (%d) or version (%d)\n", buf, (gint) size, version); exit(1); } data = persist_state_map_entry(state, handle); for (j = 0; j < 128; j++) { if (data[j] != (i % 26) + 'A') { fprintf(stderr, "Invalid data in persistent entry\n"); exit(1); } } persist_state_unmap_entry(state, handle); } cancel_and_destroy_persist_state(state); } Test(persist_state, test_persist_state_temp_file_cleanup_on_cancel) { PersistState *state = clean_and_create_persist_state_for_test("test_persist_state_temp_file_cleanup_on_cancel.persist"); cancel_and_destroy_persist_state(state); cr_assert(access("test_persist_state_temp_file_cleanup_on_cancel.persist", F_OK) != 0, "persist file is removed on destroy()"); cr_assert(access("test_persist_state_temp_file_cleanup_on_cancel.persist-", F_OK) != 0, "backup persist file is removed on destroy()"); } Test(persist_state, test_persist_state_temp_file_cleanup_on_commit_destroy) { PersistState *state = clean_and_create_persist_state_for_test("test_persist_state_temp_file_cleanup_on_commit_destroy.persist"); commit_and_destroy_persist_state(state); cr_assert(access("test_persist_state_temp_file_cleanup_on_commit_destroy.persist", F_OK) != 0, "persist file is removed on destroy(), even after commit"); cr_assert(access("test_persist_state_temp_file_cleanup_on_commit_destroy.persist-", F_OK) != 0, "backup persist file is removed on destroy(), even after commit"); } void _write_test_state_value(PersistState *state, PersistEntryHandle handle, guint32 value) { TestState *test_state = (TestState *) persist_state_map_entry(state, handle); test_state->value = value; persist_state_unmap_entry(state, handle); } void assert_test_state_value(PersistState *state, PersistEntryHandle handle, guint32 expected_value) { TestState *test_state = (TestState *) persist_state_map_entry(state, handle); cr_assert_eq(test_state->value, expected_value); persist_state_unmap_entry(state, handle); } Test(persist_state, test_persist_state_move_entry) { PersistState *state = clean_and_create_persist_state_for_test("test_persist_state_move_entry.persist"); PersistEntryHandle handle = persist_state_alloc_entry(state, "to_be_moved", sizeof(TestState)); _write_test_state_value(state, handle, 0xDEC0DE); state = restart_persist_state(state); cr_assert(persist_state_move_entry(state, "to_be_moved", "new_name")); guint8 version; gsize size; PersistEntryHandle new_handle = persist_state_lookup_entry(state, "new_name", &size, &version); cr_assert_neq(new_handle, 0, "moved entry does not exist in the new location"); assert_test_state_value(state, new_handle, 0xDEC0DE); state = restart_persist_state(state); cr_assert_eq(persist_state_lookup_entry(state, "to_be_moved", &size, &version), 0, "moved persist entry has not been removed"); cancel_and_destroy_persist_state(state); } #endif syslog-ng-syslog-ng-4.4.0/lib/tests/test_pragma.c000066400000000000000000000045061450431004300217420ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Kokan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "pragma-parser.h" Test(pragma_parser, process_valid_major_minor) { const guint version = process_version_string("3.27"); cr_assert_eq(0x031b, version); } Test(pragma_parser, process_version_large_minor) { guint version = process_version_string("42.4294957319"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_large_major) { guint version = process_version_string("4294967299.7"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_overflow_major) { guint version = process_version_string("72057594037927939.7"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_invalid_minor) { guint version = process_version_string("4.x"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_random_suffix) { guint version = process_version_string("3.7.6.5.4.3.2.1.ignition.orbital.launch-successful!"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_random_prefix) { guint version = process_version_string(".+3.7"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_negative_major) { guint version = process_version_string("-1.1031"); cr_assert_eq(version, 0); } Test(pragma_parser, process_version_negative_minor) { guint version = process_version_string("42.-9977"); cr_assert_eq(version, 0); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_rcptid.c000066400000000000000000000066001450431004300217550ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/persist_lib.h" #include "apphook.h" #include "rcptid.h" #include static PersistState * setup_persist_id_test(const gchar *persist_file) { PersistState *state; state = clean_and_create_persist_state_for_test(persist_file); rcptid_init(state, TRUE); return state; } static void teardown_persist_id_test(PersistState *state) { commit_and_destroy_persist_state(state); rcptid_deinit(); } static void setup(void) { app_startup(); } static void teardown(void) { app_shutdown(); } TestSuite(rcptid, .init = setup, .fini = teardown); Test(rcptid, test_rcptid_is_persistent_across_persist_backend_reinits) { guint64 rcptid; PersistState *state = setup_persist_id_test("test_values.backend_reinits"); rcptid_set_id(0xFFFFFFFFFFFFFFFE); rcptid = rcptid_generate_id(); cr_assert_eq(rcptid, 0xFFFFFFFFFFFFFFFE, "Rcptid initialization to specific value failed!"); state = restart_persist_state(state); rcptid_deinit(); rcptid_init(state, TRUE); rcptid = rcptid_generate_id(); cr_assert_eq(rcptid, 0xFFFFFFFFFFFFFFFF, "Rcptid did not persisted across persist backend reinit!"); teardown_persist_id_test(state); } Test(rcptid, test_rcptid_overflows_at_64bits_and_is_reset_to_one) { guint64 rcptid; PersistState *state = setup_persist_id_test("test_values.reset_to_one"); rcptid_set_id(0xFFFFFFFFFFFFFFFF); rcptid = rcptid_generate_id(); rcptid = rcptid_generate_id(); cr_assert_eq(rcptid, (guint64) 1, "Rcptid counter overflow handling did not work!"); teardown_persist_id_test(state); } Test(rcptid, test_rcptid_is_formatted_as_a_number_when_nonzero) { PersistState *state = setup_persist_id_test("test_values.nonzero"); GString *formatted_rcptid = g_string_sized_new(0); rcptid_append_formatted_id(formatted_rcptid, 1); cr_assert_str_eq(formatted_rcptid->str, "1", "RCPTID macro formatting for non-zero number failed!"); g_string_free(formatted_rcptid, TRUE); teardown_persist_id_test(state); } Test(rcptid, test_rcptid_is_an_empty_string_when_zero) { PersistState *state = setup_persist_id_test("test_values.zero"); GString *formatted_rcptid = g_string_sized_new(0); rcptid_append_formatted_id(formatted_rcptid, 0); cr_assert_str_eq(formatted_rcptid->str, "", "RCPTID macro formatting for zero value failed!"); g_string_free(formatted_rcptid, TRUE); teardown_persist_id_test(state); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_reloc.c000066400000000000000000000046701450431004300216010ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "reloc.h" CacheResolver *path_resolver; Cache *path_cache; typedef struct _LookupParameter { const gchar *template; const gchar *expected; } LookupParameter; ParameterizedTestParameters(reloc, test_path) { static LookupParameter test_data_list[] = { {"/opt/syslog-ng", "/opt/syslog-ng"}, /* absolute path remains unchanged */ {"${prefix}/bin", "/test/bin"}, /* variables are resolved */ {"/foo/${prefix}/bar", "/foo//test/bar"}, /* variables are resolved in the middle */ {"${foo}/bin", "/foo/bin"}, /* variables are resolved recursively */ {"${bar}/bin", "/foo/bin"} /* variables are resolved recursively */ }; return cr_make_param_array(LookupParameter, test_data_list, sizeof(test_data_list) / sizeof(test_data_list[0])); } ParameterizedTest(LookupParameter *test_data, reloc, test_path) { const gchar *result; result = cache_lookup(path_cache, test_data->template); cr_assert_str_eq(result, test_data->expected, "Expanded install path (%s) doesn't match expected value (%s)", result, test_data->expected); } static void setup(void) { path_resolver = path_resolver_new("/test"); path_cache = cache_new(path_resolver); path_resolver_add_configure_variable(path_resolver, "${foo}", "/foo"); path_resolver_add_configure_variable(path_resolver, "${bar}", "${foo}"); } static void teardown(void) { cache_free(path_cache); } TestSuite(reloc, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_ringbuffer.c000066400000000000000000000153641450431004300226300ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2014 Laszlo Budai * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "ringbuffer.h" #include static const guint32 capacity = 47; typedef struct _TestData { int idx; gboolean ack; } TestData; static void _ringbuffer_init(RingBuffer *self) { ring_buffer_alloc(self, sizeof(TestData), capacity); } static void _ringbuffer_fill(RingBuffer *rb, size_t n, int start_idx, gboolean ack) { TestData *td; int i; for (i = 0; i < n; i++) { td = ring_buffer_push(rb); td->idx = start_idx + i; td->ack = ack; } } static void _ringbuffer_fill2(RingBuffer *rb, size_t n, int start_idx, gboolean ack) { TestData *td; int i; for (i = 0; i < n; i++) { td = ring_buffer_tail(rb); td->idx = start_idx + i; td->ack = ack; cr_assert_eq(ring_buffer_push(rb), td, "Push should return last tail."); } } static gboolean _is_continual(void *data) { TestData *td = (TestData *)data; return td->ack; } static void assert_continual_range_length_equals(RingBuffer *rb, size_t expected) { size_t range_len = ring_buffer_get_continual_range_length(rb, _is_continual); cr_assert_eq(range_len, expected); } static void assert_test_data_idx_range_in(RingBuffer *rb, int start, int end) { TestData *td; int i; cr_assert_eq(ring_buffer_count(rb), end-start + 1, "invalid ringbuffer size; actual:%d, expected: %d", ring_buffer_count(rb), end-start+1); for (i = start; i <= end; i++) { td = ring_buffer_element_at(rb, i - start); cr_assert_eq(td->idx, i, "wrong order: idx:(%d) <-> td->idx(%d)", i, td->idx); } } Test(ringbuffer, test_init_buffer_state) { RingBuffer rb; _ringbuffer_init(&rb); cr_assert_not(ring_buffer_is_full(&rb), "buffer should not be full"); cr_assert(ring_buffer_is_empty(&rb), "buffer should be empty"); cr_assert_eq(ring_buffer_count(&rb), 0, "buffer should be empty"); cr_assert_eq(ring_buffer_capacity(&rb), capacity, "invalid buffer capacity"); ring_buffer_free(&rb); } Test(ringbuffer, test_pop_from_empty_buffer) { RingBuffer rb; _ringbuffer_init(&rb); cr_assert_null(ring_buffer_pop(&rb), "cannot pop from empty buffer"); ring_buffer_free(&rb); } Test(ringbuffer, test_push_to_full_buffer) { RingBuffer rb; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); cr_assert_null(ring_buffer_push(&rb), "cannot push to a full buffer"); ring_buffer_free(&rb); } Test(ringbuffer, test_ring_buffer_is_full) { RingBuffer rb; int i; TestData *last = NULL; _ringbuffer_init(&rb); for (i = 1; !ring_buffer_is_full(&rb); i++) { TestData *td = ring_buffer_push(&rb); cr_assert_not_null(td, "ring_buffer_push failed"); td->idx = i; last = td; } cr_assert_eq(ring_buffer_count(&rb), capacity, "buffer count(%d) is not equal to capacity(%d)", ring_buffer_count(&rb), capacity); cr_assert_eq(last->idx, capacity, "buffer is not full, number of inserted items: %d, capacity: %d", last->idx, capacity); ring_buffer_free(&rb); } Test(ringbuffer, test_pop_all_pushed_element_in_correct_order) { RingBuffer rb; int cnt = 0; const int start_from = 1; TestData *td = NULL; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); while ((td = ring_buffer_pop(&rb))) { cr_assert_eq((cnt+start_from), td->idx, "wrong order; %d != %d", td->idx, cnt); ++cnt; } cr_assert_eq(cnt, capacity, "cannot read all element, %d < %d", cnt, capacity); ring_buffer_free(&rb); } Test(ringbuffer, test_drop_elements) { RingBuffer rb; const int rb_capacity = 103; const int drop = 31; ring_buffer_alloc(&rb, sizeof(TestData), rb_capacity); _ringbuffer_fill(&rb, rb_capacity, 1, TRUE); ring_buffer_drop(&rb, drop); cr_assert_eq(ring_buffer_count(&rb), (rb_capacity - drop), "drop failed"); ring_buffer_free(&rb); } Test(ringbuffer, test_elements_ordering) { RingBuffer rb; TestData *td; int start_from = 10; int cnt = 0; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, start_from, TRUE); while ( (td = ring_buffer_pop(&rb)) ) { cr_assert_eq((cnt + start_from), td->idx, "wrong order; %d != %d", cnt, td->idx); ++cnt; } ring_buffer_free(&rb); } Test(ringbuffer, test_element_at) { RingBuffer rb; guint32 i; TestData *td; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 0, TRUE); for ( i = 0; i < ring_buffer_count(&rb); i++ ) { td = ring_buffer_element_at(&rb, i); cr_assert_not_null(td, "invalid element, i=%d", i); cr_assert_eq(td->idx, i, "invalid order, actual=%d, expected=%d", td->idx, i); } ring_buffer_free(&rb); } Test(ringbuffer, test_continual_range) { RingBuffer rb; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); assert_continual_range_length_equals(&rb, capacity); ring_buffer_free(&rb); } Test(ringbuffer, test_zero_length_continual_range) { RingBuffer rb; TestData *td; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); td = ring_buffer_element_at(&rb, 0); td->ack = FALSE; assert_continual_range_length_equals(&rb, 0); ring_buffer_free(&rb); } Test(ringbuffer, test_broken_continual_range) { RingBuffer rb; TestData *td; _ringbuffer_init(&rb); _ringbuffer_fill(&rb, capacity, 1, TRUE); td = ring_buffer_element_at(&rb, 13); td->ack = FALSE; assert_continual_range_length_equals(&rb, 13); ring_buffer_free(&rb); } Test(ringbuffer, test_push_after_pop) { } Test(ringbuffer, test_tail) { RingBuffer rb; TestData *td_tail; ring_buffer_alloc(&rb, sizeof(TestData), 103); _ringbuffer_fill2(&rb, 103, 0, TRUE); ring_buffer_pop(&rb); td_tail = ring_buffer_tail(&rb); td_tail->idx = 103; cr_assert_eq(ring_buffer_push(&rb), td_tail, "Push should return last tail."); assert_test_data_idx_range_in(&rb, 1, 103); ring_buffer_free(&rb); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_runid.c000066400000000000000000000100011450431004300215770ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 2013 Viktor Juhasz * Copyright (c) 2013 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/persist_lib.h" #include "lib/run-id.h" #include "lib/apphook.h" #include PersistState *create_persist_state(gchar *persist_file_name); TestSuite(test_run_id, .init = app_startup, .fini = app_shutdown); #define RUN_ID_FIRST 1 PersistState * create_persist_state(gchar *persist_file_name) { return clean_and_create_persist_state_for_test(persist_file_name); }; PersistState * restart_persist_state_with_cancel(PersistState *state, gchar *persist_file_name) { PersistState *new_state; persist_state_cancel(state); persist_state_free(state); new_state = create_persist_state_for_test(persist_file_name); return new_state; }; void destroy_persist_state(PersistState *state) { cancel_and_destroy_persist_state(state); }; Test(test_run_id, first_run__run_id_is_one) { PersistState *state; state = create_persist_state("test_run_id__first_run__run_id_is_one.persist"); run_id_init(state); cr_assert_eq(run_id_get(), RUN_ID_FIRST, "Newly initialized run id is not the first id!"); destroy_persist_state(state); }; Test(test_run_id, second_run__run_id_is_two) { PersistState *state; state = create_persist_state("test_run_id__second_run__run_id_is_two"); run_id_init(state); state = restart_persist_state(state); run_id_init(state); cr_assert_eq(run_id_get(), RUN_ID_FIRST + 1, "Running run_id_init twice is not the second id!"); destroy_persist_state(state); }; Test(test_run_id, second_run_but_with_non_commit__run_id_is_one) { PersistState *state; state = create_persist_state("test_run_id__second_run_but_with_non_commit__run_id_is_one"); run_id_init(state); state = restart_persist_state_with_cancel(state, "test_run_id__second_run_but_with_non_commit__run_id_is_one"); run_id_init(state); cr_assert_eq(run_id_get(), RUN_ID_FIRST, "Not committing persist state still increases run_id"); destroy_persist_state(state); }; Test(test_run_id, is_same_run__differs_when_not_same_run) { PersistState *state; state = create_persist_state("test_run_id__is_same_run__differs_when_not_same_run"); run_id_init(state); int prev_run_id = run_id_get(); state = restart_persist_state(state); run_id_init(state); cr_assert_not(run_id_is_same_run(prev_run_id), "Run_id_is_same_run returned true when the run differs"); destroy_persist_state(state); }; Test(test_run_id, macro_has_the_same_value_as_run_id) { PersistState *state; GString *res = g_string_sized_new(0); state = create_persist_state("test_run_id__macro_has_the_same_value_as_run_id"); run_id_init(state); run_id_append_formatted_id(res); cr_assert_str_eq(res->str, "1", "Run id is formatted incorrectly: %s", res->str); destroy_persist_state(state); g_string_free(res, TRUE); }; Test(test_run_id, macro_is_empty_if_run_id_is_not_inited) { GString *res = g_string_sized_new(0); run_id_deinit(); run_id_append_formatted_id(res); cr_assert_str_eq(res->str, "", "Run id is not empty if it is not inited"); g_string_free(res, TRUE); }; syslog-ng-syslog-ng-4.4.0/lib/tests/test_scratch_buffers.c000066400000000000000000000160251450431004300236350ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "mainloop.h" #include "scratch-buffers.h" #include "stats/stats-registry.h" #include #define ITERATIONS 10 #define DEFAULT_ALLOC_SIZE 256L static void _do_something_with_a_gstring(GString *str) { g_string_assign(str, "foobar"); g_string_append(str, "len"); g_string_truncate(str, 0); } Test(scratch_buffers, alloc_returns_a_gstring_instance) { GString *str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); cr_assert_eq(scratch_buffers_get_local_usage_count(), 1); } Test(scratch_buffers, reclaim_allocations_drops_all_allocs) { for (gint i = 0; i < ITERATIONS; i++) { GString *str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); } cr_assert_eq(scratch_buffers_get_local_usage_count(), ITERATIONS); scratch_buffers_reclaim_allocations(); cr_assert_eq(scratch_buffers_get_local_usage_count(), 0); } Test(scratch_buffers, reclaim_marked_allocs) { ScratchBuffersMarker marker; GString *str; str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); scratch_buffers_mark(&marker); for (gint i = 0; i < ITERATIONS; i++) { str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); } cr_assert_eq(scratch_buffers_get_local_usage_count(), ITERATIONS + 1); scratch_buffers_reclaim_marked(marker); cr_assert_eq(scratch_buffers_get_local_usage_count(), 1); } Test(scratch_buffers, reclaim_up_to_a_marked_alloc) { ScratchBuffersMarker marker; GString *str; str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); str = scratch_buffers_alloc_and_mark(&marker); cr_assert_not_null(str); _do_something_with_a_gstring(str); for (gint i = 0; i < ITERATIONS; i++) { str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); } cr_assert_eq(scratch_buffers_get_local_usage_count(), ITERATIONS + 2); scratch_buffers_reclaim_marked(marker); cr_assert_eq(scratch_buffers_get_local_usage_count(), 1); } Test(scratch_buffers, local_usage_metrics_measure_allocs) { GString *str; str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); cr_assert_eq(scratch_buffers_get_local_usage_count(), 1); cr_assert_eq(scratch_buffers_get_local_allocation_bytes(), DEFAULT_ALLOC_SIZE); str = scratch_buffers_alloc(); cr_assert_not_null(str); _do_something_with_a_gstring(str); cr_assert_eq(scratch_buffers_get_local_usage_count(), 2); cr_assert_eq(scratch_buffers_get_local_allocation_bytes(), 2*DEFAULT_ALLOC_SIZE); } /* not published via the header */ extern StatsCounterItem *stats_scratch_buffers_count; extern StatsCounterItem *stats_scratch_buffers_bytes; Test(scratch_buffers_stats, stats_counters_are_updated) { GString *str; gint allocated_counter = 0; for (gint i = 1; i <= ITERATIONS; i++) { str = scratch_buffers_alloc(); cr_assert_not_null(str); allocated_counter++; /* check through accessor functions */ cr_assert_eq(scratch_buffers_get_local_usage_count(), allocated_counter, "get_local_usage_count() not returning proper value, value=%d, expected=%d", scratch_buffers_get_local_usage_count(), allocated_counter); cr_assert_eq(scratch_buffers_get_local_allocation_bytes(), allocated_counter * DEFAULT_ALLOC_SIZE, "get_local_allocation_bytes() not returning proper value, value=%ld, expected=%ld", scratch_buffers_get_local_allocation_bytes(), allocated_counter * DEFAULT_ALLOC_SIZE); /* check through metrics */ cr_assert_eq(stats_counter_get(stats_scratch_buffers_count), allocated_counter, "Statistic scratch_buffers_count is not updated properly, value=%d, expected=%d", (gint) stats_counter_get(stats_scratch_buffers_count), allocated_counter); /* check if byte counter is updated */ scratch_buffers_update_stats(); cr_assert_eq(stats_counter_get(stats_scratch_buffers_bytes), allocated_counter * DEFAULT_ALLOC_SIZE); /* Check internal state is as expected */ cr_assert_eq(scratch_buffers_get_local_allocation_count(), allocated_counter, "Local allocation count is not updated properly, value=%ld, expected=%d", scratch_buffers_get_local_allocation_count(), allocated_counter); } scratch_buffers_explicit_gc(); cr_assert_eq(scratch_buffers_get_local_usage_count(), 0, "get_local_usage_count() failed to reset to 0, value=%d, expected=%d", scratch_buffers_get_local_usage_count(), 0); cr_assert_eq(scratch_buffers_get_local_allocation_count(), allocated_counter, "Local allocation count is not updated properly, value=%ld, expected=%d", scratch_buffers_get_local_allocation_count(), allocated_counter); cr_assert_eq(stats_counter_get(stats_scratch_buffers_count), allocated_counter, "Statistic scratch_buffers_count should not be changed, value=%d, expected=%d", (gint) stats_counter_get(stats_scratch_buffers_count), allocated_counter); scratch_buffers_allocator_deinit(); cr_assert_eq(stats_counter_get(stats_scratch_buffers_count), 0, "Statistic scratch_buffers_count failed to reset to 0, value=%ld, expected=%d", stats_counter_get(stats_scratch_buffers_count), 0); } static void setup(void) { main_loop_thread_resource_init(); stats_init(); scratch_buffers_global_init(); scratch_buffers_allocator_init(); scratch_buffers_register_stats(); } static void teardown(void) { scratch_buffers_explicit_gc(); scratch_buffers_unregister_stats(); scratch_buffers_allocator_deinit(); scratch_buffers_global_deinit(); stats_destroy(); } static void stats_test_teardown(void) { scratch_buffers_global_deinit(); stats_destroy(); } TestSuite(scratch_buffers, .init = setup, .fini = teardown); TestSuite(scratch_buffers_stats, .init = setup, .fini = stats_test_teardown); syslog-ng-syslog-ng-4.4.0/lib/tests/test_serialize.c000066400000000000000000000034341450431004300224610ustar00rootroot00000000000000/* * Copyright (c) 2007-2009 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "serialize.h" #include "apphook.h" TestSuite(serialize, .init = app_startup, .fini = app_shutdown); Test(serialize, test_serialize) { GString *stream = g_string_new(""); GString *value = g_string_new(""); gchar buf[256]; guint32 num = 0; SerializeArchive *a = serialize_string_archive_new(stream); serialize_write_blob(a, "MAGIC", 5); serialize_write_uint32(a, 0xdeadbeaf); serialize_write_cstring(a, "kismacska", -1); serialize_write_cstring(a, "tarkabarka", 10); serialize_archive_free(a); a = serialize_string_archive_new(stream); serialize_read_blob(a, buf, 5); cr_assert_arr_eq(buf, "MAGIC", 5); serialize_read_uint32(a, &num); cr_assert_eq(num, 0xdeadbeaf); serialize_read_string(a, value); cr_assert_str_eq(value->str, "kismacska"); serialize_read_string(a, value); cr_assert_str_eq(value->str, "tarkabarka"); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_str-utils.c000066400000000000000000000111311450431004300224310ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "str-utils.h" /* this macro defines which strchr() implementation we are testing. It is * extracted as a macro in order to make it easy to switch strchr() * implementation, provided there would be more. */ #define strchr_under_test _strchr_optimized_for_single_char_haystack typedef struct _StrChrTestData { gchar *str; int c; int ofs; } StrChrTestData; ParameterizedTestParameters(str_utils, test_str_utils_is_null) { static StrChrTestData test_data_list[] = { {"", 'x', 0}, {"\0x", 'x', 0}, {"a", 'x', 0}, {"abc", 'x', 0} }; return cr_make_param_array(StrChrTestData, test_data_list, sizeof(test_data_list) / sizeof(test_data_list[0])); } ParameterizedTest(StrChrTestData *test_data, str_utils, test_str_utils_is_null) { cr_assert_null(strchr_under_test(test_data->str, test_data->c), "expected a NULL return"); } ParameterizedTestParameters(str_utils, test_str_utils_find_char) { static StrChrTestData test_data_list[] = { {"", '\0', 0}, {"a", 'a', 0}, {"a", '\0', 1}, {"abc", 'a', 0}, {"abc", 'b', 1}, {"abc", 'c', 2}, {"abc", '\0', 3}, {"0123456789abcdef", '0', 0}, {"0123456789abcdef", '7', 7}, {"0123456789abcdef", 'f', 15} }; return cr_make_param_array(StrChrTestData, test_data_list, sizeof(test_data_list) / sizeof(test_data_list[0])); } ParameterizedTest(StrChrTestData *test_data, str_utils, test_str_utils_find_char) { char *result = strchr_under_test(test_data->str, test_data->c); cr_assert_not_null(result, "expected a non-NULL return"); cr_assert(result - test_data->str <= strlen(test_data->str), "Expected the strchr() return value to point into the input string or the terminating NUL, it points past the NUL"); cr_assert(result >= test_data->str, "Expected the strchr() return value to point into the input string or the terminating NUL, it points before the start of the string"); cr_assert_eq((result - test_data->str), test_data->ofs, "Expected the strchr() return value to point right to the specified offset"); } Test(strsplit, when_tokens_not_limited_find_all_tokens) { gchar **tokens = strsplit(" ABB CCC DDDD 111", ' ', 0); gint tokens_n = g_strv_length(tokens); cr_expect_eq(tokens_n, 4); cr_expect_str_eq(tokens[0], "ABB"); cr_expect_str_eq(tokens[1], "CCC"); cr_expect_str_eq(tokens[2], "DDDD"); cr_expect_str_eq(tokens[3], "111"); cr_expect_null(tokens[4]); g_strfreev(tokens); } Test(strsplit, when_string_without_delim_return_the_string) { gchar **tokens = strsplit("111", ' ', 0); gint tokens_n = g_strv_length(tokens); cr_expect_eq(tokens_n, 1); cr_expect_str_eq(tokens[0], "111"); cr_expect_null(tokens[1]); g_strfreev(tokens); } Test(strsplit, when_empty_string_return_the_empty_string) { gchar **tokens = strsplit("", ' ', 0); gint tokens_n = g_strv_length(tokens); cr_expect_eq(tokens_n, 1); cr_expect_str_eq(tokens[0], ""); cr_expect_null(tokens[1]); g_strfreev(tokens); } Test(strsplit, when_null_str_or_null_delim_return_null) { gchar **tokens = strsplit(NULL, ' ', 0); cr_expect_null(tokens); tokens = strsplit(NULL, '\0', 0); cr_expect_null(tokens); tokens = strsplit("AAA ", '\0', 0); cr_expect_null(tokens); } Test(strsplit, when_tokens_limited_join_remaining_tokens) { gchar **tokens = strsplit(" ABB CCC DDDD 111", ' ', 3); gint tokens_n = g_strv_length(tokens); cr_expect_eq(tokens_n, 3); cr_expect_str_eq(tokens[0], "ABB"); cr_expect_str_eq(tokens[1], "CCC"); cr_expect_str_eq(tokens[2], "DDDD 111"); cr_expect_null(tokens[3]); g_strfreev(tokens); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_str_format.c000066400000000000000000000112211450431004300226430ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2014 Balázs Scheidler * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "str-format.h" Test(test_str_format, hex_string__single_byte__perfect) { gchar expected_output[3] = "40"; gchar output[3]; gchar input[1] = "@"; format_hex_string(input, sizeof(input), output, sizeof(output)); cr_expect_str_eq(output, expected_output, "format_hex_string output does not match!"); } Test(test_str_format, hex_string__two_bytes__perfect) { gchar expected_output[5] = "4041"; gchar output[5]; gchar input[2] = "@A"; format_hex_string(input, sizeof(input), output, sizeof(output)); cr_expect_str_eq(output, expected_output, "format_hex_string output does not match with two bytes!"); } Test(test_str_format, hex_string_with_delimiter__single_byte__perfect) { gchar expected_output[3] = "40"; gchar output[3]; gchar input[1] = "@"; format_hex_string_with_delimiter(input, sizeof(input), output, sizeof(output), ' '); cr_expect_str_eq(output, expected_output, "format_hex_string_with_delimiter output does not match!"); } Test(test_str_format, hex_string_with_delimiter__two_bytes__perfect) { gchar expected_output[6] = "40 41"; gchar output[6]; gchar input[2] = "@A"; format_hex_string_with_delimiter(input, sizeof(input), output, sizeof(output), ' '); cr_expect_str_eq(output, expected_output, "format_hex_string_with_delimiter output does not match in case of two bytes!"); } static void assert_scan_positive_int_in_field_value_equals(const gchar *input, gint field, gint expected_result) { const gchar *buf = input; gint left = strlen(buf); gint result = expected_result + 1; gboolean success = scan_positive_int(&buf, &left, field >= 0 ? field : left, &result); cr_assert(success); if (field == -1 || field == strlen(input)) { cr_assert(*buf == 0); cr_assert(left == 0); } else { cr_assert(buf[0] == input[field]); cr_assert(left == strlen(input) - field); } cr_assert_eq(result, expected_result); } static void assert_scan_positive_int_value_equals(const gchar *input, gint expected_result) { return assert_scan_positive_int_in_field_value_equals(input, -1, expected_result); } static void assert_scan_positive_int_in_field_fails(const gchar *input, gint field) { const gchar *buf = input; gint left = strlen(buf); gint result = 99; gboolean success = scan_positive_int(&buf, &left, field >= 0 ? field : left, &result); cr_assert_not(success); } static void assert_scan_positive_int_fails(const gchar *input) { return assert_scan_positive_int_in_field_fails(input, -1); } Test(test_str_format, scan_positive_int) { assert_scan_positive_int_value_equals("1", 1); assert_scan_positive_int_value_equals("3", 3); assert_scan_positive_int_value_equals("11", 11); assert_scan_positive_int_value_equals("222", 222); assert_scan_positive_int_value_equals(" 3", 3); assert_scan_positive_int_value_equals(" 3", 3); assert_scan_positive_int_value_equals(" 3", 3); assert_scan_positive_int_in_field_value_equals(" 3", 2, 0); assert_scan_positive_int_in_field_value_equals(" 3", 3, 3); assert_scan_positive_int_in_field_value_equals(" 31", 3, 3); assert_scan_positive_int_fails(" 3 "); assert_scan_positive_int_fails(" 0 "); assert_scan_positive_int_fails("a3"); assert_scan_positive_int_fails("3a"); /* string too short for field_length */ assert_scan_positive_int_in_field_fails("31", 3); /* non-number in front */ assert_scan_positive_int_in_field_fails("a31", 3); assert_scan_positive_int_in_field_fails("aaaaaaaa31", 3); assert_scan_positive_int_in_field_fails("31a", 3); assert_scan_positive_int_in_field_fails("31aaaaaaaa", 3); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_string_list.c000066400000000000000000000060611450431004300230320ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "string-list.h" Test(string_list, test_string_array_to_list_converts_to_an_equivalent_glist) { const gchar *arr[] = { "foo", "bar", "baz", NULL }; GList *l; l = string_array_to_list(arr); cr_assert_eq(g_list_length(l), 3, "converted list is not the expected length"); cr_assert_str_eq(l->data, "foo", "first element is expected to be foo"); cr_assert_str_eq(l->next->data, "bar", "second element is expected to be bar"); cr_assert_str_eq(l->next->next->data, "baz", "third element is expected to be baz"); string_list_free(l); } Test(string_list, test_string_varargs_to_list_converts_to_an_equivalent_glist) { GList *l; l = string_vargs_to_list("foo", "bar", "baz", NULL); cr_assert_eq(g_list_length(l), 3, "converted list is not the expected length"); cr_assert_str_eq(l->data, "foo", "first element is expected to be foo"); cr_assert_str_eq(l->next->data, "bar", "second element is expected to be bar"); cr_assert_str_eq(l->next->next->data, "baz", "third element is expected to be baz"); string_list_free(l); } Test(string_list, test_clone_string_array_duplicates_elements_while_leaving_token_values_intact) { const gchar *arr[] = { "foo", "bar", "baz", NULL }; GList *l, *l2; l = string_array_to_list(arr); l = g_list_append(l, GUINT_TO_POINTER(1)); l = g_list_append(l, GUINT_TO_POINTER(2)); l2 = string_list_clone(l); string_list_free(l); cr_assert_eq(g_list_length(l2), 5, "converted list is not the expected length"); cr_assert_str_eq(l2->data, "foo", "first element is expected to be foo"); cr_assert_str_eq(l2->next->data, "bar", "second element is expected to be bar"); cr_assert_str_eq(l2->next->next->data, "baz", "third element is expected to be baz"); cr_assert_eq(GPOINTER_TO_UINT(l2->next->next->next->data), 1, "fourth element is expected to be a token, with a value of 1"); cr_assert_eq(GPOINTER_TO_UINT(l2->next->next->next->next->data), 2, "fifth element is expected to be a token, with a value of 2"); string_list_free(l2); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_thread_wakeup.c000066400000000000000000000103161450431004300233120ustar00rootroot00000000000000/* * Copyright (c) 2010-2011 Balabit * Copyright (c) 2010-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include gboolean thread_exit = FALSE; gboolean thread_started; GCond thread_startup; GMutex thread_lock; pthread_t thread_handle; void sigusr1_handler(int signo) { } static void setup_sigusr1(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); /* NOTE: this has to be a real signal handler as SIG_IGN will not interrupt the accept call below */ sa.sa_handler = sigusr1_handler; sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); } static void signal_startup(void) { thread_handle = pthread_self(); g_mutex_lock(&thread_lock); thread_started = TRUE; g_cond_signal(&thread_startup); g_mutex_unlock(&thread_lock); } static gboolean create_test_thread(GThreadFunc thread_func, gpointer data) { GThread *t; struct timespec nsleep; thread_exit = FALSE; thread_started = FALSE; t = g_thread_new(NULL, thread_func, data); g_mutex_lock(&thread_lock); while (!thread_started) g_cond_wait(&thread_startup, &thread_lock); g_mutex_unlock(&thread_lock); nsleep.tv_sec = 0; nsleep.tv_nsec = 1e6; nanosleep(&nsleep, NULL); thread_exit = TRUE; pthread_kill(thread_handle, SIGUSR1); return (g_thread_join(t) != NULL); } int sock; gpointer accept_thread_func(gpointer args) { struct sockaddr_un peer; gint new_sock; gpointer result = NULL; setup_sigusr1(); signal_startup(); while (1) { gint err; socklen_t peer_size = sizeof(peer); new_sock = accept(sock, (struct sockaddr *) &peer, &peer_size); err = errno; if (new_sock >= 0) close(new_sock); if (thread_exit) { fprintf(stderr, "accept woken up, errno=%s\n", g_strerror(err)); result = (gpointer) 0x1; break; } } close(sock); return result; } int test_accept_wakeup(void) { struct sockaddr_un s; unlink("almafa"); sock = socket(PF_UNIX, SOCK_STREAM, 0); s.sun_family = AF_UNIX; strcpy(s.sun_path, "almafa"); cr_assert_not(bind(sock, (struct sockaddr *) &s, sizeof(s)), "error binding socket: %s", strerror(errno)); cr_assert_not(listen(sock, 255), "error in listen(): %s", strerror(errno)); return create_test_thread(accept_thread_func, NULL); } gpointer read_thread_func(gpointer args) { gint *pair = (gint *) args; gpointer result = NULL; setup_sigusr1(); signal_startup(); while (1) { gint err; gchar buf[1024]; gint count G_GNUC_UNUSED = read(pair[1], buf, sizeof(buf)); err = errno; if (thread_exit) { fprintf(stderr, "read woken up, errno=%s\n", g_strerror(err)); result = (gpointer) 0x1; break; } } close(pair[0]); close(pair[1]); return result; } int test_read_wakeup(void) { gint pair[2]; socketpair(PF_UNIX, SOCK_STREAM, 0, pair); return create_test_thread(read_thread_func, pair); } Test(test_thread_wakeup, testcase) { g_mutex_init(&thread_lock); g_cond_init(&thread_startup); cr_assert(test_accept_wakeup()); cr_assert(test_read_wakeup()); g_mutex_clear(&thread_lock); g_cond_clear(&thread_startup); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_userdb.c000066400000000000000000000045341450431004300217600ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "userdb.h" #include Test(user_db, resolve_user_root) { gint uid; /* On OSX the root user is disabled by default */ #ifndef __APPLE__ cr_assert(resolve_user("root", &uid)); cr_assert_eq(uid, 0); #endif cr_assert(resolve_user("0", &uid)); cr_assert_eq(uid, 0); } Test(user_db, resolve_non_existing_user) { gint uid; cr_assert_not(resolve_user("nemtudom", &uid)); cr_assert_not(resolve_user("", &uid)); } Test(user_db, resolve_group) { gint gid; cr_assert(resolve_group("0", &gid)); cr_assert_eq(gid, 0); cr_assert(resolve_group("sys", &gid)); cr_assert(resolve_group("-1", &gid)); cr_assert_eq(gid, -1); } Test(user_db, resolve_non_existing_group) { gint gid; cr_assert_not(resolve_group("nincsily", &gid)); cr_assert_not(resolve_group("", &gid)); } /* On OSX the root user is disabled by default */ #ifndef __APPLE__ Test(user_db, resolve_user_group) { gint uid; gint gid; char str[] = "root:sys"; struct group *sys_group = getgrnam("sys"); cr_assert(sys_group); gint expected_gid = sys_group->gr_gid; cr_assert(resolve_user_group(str, &uid, &gid)); cr_assert_eq(uid, 0); cr_assert_eq(gid, expected_gid); } #endif Test(user_db, resolve_none_existing_user_group) { gint uid; gint gid; char str[] = "nemtudom:nincsily"; cr_assert_not(resolve_user_group(str, &uid, &gid)); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_utf8utils.c000066400000000000000000000075761450431004300224540ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "utf8utils.h" typedef struct _StringValueList { const gchar *str; const gchar *expected_escaped_str; const gchar *unsafe_chars; gssize str_len; } StringValueList; ParameterizedTestParameters(test_utf8utils, test_escaped_binary) { static StringValueList string_value_list[] = { {"", "", NULL, -1}, {"\n", "\\n", NULL, -1}, {"\b \f \n \r \t", "\\b \\f \\n \\r \\t", NULL, -1}, {"\\", "\\\\", NULL, -1}, {"árvíztűrőtükörfúrógép", "árvíztűrőtükörfúrógép", NULL, -1}, {"árvíztűrőtükörfúrógép\n", "árvíztűrőtükörfúrógép\\n", NULL, -1}, {"\x41", "A", NULL, -1}, {"\x7", "\\x07", NULL, -1}, {"\xad", "\\xad", NULL, -1}, {"Á\xadÉ", "Á\\xadÉ", NULL, -1}, {"\xc3\x00\xc1""", "\\xc3", NULL, -1}, {"\"text\"", "\\\"text\\\"", "\"", -1}, {"\"text\"", "\\\"te\\xt\\\"", "\"x", -1}, {"\xc3""\xa1 non zero terminated", "\\xc3", NULL, 1}, {"\xc3""\xa1 non zero terminated", "á", NULL, 2}, }; return cr_make_param_array(StringValueList, string_value_list, sizeof(string_value_list) / sizeof(string_value_list[0])); } ParameterizedTest(StringValueList *string_value_list, test_utf8utils, test_escaped_binary) { GString *escaped_str = g_string_sized_new(64); append_unsafe_utf8_as_escaped_binary(escaped_str, string_value_list->str, string_value_list->str_len, string_value_list->unsafe_chars); cr_assert_str_eq(escaped_str->str, string_value_list->expected_escaped_str, "Escaped UTF-8 string is not as expected"); g_string_free(escaped_str, TRUE); } ParameterizedTestParameters(test_utf8utils, test_escaped_text) { static StringValueList string_value_list[] = { {"", "", NULL, -1}, {"\n", "\\n", NULL, -1}, {"\b \f \n \r \t", "\\b \\f \\n \\r \\t", NULL, -1}, {"\\", "\\\\", NULL, -1}, {"árvíztűrőtükörfúrógép", "árvíztűrőtükörfúrógép", NULL, -1}, {"árvíztűrőtükörfúrógép\n", "árvíztűrőtükörfúrógép\\n", NULL, -1}, {"\x41", "A", NULL, -1}, {"\x7", "\\x07", NULL, -1}, {"\xad", "\\\\xad", NULL, -1}, {"Á\xadÉ", "Á\\\\xadÉ", NULL, -1}, {"\"text\"", "\\\"text\\\"", "\"", -1}, {"\"text\"", "\\\"te\\xt\\\"", "\"x", -1}, }; return cr_make_param_array(StringValueList, string_value_list, sizeof(string_value_list) / sizeof(string_value_list[0])); } ParameterizedTest(StringValueList *string_value_list, test_utf8utils, test_escaped_text) { gchar *escaped_str = convert_unsafe_utf8_to_escaped_text(string_value_list->str, string_value_list->str_len, string_value_list->unsafe_chars); cr_assert_str_eq(escaped_str, string_value_list->expected_escaped_str, "Escaped UTF-8 string is not as expected"); g_free(escaped_str); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_window_size_counter.c000066400000000000000000000062471450431004300245770ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "window-size-counter.h" Test(test_window_size_counter, suspend_resume) { WindowSizeCounter c; gboolean suspended = FALSE; window_size_counter_set(&c, 10); cr_expect_not(window_size_counter_suspended(&c)); window_size_counter_sub(&c, 10, &suspended); cr_expect_not(suspended); cr_expect(window_size_counter_suspended(&c)); window_size_counter_add(&c, 10, &suspended); cr_expect(suspended); cr_expect_not(window_size_counter_suspended(&c)); window_size_counter_suspend(&c); cr_expect(window_size_counter_suspended(&c)); gsize val = window_size_counter_get(&c, &suspended); cr_expect(suspended); cr_expect_eq(val, 10); window_size_counter_add(&c, 1, &suspended); cr_expect_eq(window_size_counter_get(&c, &suspended), 11); window_size_counter_resume(&c); cr_expect_not(window_size_counter_suspended(&c)); } Test(test_window_size_counter, negative_value) { WindowSizeCounter c; gboolean suspended = FALSE; window_size_counter_set(&c, -1); gint v = (gint)window_size_counter_get(&c, &suspended); cr_assert_eq(v, -1); } Test(test_window_size_counter, suspend_resume_multiple_times) { WindowSizeCounter c; window_size_counter_set(&c, window_size_counter_get_max()); window_size_counter_resume(&c); cr_expect_not(window_size_counter_suspended(&c)); gboolean suspended; cr_expect_eq(window_size_counter_get(&c, &suspended), window_size_counter_get_max()); cr_expect_not(suspended); window_size_counter_resume(&c); cr_expect_not(window_size_counter_suspended(&c)); cr_expect_eq(window_size_counter_get(&c, &suspended), window_size_counter_get_max()); cr_expect_not(suspended); window_size_counter_suspend(&c); cr_expect(window_size_counter_suspended(&c)); cr_expect_eq(window_size_counter_get(&c, &suspended), window_size_counter_get_max()); cr_expect(suspended); window_size_counter_suspend(&c); cr_expect(window_size_counter_suspended(&c)); cr_expect_eq(window_size_counter_get(&c, &suspended), window_size_counter_get_max()); cr_expect(suspended); window_size_counter_resume(&c); cr_expect_not(window_size_counter_suspended(&c)); cr_expect_eq(window_size_counter_get(&c, &suspended), window_size_counter_get_max()); cr_expect_not(suspended); } syslog-ng-syslog-ng-4.4.0/lib/tests/test_zone.c000066400000000000000000000562071450431004300214530ustar00rootroot00000000000000/* * Copyright (c) 2005-2015 Balabit * Copyright (c) 2005-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include "timeutils/zoneinfo.h" #include "timeutils/unixtime.h" #include "timeutils/format.h" #include #include #include typedef struct _TimezoneOffsetTestCase { const gchar *time_zone; time_t utc; long expected_offset; } TimezoneOffsetTestCase; typedef struct _TimezoneTestCase { const time_t stamp_to_test; const gchar *time_zone; } TimezoneTestCase; typedef struct _TimestampFormatTestCase { gint format; glong zone_offset; gint frac_digits; gchar *expected_format; } TimestampFormatTestCase; void set_time_zone(const gchar *time_zone) { setenv("TZ", time_zone, TRUE); invalidate_timeutils_cache(); } int time_zone_exists(const char *time_zone) { TimeZoneInfo *info; set_time_zone(time_zone); info = time_zone_info_new(time_zone); if (info) { time_zone_info_free(info); return TRUE; } return FALSE; } void test_time_zone(const time_t stamp_to_test, const char *time_zone) { TimeZoneInfo *info; time_t offset, expected_offset; set_time_zone(time_zone); info = time_zone_info_new(time_zone); offset = time_zone_info_get_offset(info, stamp_to_test); expected_offset = get_local_timezone_ofs(stamp_to_test); cr_assert_eq(difftime(offset, expected_offset), 0.0, "unixtimestamp: %ld TimeZoneName (%s) localtime offset(%ld), timezone file offset(%ld)\n", (glong) stamp_to_test, time_zone, (glong) expected_offset, (glong) offset); time_zone_info_free(info); } void assert_time_zone(TimezoneTestCase c) { if (!time_zone_exists(c.time_zone)) { printf("SKIP: %s\n", c.time_zone); return; } test_time_zone(c.stamp_to_test, c.time_zone); test_time_zone(c.stamp_to_test - 6*30*24*60*60, c.time_zone); test_time_zone(c.stamp_to_test + 6*30*24*6, c.time_zone); } void assert_time_zone_offset(TimezoneOffsetTestCase c) { long offset; set_time_zone(c.time_zone); offset = get_local_timezone_ofs(c.utc); cr_assert_eq(offset, c.expected_offset, "Timezone offset mismatch: zone: %s, %ld, expected %ld\n", c.time_zone, offset, c.expected_offset); } void assert_timestamp_format(GString *target, UnixTime *stamp, TimestampFormatTestCase c) { format_unix_time(stamp, target, c.format, c.zone_offset, c.frac_digits); cr_assert_str_eq(target->str, c.expected_format, "Actual: %s, Expected: %s", target->str, c.expected_format); } TestSuite(zone, .init = app_startup, .fini = app_shutdown); Test(zone, test_time_zone_offset) { TimezoneOffsetTestCase test_cases[] = { /* 2005-10-14 21:47:37 CEST, dst enabled */ {"MET-1METDST", 1129319257, 7200}, /* 2005-11-14 10:10:00 CET, dst disabled */ {"MET-1METDST", 1131959400, 3600}, /* 2005-10-14 21:47:37 GMT, no DST */ {"GMT", 1129319257, 0}, /* 2005-11-14 10:10:00 GMT, no DST */ {"GMT", 1131959400, 0}, /* 2005-04-03 01:30:00 ESD, DST disabled */ {"EST5EDT", 1112509800, -5*3600}, /* 2005-04-03 01:59:59 ESD, DST disabled */ {"EST5EDT", 1112511599, -5*3600}, /* 2005-04-03 03:00:00 EDT, DST enabled */ {"EST5EDT", 1112511600, -4*3600}, /* 2005-04-03 03:00:01 EDT, DST enabled */ {"EST5EDT", 1112511601, -4*3600}, /* 2005-10-30 01:59:59 EDT, DST enabled */ {"EST5EDT", 1130651999, -4*3600}, /* 2005-10-30 01:00:00 EST, DST disabled */ {"EST5EDT", 1130652000, -5*3600}, /* 2007-03-11 01:00:00 EST, DST disabled */ {"EST5EDT", 1173592800, -5*3600}, /* 2007-03-11 01:59:59 EST, DST disabled */ {"EST5EDT", 1173596399, -5*3600}, /* 2007-03-11 03:00:00 EST, DST enabled */ {"EST5EDT", 1173596400, -4*3600}, /* 2007-11-04 01:59:59 EST, DST enabled */ {"EST5EDT", 1194155999, -4*3600}, /* 2007-11-04 01:00:00 EST, DST disabled */ {"EST5EDT", 1194156000, -5*3600}, /* Oct 31 01:59:59 2004 (EST) +1000 */ {"Australia/Victoria", 1099151999, 10*3600}, /* Oct 31 03:00:00 2004 (EST) +1100 */ {"Australia/Victoria", 1099152000, 11*3600}, /* Mar 27 02:59:59 2005 (EST) +1100 */ {"Australia/Victoria", 1111852799, 11*3600}, /* Mar 27 02:00:00 2005 (EST) +1000 */ {"Australia/Victoria", 1111852800, 10*3600}, /* Oct 2 01:59:59 2004 (NZT) +1200 */ {"NZ", 1128175199, 12*3600}, /* Oct 2 03:00:00 2004 (NZDT) +1300 */ {"NZ", 1128175200, 13*3600}, /* Mar 20 02:59:59 2005 (NZDT) +1300 */ {"NZ", 1111240799, 13*3600}, /* Mar 20 02:00:00 2005 (NZT) +1200 */ {"NZ", 1111240800, 12*3600}, }; gint i, nr_of_cases; nr_of_cases = sizeof(test_cases) / sizeof(test_cases[0]); for (i = 0; i < nr_of_cases; i++) assert_time_zone_offset(test_cases[i]); } Test(zone, test_time_zones) { time_t now = time(NULL); TimezoneTestCase test_cases[] = { {now, "America/Louisville"}, {now, "Hongkong"}, {now, "Europe/Budapest"}, {1288486800, "Europe/Budapest"}, {1288486860, "Europe/Budapest"}, {1288486740, "Europe/Budapest"}, {1288486800-1800, "Europe/Budapest"}, {1288486800+1800, "Europe/Budapest"}, {1288486800-3600, "Europe/Budapest"}, {1288486800+3600, "Europe/Budapest"}, {1288486800-3601, "Europe/Budapest"}, {1288486800+3601, "Europe/Budapest"}, {now, "Asia/Kuala_Lumpur"}, {now, "CST6CDT"}, {now, "US/Pacific"}, {now, "US/Indiana-Starke"}, {now, "US/Samoa"}, {now, "US/Arizona"}, {now, "US/Aleutian"}, {now, "US/Michigan"}, {now, "US/Alaska"}, {now, "US/Central"}, {now, "US/Hawaii"}, {now, "US/East-Indiana"}, {now, "US/Eastern"}, {now, "US/Mountain"}, {now, "Pacific/Noumea"}, {now, "Pacific/Samoa"}, {now, "Pacific/Apia"}, {now, "Pacific/Auckland"}, {now, "Pacific/Fakaofo"}, {now, "Pacific/Saipan"}, {now, "Pacific/Easter"}, {now, "Pacific/Norfolk"}, {now, "Pacific/Kosrae"}, {now, "Pacific/Tarawa"}, {now, "Pacific/Tahiti"}, {now, "Pacific/Pago_Pago"}, {now, "Pacific/Majuro"}, {now, "Pacific/Guam"}, {now, "Pacific/Ponape"}, {now, "Pacific/Tongatapu"}, {now, "Pacific/Funafuti"}, {now, "Pacific/Wallis"}, {now, "Pacific/Efate"}, {now, "Pacific/Marquesas"}, {now, "Pacific/Enderbury"}, {now, "Pacific/Pitcairn"}, {now, "Pacific/Yap"}, {now, "Pacific/Wake"}, {now, "Pacific/Johnston"}, {now, "Pacific/Kwajalein"}, {now, "Pacific/Chatham"}, {now, "Pacific/Gambier"}, {now, "Pacific/Galapagos"}, {now, "Pacific/Kiritimati"}, {now, "Pacific/Honolulu"}, {now, "Pacific/Truk"}, {now, "Pacific/Midway"}, {now, "Pacific/Fiji"}, {now, "Pacific/Rarotonga"}, {now, "Pacific/Guadalcanal"}, {now, "Pacific/Nauru"}, {now, "Pacific/Palau"}, {now, "Pacific/Port_Moresby"}, {now, "Pacific/Niue"}, {now, "GMT"}, {now, "Hongkong"}, {now, "ROK"}, {now, "Navajo"}, {now, "ROC"}, {now, "WET"}, {now, "posixrules"}, {now, "CET"}, {now, "MET"}, {now, "MST"}, {now, "Turkey"}, {now, "Zulu"}, {now, "GMT+0"}, {now, "Canada/Saskatchewan"}, {now, "Canada/Pacific"}, {now, "Canada/Yukon"}, {now, "Canada/East-Saskatchewan"}, {now, "Canada/Newfoundland"}, {now, "Canada/Central"}, {now, "Canada/Eastern"}, {now, "Canada/Atlantic"}, {now, "Canada/Mountain"}, {now, "Singapore"}, {now, "UCT"}, {now, "Poland"}, {now, "Chile/Continental"}, {now, "Chile/EasterIsland"}, {now, "Portugal"}, {now, "Egypt"}, {now, "Japan"}, {now, "Iran"}, {now, "EET"}, {now, "Europe/Oslo"}, {now, "Europe/Bratislava"}, {now, "Europe/Gibraltar"}, {now, "Europe/Skopje"}, {now, "Europe/Simferopol"}, {now, "Europe/Zurich"}, {now, "Europe/Vienna"}, {now, "Europe/Paris"}, {now, "Europe/Jersey"}, {now, "Europe/Tallinn"}, {now, "Europe/Madrid"}, {now, "Europe/Volgograd"}, {now, "Europe/Zaporozhye"}, {now, "Europe/Mariehamn"}, {now, "Europe/Vaduz"}, {now, "Europe/Moscow"}, {now, "Europe/Stockholm"}, {now, "Europe/Minsk"}, {now, "Europe/Andorra"}, {now, "Europe/Istanbul"}, {now, "Europe/Tiraspol"}, {now, "Europe/Podgorica"}, {now, "Europe/Bucharest"}, {now, "Europe/Ljubljana"}, {now, "Europe/Brussels"}, {now, "Europe/Amsterdam"}, {now, "Europe/Riga"}, {now, "Europe/Tirane"}, {now, "Europe/Berlin"}, {now, "Europe/Guernsey"}, {now, "Europe/Warsaw"}, {now, "Europe/Vatican"}, {now, "Europe/Malta"}, {now, "Europe/Nicosia"}, {now, "Europe/Budapest"}, {now, "Europe/Kaliningrad"}, {now, "Europe/Sarajevo"}, {now, "Europe/Isle_of_Man"}, {now, "Europe/Rome"}, {now, "Europe/London"}, {now, "Europe/Vilnius"}, {now, "Europe/Samara"}, {now, "Europe/Belfast"}, {now, "Europe/Athens"}, {now, "Europe/Copenhagen"}, {now, "Europe/Belgrade"}, {now, "Europe/Sofia"}, {now, "Europe/San_Marino"}, {now, "Europe/Helsinki"}, {now, "Europe/Uzhgorod"}, {now, "Europe/Monaco"}, {now, "Europe/Prague"}, {now, "Europe/Zagreb"}, {now, "Europe/Lisbon"}, {now, "Europe/Chisinau"}, {now, "Europe/Dublin"}, {now, "Europe/Luxembourg"}, {now, "Europe/Kiev"}, {now, "Jamaica"}, {now, "Indian/Chagos"}, {now, "Indian/Comoro"}, {now, "Indian/Mauritius"}, {now, "Indian/Mayotte"}, {now, "Indian/Kerguelen"}, {now, "Indian/Maldives"}, {now, "Indian/Antananarivo"}, {now, "Indian/Mahe"}, {now, "Indian/Cocos"}, {now, "Indian/Christmas"}, {now, "Indian/Reunion"}, {now, "Africa/Accra"}, {now, "Africa/Lubumbashi"}, {now, "Africa/Bangui"}, {now, "Africa/Asmara"}, {now, "Africa/Freetown"}, {now, "Africa/Mbabane"}, {now, "Africa/Djibouti"}, {now, "Africa/Ndjamena"}, {now, "Africa/Porto-Novo"}, {now, "Africa/Nouakchott"}, {now, "Africa/Brazzaville"}, {now, "Africa/Tunis"}, {now, "Africa/Dar_es_Salaam"}, {now, "Africa/Lusaka"}, {now, "Africa/Banjul"}, {now, "Africa/Sao_Tome"}, {now, "Africa/Monrovia"}, {now, "Africa/Lagos"}, {now, "Africa/Conakry"}, {now, "Africa/Tripoli"}, {now, "Africa/Algiers"}, {now, "Africa/Casablanca"}, {now, "Africa/Lome"}, {now, "Africa/Bamako"}, {now, "Africa/Nairobi"}, {now, "Africa/Douala"}, {now, "Africa/Addis_Ababa"}, {now, "Africa/El_Aaiun"}, {now, "Africa/Ceuta"}, {now, "Africa/Harare"}, {now, "Africa/Libreville"}, {now, "Africa/Johannesburg"}, {now, "Africa/Timbuktu"}, {now, "Africa/Niamey"}, {now, "Africa/Windhoek"}, {now, "Africa/Bissau"}, {now, "Africa/Maputo"}, {now, "Africa/Kigali"}, {now, "Africa/Dakar"}, {now, "Africa/Ouagadougou"}, {now, "Africa/Gaborone"}, {now, "Africa/Khartoum"}, {now, "Africa/Bujumbura"}, {now, "Africa/Luanda"}, {now, "Africa/Malabo"}, {now, "Africa/Asmera"}, {now, "Africa/Maseru"}, {now, "Africa/Abidjan"}, {now, "Africa/Kinshasa"}, {now, "Africa/Blantyre"}, {now, "Africa/Cairo"}, {now, "Africa/Kampala"}, {now, "Africa/Mogadishu"}, {now, "Universal"}, {now, "EST"}, {now, "Greenwich"}, {now, "Eire"}, {now, "Asia/Qatar"}, {now, "Asia/Makassar"}, {now, "Asia/Colombo"}, {now, "Asia/Chungking"}, {now, "Asia/Macau"}, {now, "Asia/Choibalsan"}, {now, "Asia/Rangoon"}, {now, "Asia/Harbin"}, {now, "Asia/Yerevan"}, {now, "Asia/Brunei"}, {now, "Asia/Omsk"}, {now, "Asia/Chongqing"}, {now, "Asia/Tbilisi"}, {now, "Asia/Tehran"}, {now, "Asia/Manila"}, {now, "Asia/Yakutsk"}, {now, "Asia/Qyzylorda"}, {now, "Asia/Dhaka"}, {now, "Asia/Singapore"}, {now, "Asia/Jakarta"}, {now, "Asia/Novosibirsk"}, {now, "Asia/Saigon"}, {now, "Asia/Krasnoyarsk"}, {now, "Asia/Kabul"}, {now, "Asia/Bahrain"}, {now, "Asia/Urumqi"}, {now, "Asia/Thimbu"}, {now, "Asia/Ulan_Bator"}, {now, "Asia/Taipei"}, {now, "Asia/Tashkent"}, {now, "Asia/Dacca"}, {now, "Asia/Aqtau"}, {now, "Asia/Seoul"}, {now, "Asia/Istanbul"}, {now, "Asia/Tel_Aviv"}, {now, "Asia/Almaty"}, {now, "Asia/Phnom_Penh"}, {now, "Asia/Baku"}, {now, "Asia/Anadyr"}, {now, "Asia/Aqtobe"}, {now, "Asia/Kuwait"}, {now, "Asia/Irkutsk"}, {now, "Asia/Ulaanbaatar"}, {now, "Asia/Tokyo"}, {now, "Asia/Gaza"}, {now, "Asia/Yekaterinburg"}, {now, "Asia/Nicosia"}, {now, "Asia/Jayapura"}, {now, "Asia/Shanghai"}, {now, "Asia/Pyongyang"}, {now, "Asia/Macao"}, {now, "Asia/Dushanbe"}, {now, "Asia/Kuching"}, {now, "Asia/Vientiane"}, {now, "Asia/Riyadh"}, {now, "Asia/Dili"}, {now, "Asia/Samarkand"}, {now, "Asia/Ashkhabad"}, {now, "Asia/Calcutta"}, {now, "Asia/Hong_Kong"}, {now, "Asia/Sakhalin"}, {now, "Asia/Beirut"}, {now, "Asia/Damascus"}, {now, "Asia/Katmandu"}, {now, "Asia/Jerusalem"}, {now, "Asia/Vladivostok"}, {now, "Asia/Kamchatka"}, {now, "Asia/Dubai"}, {now, "Asia/Kashgar"}, {now, "Asia/Ashgabat"}, {now, "Asia/Amman"}, {now, "Asia/Karachi"}, {now, "Asia/Bangkok"}, {now, "Asia/Oral"}, {now, "Asia/Thimphu"}, {now, "Asia/Bishkek"}, {now, "Asia/Baghdad"}, {now, "Asia/Kuala_Lumpur"}, {now, "Asia/Pontianak"}, {now, "Asia/Ujung_Pandang"}, {now, "Asia/Muscat"}, {now, "Asia/Aden"}, {now, "Asia/Hovd"}, {now, "Asia/Magadan"}, {now, "EST5EDT"}, {now, "PST8PDT"}, {now, "Atlantic/Bermuda"}, {now, "Atlantic/St_Helena"}, {now, "Atlantic/Cape_Verde"}, {now, "Atlantic/Stanley"}, {now, "Atlantic/Azores"}, {now, "Atlantic/Jan_Mayen"}, {now, "Atlantic/Reykjavik"}, {now, "Atlantic/Madeira"}, {now, "Atlantic/Canary"}, {now, "Atlantic/Faeroe"}, {now, "Atlantic/Faroe"}, {now, "Atlantic/South_Georgia"}, {now, "Kwajalein"}, {now, "UTC"}, {now, "GMT-0"}, {now, "MST7MDT"}, {now, "GB-Eire"}, {now, "PRC"}, {now, "Arctic/Longyearbyen"}, {now, "Cuba"}, {now, "Israel"}, {now, "Etc/GMT-3"}, {now, "Etc/GMT+1"}, {now, "Etc/GMT-5"}, {now, "Etc/GMT"}, {now, "Etc/GMT-13"}, {now, "Etc/GMT-1"}, {now, "Etc/GMT-9"}, {now, "Etc/Zulu"}, {now, "Etc/GMT+0"}, {now, "Etc/UCT"}, {now, "Etc/GMT+12"}, {now, "Etc/GMT+9"}, {now, "Etc/GMT-6"}, {now, "Etc/Universal"}, {now, "Etc/GMT-2"}, {now, "Etc/Greenwich"}, {now, "Etc/GMT+3"}, {now, "Etc/GMT+8"}, {now, "Etc/UTC"}, {now, "Etc/GMT-0"}, {now, "Etc/GMT-14"}, {now, "Etc/GMT+10"}, {now, "Etc/GMT+4"}, {now, "Etc/GMT+5"}, {now, "Etc/GMT-12"}, {now, "Etc/GMT-8"}, {now, "Etc/GMT+7"}, {now, "Etc/GMT-11"}, {now, "Etc/GMT+6"}, {now, "Etc/GMT0"}, {now, "Etc/GMT-7"}, {now, "Etc/GMT+11"}, {now, "Etc/GMT-4"}, {now, "Etc/GMT+2"}, {now, "Etc/GMT-10"}, {now, "HST"}, {now, "Iceland"}, {now, "Mexico/BajaNorte"}, {now, "Mexico/BajaSur"}, {now, "Mexico/General"}, {now, "Antarctica/Davis"}, {now, "Antarctica/DumontDUrville"}, {now, "Antarctica/Syowa"}, {now, "Antarctica/Palmer"}, {now, "Antarctica/Casey"}, {now, "Antarctica/Rothera"}, {now, "Antarctica/Mawson"}, {now, "Antarctica/McMurdo"}, {now, "Antarctica/South_Pole"}, {now, "Antarctica/Vostok"}, {now, "America/Curacao"}, {now, "America/St_Lucia"}, {now, "America/Managua"}, {now, "America/Lima"}, {now, "America/Nipigon"}, {now, "America/Cayenne"}, {now, "America/Detroit"}, {now, "America/Kentucky/Louisville"}, {now, "America/Kentucky/Monticello"}, {now, "America/Belem"}, {now, "America/Jujuy"}, {now, "America/Godthab"}, {now, "America/Guatemala"}, {now, "America/Atka"}, {now, "America/Montreal"}, {now, "America/Resolute"}, {now, "America/Thunder_Bay"}, {now, "America/North_Dakota/New_Salem"}, {now, "America/North_Dakota/Center"}, {now, "America/Panama"}, {now, "America/Los_Angeles"}, {now, "America/Whitehorse"}, {now, "America/Santiago"}, {now, "America/Iqaluit"}, {now, "America/Dawson"}, {now, "America/Juneau"}, {now, "America/Thule"}, {now, "America/Fortaleza"}, {now, "America/Montevideo"}, {now, "America/Tegucigalpa"}, {now, "America/Port-au-Prince"}, {now, "America/Guadeloupe"}, {now, "America/Coral_Harbour"}, {now, "America/Monterrey"}, {now, "America/Anguilla"}, {now, "America/Antigua"}, {now, "America/Campo_Grande"}, {now, "America/Buenos_Aires"}, {now, "America/Maceio"}, {now, "America/New_York"}, {now, "America/Puerto_Rico"}, {now, "America/Noronha"}, {now, "America/Sao_Paulo"}, {now, "America/Cancun"}, {now, "America/Aruba"}, {now, "America/Yellowknife"}, {now, "America/Knox_IN"}, {now, "America/Halifax"}, {now, "America/Grand_Turk"}, {now, "America/Vancouver"}, {now, "America/Bogota"}, {now, "America/Santo_Domingo"}, {now, "America/Tortola"}, {now, "America/Blanc-Sablon"}, {now, "America/St_Thomas"}, {now, "America/Scoresbysund"}, {now, "America/Jamaica"}, {now, "America/El_Salvador"}, {now, "America/Montserrat"}, {now, "America/Martinique"}, {now, "America/Nassau"}, {now, "America/Indianapolis"}, {now, "America/Pangnirtung"}, {now, "America/Port_of_Spain"}, {now, "America/Mexico_City"}, {now, "America/Denver"}, {now, "America/Dominica"}, {now, "America/Eirunepe"}, {now, "America/Atikokan"}, {now, "America/Glace_Bay"}, {now, "America/Rainy_River"}, {now, "America/St_Barthelemy"}, {now, "America/Miquelon"}, {now, "America/Indiana/Vevay"}, {now, "America/Indiana/Vincennes"}, {now, "America/Indiana/Marengo"}, {now, "America/Indiana/Petersburg"}, {now, "America/Indiana/Tell_City"}, {now, "America/Indiana/Knox"}, {now, "America/Indiana/Indianapolis"}, {now, "America/Indiana/Winamac"}, {now, "America/Menominee"}, {now, "America/Porto_Velho"}, {now, "America/Phoenix"}, {now, "America/Argentina/San_Juan"}, {now, "America/Argentina/Jujuy"}, {now, "America/Argentina/Ushuaia"}, {now, "America/Argentina/Buenos_Aires"}, {now, "America/Argentina/La_Rioja"}, {now, "America/Argentina/ComodRivadavia"}, {now, "America/Argentina/Tucuman"}, {now, "America/Argentina/Rio_Gallegos"}, {now, "America/Argentina/Mendoza"}, {now, "America/Argentina/Cordoba"}, {now, "America/Argentina/Catamarca"}, {now, "America/Dawson_Creek"}, {now, "America/Merida"}, {now, "America/Moncton"}, {now, "America/Goose_Bay"}, {now, "America/Grenada"}, {now, "America/Barbados"}, {now, "America/Tijuana"}, {now, "America/Regina"}, {now, "America/Ensenada"}, {now, "America/Louisville"}, {now, "America/Edmonton"}, {now, "America/Bahia"}, {now, "America/Nome"}, {now, "America/Guayaquil"}, {now, "America/La_Paz"}, {now, "America/Costa_Rica"}, {now, "America/Mazatlan"}, {now, "America/Havana"}, {now, "America/Marigot"}, {now, "America/Mendoza"}, {now, "America/Virgin"}, {now, "America/Manaus"}, {now, "America/Rosario"}, {now, "America/Boa_Vista"}, {now, "America/Winnipeg"}, {now, "America/Paramaribo"}, {now, "America/Danmarkshavn"}, {now, "America/Caracas"}, {now, "America/Swift_Current"}, {now, "America/St_Johns"}, {now, "America/Araguaina"}, {now, "America/Adak"}, {now, "America/Cordoba"}, {now, "America/Fort_Wayne"}, {now, "America/Catamarca"}, {now, "America/Recife"}, {now, "America/Toronto"}, {now, "America/Anchorage"}, {now, "America/St_Vincent"}, {now, "America/St_Kitts"}, {now, "America/Chihuahua"}, {now, "America/Cayman"}, {now, "America/Belize"}, {now, "America/Cambridge_Bay"}, {now, "America/Cuiaba"}, {now, "America/Chicago"}, {now, "America/Guyana"}, {now, "America/Inuvik"}, {now, "America/Asuncion"}, {now, "America/Porto_Acre"}, {now, "America/Hermosillo"}, {now, "America/Shiprock"}, {now, "America/Rio_Branco"}, {now, "America/Yakutat"}, {now, "America/Rankin_Inlet"}, {now, "America/Boise"}, {now, "Brazil/West"}, {now, "Brazil/Acre"}, {now, "Brazil/East"}, {now, "Brazil/DeNoronha"}, {now, "GMT0"}, {now, "Libya"}, {now, "W-SU"}, {now, "NZ-CHAT"}, {now, "Factory"}, {now, "GB"}, {now, "Australia/West"}, {now, "Australia/Canberra"}, {now, "Australia/Broken_Hill"}, {now, "Australia/Eucla"}, {now, "Australia/Currie"}, {now, "Australia/South"}, {now, "Australia/Lindeman"}, {now, "Australia/Hobart"}, {now, "Australia/Perth"}, {now, "Australia/Yancowinna"}, {now, "Australia/Victoria"}, {now, "Australia/Sydney"}, {now, "Australia/North"}, {now, "Australia/Adelaide"}, {now, "Australia/ACT"}, {now, "Australia/Melbourne"}, {now, "Australia/Tasmania"}, {now, "Australia/Darwin"}, {now, "Australia/Brisbane"}, {now, "Australia/LHI"}, {now, "Australia/NSW"}, {now, "Australia/Queensland"}, {now, "Australia/Lord_Howe"}, {now, "NZ"}, }; gint i, nr_of_cases; nr_of_cases = sizeof(test_cases) / sizeof (test_cases[0]); for (i = 0; i < nr_of_cases; i++) assert_time_zone(test_cases[i]); } Test(zone, test_logstamp_format) { UnixTime stamp; GString *target = g_string_sized_new(32); TimestampFormatTestCase test_cases[] = { /* formats */ {TS_FMT_BSD, 3600, 3, "Oct 14 20:47:37.123"}, {TS_FMT_ISO, 3600, 3, "2005-10-14T20:47:37.123+01:00"}, {TS_FMT_FULL, 3600, 3, "2005 Oct 14 20:47:37.123"}, {TS_FMT_UNIX, 3600, 3, "1129319257.123"}, /* time_zone offsets */ {TS_FMT_ISO, 5400, 3, "2005-10-14T21:17:37.123+01:30"}, {TS_FMT_ISO, -3600, 3, "2005-10-14T18:47:37.123-01:00"}, {TS_FMT_ISO, -5400, 3, "2005-10-14T18:17:37.123-01:30"}, }; TimestampFormatTestCase boundary_test_case = {TS_FMT_ISO, -1, 0, "1970-01-01T00:00:00+00:00"}; gint i, nr_of_cases; stamp.ut_sec = 1129319257; stamp.ut_usec = 123456; stamp.ut_gmtoff = 0; nr_of_cases = sizeof(test_cases) / sizeof(test_cases[0]); for (i = 0; i < nr_of_cases; i++) assert_timestamp_format(target, &stamp, test_cases[i]); // boundary testing stamp.ut_sec = 0; stamp.ut_usec = 0; assert_timestamp_format(target, &stamp, boundary_test_case); g_string_free(target, TRUE); } syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/000077500000000000000000000000001450431004300222115ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/include-test/000077500000000000000000000000001450431004300246115ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/include-test/bar.conf000066400000000000000000000000041450431004300262160ustar00rootroot00000000000000bar syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/include-test/baz.conf000066400000000000000000000000041450431004300262260ustar00rootroot00000000000000baz syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/include-test/foo.conf000066400000000000000000000000041450431004300262350ustar00rootroot00000000000000foo syslog-ng-syslog-ng-4.4.0/lib/tests/testdata-lexer/include-test/invalid~include~file.conf000066400000000000000000000000201450431004300316760ustar00rootroot00000000000000invalid include syslog-ng-syslog-ng-4.4.0/lib/thread-utils.h000066400000000000000000000030711450431004300207000ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef THREAD_UTILS_H_INCLUDED #define THREAD_UTILS_H_INCLUDED #include "syslog-ng.h" #include #ifdef _WIN32 typedef DWORD ThreadId; #else typedef pthread_t ThreadId; #endif static inline ThreadId get_thread_id(void) { #ifndef _WIN32 return pthread_self(); #else return GetCurrentThreadId(); #endif } static inline int threads_equal(ThreadId thread_a, ThreadId thread_b) { #ifndef _WIN32 return pthread_equal(thread_a, thread_b); #else return thread_a == thread_b; #endif } static inline void thread_cancel(ThreadId tid) { #ifndef _WIN32 pthread_cancel(tid); #else TerminateThread(tid, 0); #endif } #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/000077500000000000000000000000001450431004300201405ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/timeutils/CMakeLists.txt000066400000000000000000000012751450431004300227050ustar00rootroot00000000000000set(TIMEUTILS_HEADERS timeutils/cache.h timeutils/conv.h timeutils/scan-timestamp.h timeutils/format.h timeutils/misc.h timeutils/names.h timeutils/timeutils.h timeutils/unixtime.h timeutils/zonecache.h timeutils/zonedb.h timeutils/zoneinfo.h timeutils/wallclocktime.h PARENT_SCOPE) set(TIMEUTILS_SOURCES timeutils/cache.c timeutils/conv.c timeutils/scan-timestamp.c timeutils/format.c timeutils/misc.c timeutils/names.c timeutils/timeutils.c timeutils/unixtime.c timeutils/zonecache.c timeutils/zonedb.c timeutils/zoneinfo.c timeutils/wallclocktime.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/timeutils/Makefile.am000066400000000000000000000015371450431004300222020ustar00rootroot00000000000000timeutilsincludedir = ${pkgincludedir}/timeutils EXTRA_DIST += lib/timeutils/CMakeLists.txt timeutilsinclude_HEADERS = \ lib/timeutils/cache.h \ lib/timeutils/conv.h \ lib/timeutils/scan-timestamp.h\ lib/timeutils/format.h \ lib/timeutils/misc.h \ lib/timeutils/names.h \ lib/timeutils/timeutils.h \ lib/timeutils/unixtime.h \ lib/timeutils/zonecache.h \ lib/timeutils/zonedb.h \ lib/timeutils/zoneinfo.h \ lib/timeutils/wallclocktime.h timeutils_sources = \ lib/timeutils/scan-timestamp.c \ lib/timeutils/cache.c \ lib/timeutils/conv.c \ lib/timeutils/format.c \ lib/timeutils/misc.c \ lib/timeutils/names.c \ lib/timeutils/timeutils.c \ lib/timeutils/unixtime.c \ lib/timeutils/zonecache.c \ lib/timeutils/zonedb.c \ lib/timeutils/zoneinfo.c \ lib/timeutils/wallclocktime.c include lib/timeutils/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/timeutils/cache.c000066400000000000000000000214651450431004300213570ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/cache.h" #include "timeutils/zonecache.h" #include "tls-support.h" #include #include #include typedef struct _TimeCache { time_t when; struct tm tm; } TimeCache; TLS_BLOCK_START { GTimeVal current_time_value; struct iv_task invalidate_time_task; gint local_gencounter; struct { struct { Cache *zones; } tzinfo; struct { TimeCache buckets[64]; } localtime; struct { TimeCache buckets[64]; } gmtime; struct { struct tm key; struct tm mutated_key; time_t value; } mktime; } cache; struct { glong timezone; gchar *tzname[2]; } state; } TLS_BLOCK_END; /* this indicates that a test program is faking the current time */ static gboolean faking_time; #define current_time_value __tls_deref(current_time_value) #define invalidate_time_task __tls_deref(invalidate_time_task) #define local_gencounter __tls_deref(local_gencounter) #define cache __tls_deref(cache) #define state __tls_deref(state) static struct { /* generation counter for the timezone cache. To invalidate the thread * specific cache, just increase this using g_atomic_int_inc(). Any * threads would check if this was changed to see if they need to reset * their own cache. */ gint cache_gencounter; /* copy of the timezone related global variables that might be changed by * _any_ localtime() call in any libraries that we use. We save this * information right after a tzset() call, which happens at reload, with * our threads not running, i.e. at a race free point. Then later on, * threads copy these into their own cache in a thread synchronized * manner. */ glong timezone; gchar *tzname[2]; } global_state; static GMutex localtime_lock; static glong _get_system_tzofs(void) { #ifdef SYSLOG_NG_HAVE_TIMEZONE /* global variable */ return timezone; #elif SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF time_t t = time(NULL); struct tm *tm; /* we can't call the cached APIs because the localtime_lock is held, but * this is not performance critical. */ tm = localtime(&t); return -tm->tm_gmtoff; #else return -1; #endif } /* NOTE: this function assumes that localtime_lock() is held */ static void _capture_timezone_state_from_variables(void) { g_free(global_state.tzname[0]); g_free(global_state.tzname[1]); /* these are fetching from the tzname & timezone globals. We cannot use * those variables directly as they are managed by the libc functions, and * which can be changed in other threads in any localtime() (non _r) call * in any of the code of syslog-ng/dependent libraries. * * This function is only invoked when the global timezone state should be * static, as we are either just starting up or being reloaded. **/ global_state.timezone = _get_system_tzofs(); global_state.tzname[0] = g_strdup(tzname[0]); global_state.tzname[1] = g_strdup(tzname[1]); } /* NOTE: copy the contents of the global cache to thread local variables */ static void _copy_timezone_state_to_locals(void) { g_free(state.tzname[0]); g_free(state.tzname[1]); state.tzname[0] = g_strdup(global_state.tzname[0]); state.tzname[1] = g_strdup(global_state.tzname[1]); state.timezone = global_state.timezone; } static void _clean_timeutils_cache(void) { memset(&cache.gmtime.buckets, 0, sizeof(cache.gmtime.buckets)); memset(&cache.localtime.buckets, 0, sizeof(cache.localtime.buckets)); memset(&cache.mktime.key, 0, sizeof(cache.mktime.key)); if (cache.tzinfo.zones) cache_clear(cache.tzinfo.zones); g_free(state.tzname[0]); state.tzname[0] = NULL; g_free(state.tzname[1]); state.tzname[1] = NULL; } static void _validate_timeutils_cache(void) { gint gencounter = g_atomic_int_get(&global_state.cache_gencounter); if (G_UNLIKELY(gencounter != local_gencounter)) { _clean_timeutils_cache(); g_mutex_lock(&localtime_lock); _copy_timezone_state_to_locals(); g_mutex_unlock(&localtime_lock); local_gencounter = gencounter; } } void timeutils_cache_deinit(void) { _clean_timeutils_cache(); } void invalidate_timeutils_cache(void) { g_mutex_lock(&localtime_lock); tzset(); _capture_timezone_state_from_variables(); g_mutex_unlock(&localtime_lock); g_atomic_int_inc(&global_state.cache_gencounter); } void invalidate_cached_time(void) { current_time_value.tv_sec = 0; } void set_cached_time(GTimeVal *timeval) { current_time_value = *timeval; faking_time = TRUE; } /* * this shuld replace the g_get_current_time and the g_source_get_current_time calls in the main thread * (log_msg_init, afinter_postpone_mark) */ void cached_g_current_time(GTimeVal *result) { if (current_time_value.tv_sec == 0) { g_get_current_time(¤t_time_value); } *result = current_time_value; if (G_UNLIKELY(faking_time)) return; else if (iv_inited()) { if (invalidate_time_task.handler == NULL) { IV_TASK_INIT(&invalidate_time_task); invalidate_time_task.handler = (void (*)(void *)) invalidate_cached_time; } if (!iv_task_registered(&invalidate_time_task)) iv_task_register(&invalidate_time_task); } else { invalidate_cached_time(); } } time_t cached_g_current_time_sec(void) { GTimeVal now; cached_g_current_time(&now); return now.tv_sec; } time_t cached_mktime(struct tm *tm) { _validate_timeutils_cache(); if (G_LIKELY(tm->tm_sec == cache.mktime.key.tm_sec && tm->tm_min == cache.mktime.key.tm_min && tm->tm_hour == cache.mktime.key.tm_hour && tm->tm_mday == cache.mktime.key.tm_mday && tm->tm_mon == cache.mktime.key.tm_mon && tm->tm_year == cache.mktime.key.tm_year && tm->tm_isdst == cache.mktime.key.tm_isdst)) { *tm = cache.mktime.mutated_key; return cache.mktime.value; } /* we need to store the incoming value first, as mktime() might change the * fields in *tm, for instance in the daylight saving transition hour */ cache.mktime.key = *tm; cache.mktime.value = mktime(tm); /* the result we yield consists of both the return value and the mutated * key, so we need to save both */ cache.mktime.mutated_key = *tm; return cache.mktime.value; } void cached_localtime(time_t *when, struct tm *tm) { _validate_timeutils_cache(); guchar i = *when & 0x3F; if (G_LIKELY(*when == cache.localtime.buckets[i].when)) { *tm = cache.localtime.buckets[i].tm; return; } else { #ifdef SYSLOG_NG_HAVE_LOCALTIME_R localtime_r(when, tm); #else struct tm *ltm; g_mutex_lock(&localtime_lock); ltm = localtime(when); *tm = *ltm; g_mutex_unlock(&localtime_lock); #endif cache.localtime.buckets[i].tm = *tm; cache.localtime.buckets[i].when = *when; } } void cached_gmtime(time_t *when, struct tm *tm) { _validate_timeutils_cache(); guchar i = *when & 0x3F; if (G_LIKELY(*when == cache.gmtime.buckets[i].when && *when != 0)) { *tm = cache.gmtime.buckets[i].tm; return; } else { #ifdef SYSLOG_NG_HAVE_GMTIME_R gmtime_r(when, tm); #else struct tm *ltm; g_mutex_lock(&localtime_lock); ltm = gmtime(when); *tm = *ltm; g_mutex_unlock(&localtime_lock); #endif cache.gmtime.buckets[i].tm = *tm; cache.gmtime.buckets[i].when = *when; } } TimeZoneInfo * cached_get_time_zone_info(const gchar *tz) { if (!cache.tzinfo.zones) cache.tzinfo.zones = time_zone_cache_new(); TimeZoneInfo *result = cache_lookup(cache.tzinfo.zones, tz); return result; } glong cached_get_system_tzofs(void) { _validate_timeutils_cache(); return state.timezone; } const gchar *const * cached_get_system_tznames(void) { _validate_timeutils_cache(); return (const gchar *const *) &state.tzname; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/cache.h000066400000000000000000000040771450431004300213640ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_CACHE_H_INCLUDED #define TIMEUTILS_CACHE_H_INCLUDED #include "timeutils/wallclocktime.h" #include "timeutils/zoneinfo.h" /* the thread safe variant of the global "timezone" */ glong cached_get_system_tzofs(void); /* the thread safe variant of the global "tzname" */ const gchar *const *cached_get_system_tznames(void); time_t cached_mktime(struct tm *tm); void cached_localtime(time_t *when, struct tm *tm); void cached_gmtime(time_t *when, struct tm *tm); void timeutils_cache_deinit(void); static inline void cached_localtime_wct(time_t *when, WallClockTime *wct) { cached_localtime(when, &wct->tm); } static inline time_t cached_mktime_wct(WallClockTime *wct) { return cached_mktime(&wct->tm); } static inline void cached_gmtime_wct(time_t *when, WallClockTime *wct) { cached_gmtime(when, &wct->tm); } void invalidate_cached_time(void); void set_cached_time(GTimeVal *timeval); void cached_g_current_time(GTimeVal *result); time_t cached_g_current_time_sec(void); TimeZoneInfo *cached_get_time_zone_info(const gchar *tz); void invalidate_timeutils_cache(void); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/conv.c000066400000000000000000000074441450431004300212620ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/conv.h" #include "timeutils/cache.h" #include "timeutils/misc.h" void convert_wall_clock_time_to_unix_time(const WallClockTime *src, UnixTime *dst) { WallClockTime work_wct = *src; convert_and_normalize_wall_clock_time_to_unix_time(&work_wct, dst); } void convert_wall_clock_time_to_unix_time_with_tz_hint(const WallClockTime *src, UnixTime *dst, long gmtoff_hint) { WallClockTime work_wct = *src; convert_and_normalize_wall_clock_time_to_unix_time_with_tz_hint(&work_wct, dst, gmtoff_hint); } void convert_and_normalize_wall_clock_time_to_unix_time(WallClockTime *src, UnixTime *dst) { convert_and_normalize_wall_clock_time_to_unix_time_with_tz_hint(src, dst, -1); } /* hint the timezone value if it is not present in the wct struct, e.g. the * timestamp takes precedence, but as an additional information the caller * can supply its best idea. this maps nicely to the source-side * time-zone() value, which is only used in case an incoming timestamp does * not have the timestamp value. */ void convert_and_normalize_wall_clock_time_to_unix_time_with_tz_hint(WallClockTime *src, UnixTime *dst, long gmtoff_hint) { /* usec is just copied over, doesn't change timezone or anything */ dst->ut_usec = src->wct_usec; /* determine target gmtoff if it's coming from the timestamp or from the hint */ gint target_gmtoff = src->wct_gmtoff; if (target_gmtoff == -1) target_gmtoff = gmtoff_hint; /* FIRST: We convert the timestamp as it was in our local time zone. */ gint unnormalized_hour = src->wct_hour; src->wct_isdst = -1; dst->ut_sec = cached_mktime_wct(src); gint normalized_hour = src->wct_hour; /* SECOND: adjust ut_sec as if we converted it according to our timezone. */ gint local_gmtoff = get_local_timezone_ofs(dst->ut_sec); if (target_gmtoff == -1) { target_gmtoff = local_gmtoff; } dst->ut_sec = dst->ut_sec + local_gmtoff - (normalized_hour - unnormalized_hour) * 3600 - target_gmtoff; dst->ut_gmtoff = target_gmtoff; src->wct_gmtoff = dst->ut_gmtoff; src->wct_hour = unnormalized_hour; } void convert_unix_time_to_wall_clock_time(const UnixTime *src, WallClockTime *dst) { convert_unix_time_to_wall_clock_time_with_tz_override(src, dst, -1); } /* the timezone information overrides what is present in the timestamp, e.g. * it will _convert_ the timestamp to a destination timezone */ void convert_unix_time_to_wall_clock_time_with_tz_override(const UnixTime *src, WallClockTime *dst, gint gmtoff_override) { gint gmtoff = gmtoff_override; if (gmtoff == -1) gmtoff = src->ut_gmtoff; if (gmtoff == -1) gmtoff = get_local_timezone_ofs(src->ut_sec); time_t t = src->ut_sec + gmtoff; cached_gmtime_wct(&t, dst); dst->wct_gmtoff = gmtoff; dst->wct_zone = NULL; dst->wct_usec = src->ut_usec; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/conv.h000066400000000000000000000044761450431004300212710ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_CONV_H_INCLUDED #define TIMEUTILS_CONV_H_INCLUDED #include "timeutils/unixtime.h" #include "timeutils/wallclocktime.h" /* * The algorithm that takes a WallClockTime and converts it to UnixTime * mutates the WallClockTime, contrary to intuitions (this behavior is * inherited from mktime, which we use in the implementation). We therefore * introduce a second set of set_from() functions, so we have two sets: * * 1) one that takes a const WallClockTime * 2) one that mutates its argument * * The second one is qualified with the word "normalized". */ void convert_wall_clock_time_to_unix_time(const WallClockTime *src, UnixTime *dst); void convert_wall_clock_time_to_unix_time_with_tz_hint(const WallClockTime *src, UnixTime *dst, long gmtoff_hint); /* these change the WallClockTime while setting unix time, just as mktime() would */ void convert_and_normalize_wall_clock_time_to_unix_time(WallClockTime *src, UnixTime *dst); void convert_and_normalize_wall_clock_time_to_unix_time_with_tz_hint(WallClockTime *src, UnixTime *dst, long gmtoff_hint); void convert_unix_time_to_wall_clock_time(const UnixTime *src, WallClockTime *dst); void convert_unix_time_to_wall_clock_time_with_tz_override(const UnixTime *src, WallClockTime *dst, gint gmtoff_override); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/format.c000066400000000000000000000124341450431004300216000ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/format.h" #include "timeutils/cache.h" #include "timeutils/names.h" #include "timeutils/conv.h" #include "str-format.h" static void _append_frac_digits(glong usecs, GString *target, gint frac_digits) { usecs = usecs % 1000000; if (frac_digits > 0) { gulong x; g_string_append_c(target, '.'); for (x = 100000; frac_digits && x; x = x / 10) { g_string_append_c(target, (usecs / x) + '0'); usecs = usecs % x; frac_digits--; } } } void append_format_zone_info(GString *target, glong gmtoff) { g_string_append_c(target, gmtoff < 0 ? '-' : '+'); format_uint32_padded(target, 2, '0', 10, (gmtoff < 0 ? -gmtoff : gmtoff) / 3600); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, ((gmtoff < 0 ? -gmtoff : gmtoff) % 3600) / 60); } void append_format_unix_time(const UnixTime *ut, GString *target, gint ts_format, glong zone_offset, gint frac_digits) { WallClockTime wct = WALL_CLOCK_TIME_INIT; if (ts_format == TS_FMT_UNIX) { format_uint32_padded(target, 0, 0, 10, (int) ut->ut_sec); _append_frac_digits(ut->ut_usec, target, frac_digits); } else { convert_unix_time_to_wall_clock_time_with_tz_override(ut, &wct, zone_offset); append_format_wall_clock_time(&wct, target, ts_format, frac_digits); } } void format_unix_time(const UnixTime *stamp, GString *target, gint ts_format, glong zone_offset, gint frac_digits) { g_string_truncate(target, 0); append_format_unix_time(stamp, target, ts_format, zone_offset, frac_digits); } /** * unix_time_format: * @stamp: Timestamp to format * @target: Target storage for formatted timestamp * @ts_format: Specifies basic timestamp format (TS_FMT_BSD, TS_FMT_ISO) * @zone_offset: Specifies custom zone offset if @tz_convert == TZ_CNV_CUSTOM * * Emits the formatted version of @stamp into @target as specified by * @ts_format and @tz_convert. **/ void append_format_wall_clock_time(const WallClockTime *wct, GString *target, gint ts_format, gint frac_digits) { UnixTime ut = UNIX_TIME_INIT; switch (ts_format) { case TS_FMT_BSD: g_string_append_len(target, month_names_abbrev[wct->wct_mon], MONTH_NAME_ABBREV_LEN); g_string_append_c(target, ' '); format_uint32_padded(target, 2, ' ', 10, wct->wct_mday); g_string_append_c(target, ' '); format_uint32_padded(target, 2, '0', 10, wct->wct_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_sec); _append_frac_digits(wct->wct_usec, target, frac_digits); break; case TS_FMT_ISO: format_uint32_padded(target, 0, 0, 10, wct->wct_year + 1900); g_string_append_c(target, '-'); format_uint32_padded(target, 2, '0', 10, wct->wct_mon + 1); g_string_append_c(target, '-'); format_uint32_padded(target, 2, '0', 10, wct->wct_mday); g_string_append_c(target, 'T'); format_uint32_padded(target, 2, '0', 10, wct->wct_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_sec); _append_frac_digits(wct->wct_usec, target, frac_digits); append_format_zone_info(target, wct->wct_gmtoff); break; case TS_FMT_FULL: format_uint32_padded(target, 0, 0, 10, wct->wct_year + 1900); g_string_append_c(target, ' '); g_string_append_len(target, month_names_abbrev[wct->wct_mon], MONTH_NAME_ABBREV_LEN); g_string_append_c(target, ' '); format_uint32_padded(target, 2, ' ', 10, wct->wct_mday); g_string_append_c(target, ' '); format_uint32_padded(target, 2, '0', 10, wct->wct_hour); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_min); g_string_append_c(target, ':'); format_uint32_padded(target, 2, '0', 10, wct->wct_sec); _append_frac_digits(wct->wct_usec, target, frac_digits); break; case TS_FMT_UNIX: convert_wall_clock_time_to_unix_time(wct, &ut); append_format_unix_time(&ut, target, TS_FMT_UNIX, wct->wct_gmtoff, frac_digits); break; default: g_assert_not_reached(); break; } } syslog-ng-syslog-ng-4.4.0/lib/timeutils/format.h000066400000000000000000000035641450431004300216110ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_FORMAT_H_INCLUDED #define TIMEUTILS_FORMAT_H_INCLUDED #include "unixtime.h" #include "wallclocktime.h" /* timestamp formats */ #define TS_FMT_BSD 0 #define TS_FMT_ISO 1 #define TS_FMT_FULL 2 #define TS_FMT_UNIX 3 void format_unix_time(const UnixTime *stamp, GString *target, gint ts_format, glong zone_offset, gint frac_digits); void append_format_unix_time(const UnixTime *stamp, GString *target, gint ts_format, glong zone_offset, gint frac_digits); void format_wall_clock_time(const WallClockTime *stamp, GString *target, gint ts_format, glong zone_offset, gint frac_digits); void append_format_wall_clock_time(const WallClockTime *stamp, GString *target, gint ts_format, gint frac_digits); void append_format_zone_info(GString *target, glong gmtoff); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/misc.c000066400000000000000000000076111450431004300212440ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat/time.h" #include "timeutils/misc.h" #include "timeutils/cache.h" #include "messages.h" #include #include /** * get_local_timezone_ofs: * @when: time in UTC * * Return the zone offset (measured in seconds) of @when expressed in local * time. The function also takes care about daylight saving. **/ long get_local_timezone_ofs(time_t when) { #ifdef SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF struct tm ltm; cached_localtime(&when, <m); return ltm.tm_gmtoff; #else struct tm gtm; struct tm ltm; long tzoff; cached_localtime(&when, <m); cached_gmtime(&when, >m); tzoff = (ltm.tm_hour - gtm.tm_hour) * 3600; tzoff += (ltm.tm_min - gtm.tm_min) * 60; tzoff += ltm.tm_sec - gtm.tm_sec; if (tzoff > 0 && (ltm.tm_year < gtm.tm_year || ltm.tm_mon < gtm.tm_mon || ltm.tm_mday < gtm.tm_mday)) tzoff -= 86400; else if (tzoff < 0 && (ltm.tm_year > gtm.tm_year || ltm.tm_mon > gtm.tm_mon || ltm.tm_mday > gtm.tm_mday)) tzoff += 86400; return tzoff; #endif /* SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF */ } /** * check_nanosleep: * * Check if nanosleep() is accurate enough for sub-millisecond sleeping. If * it is not good enough, we're skipping the minor sleeps in LogReader to * balance the cost of returning to the main loop (e.g. we're always going * to return to the main loop, instead of trying to wait for the writer). **/ gboolean check_nanosleep(void) { struct timespec start, stop, sleep_amount; glong diff; gint attempts; for (attempts = 0; attempts < 3; attempts++) { clock_gettime(CLOCK_MONOTONIC, &start); sleep_amount.tv_sec = 0; /* 0.1 msec */ sleep_amount.tv_nsec = 1e5; while (nanosleep(&sleep_amount, &sleep_amount) < 0) { if (errno != EINTR) return FALSE; } clock_gettime(CLOCK_MONOTONIC, &stop); diff = timespec_diff_nsec(&stop, &start); if (diff < 5e5) return TRUE; } return FALSE; } /** * g_time_val_diff: * @t1: time value t1 * @t2: time value t2 * * Calculates the time difference between t1 and t2 in microseconds. * The result is positive if t1 is later than t2. * * Returns: * Time difference in microseconds */ glong g_time_val_diff(GTimeVal *t1, GTimeVal *t2) { g_assert(t1); g_assert(t2); return (t1->tv_sec - t2->tv_sec) * G_USEC_PER_SEC + (t1->tv_usec - t2->tv_usec); } void timespec_add_msec(struct timespec *ts, glong msec) { ts->tv_sec += msec / 1000; msec = msec % 1000; ts->tv_nsec += (glong) (msec * 1e6); if (ts->tv_nsec > 1e9) { ts->tv_nsec -= (glong) 1e9; ts->tv_sec++; } } glong timespec_diff_msec(const struct timespec *t1, const struct timespec *t2) { return ((t1->tv_sec - t2->tv_sec) * 1000 + (t1->tv_nsec - t2->tv_nsec) / 1000000); } glong timespec_diff_nsec(struct timespec *t1, struct timespec *t2) { return (glong)((t1->tv_sec - t2->tv_sec) * 1e9) + (t1->tv_nsec - t2->tv_nsec); } syslog-ng-syslog-ng-4.4.0/lib/timeutils/misc.h000066400000000000000000000026361450431004300212530ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_MISC_H_INCLUDED #define TIMEUTILS_MISC_H_INCLUDED #include "syslog-ng.h" long get_local_timezone_ofs(time_t when); gboolean check_nanosleep(void); glong g_time_val_diff(GTimeVal *t1, GTimeVal *t2); void timespec_add_msec(struct timespec *ts, glong msec); glong timespec_diff_msec(const struct timespec *t1, const struct timespec *t2); glong timespec_diff_nsec(struct timespec *t1, struct timespec *t2); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/names.c000066400000000000000000000027271450431004300214170ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ const char *month_names_abbrev[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; const char *month_names[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; const char *weekday_names_abbrev[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; const char *weekday_names[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; syslog-ng-syslog-ng-4.4.0/lib/timeutils/names.h000066400000000000000000000024311450431004300214140ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_NAMES_H_INCLUDED #define TIMEUTILS_NAMES_H_INCLUDED #define MONTH_NAME_ABBREV_LEN 3 #define WEEKDAY_NAME_ABBREV_LEN 3 extern const char *month_names_abbrev[]; extern const char *month_names[]; extern const char *weekday_names_abbrev[]; extern const char *weekday_names[]; #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/scan-timestamp.c000066400000000000000000000327411450431004300232400ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/scan-timestamp.h" #include "timeutils/wallclocktime.h" #include "str-format.h" #include "timeutils/cache.h" #include #include gboolean scan_day_abbrev(const gchar **buf, gint *left, gint *wday) { *wday = -1; const gsize abbrev_length = 3; if (*left < abbrev_length) return FALSE; switch (**buf) { case 'S': if (strncasecmp(*buf, "Sun", abbrev_length) == 0) *wday = 0; else if (strncasecmp(*buf, "Sat", abbrev_length) == 0) *wday = 6; else return FALSE; break; case 'M': if (strncasecmp(*buf, "Mon", abbrev_length) == 0) *wday = 1; else return FALSE; break; case 'T': if (strncasecmp(*buf, "Tue", abbrev_length) == 0) *wday = 2; else if (strncasecmp(*buf, "Thu", abbrev_length) == 0) *wday = 4; else return FALSE; break; case 'W': if (strncasecmp(*buf, "Wed", abbrev_length) == 0) *wday = 3; else return FALSE; break; case 'F': if (strncasecmp(*buf, "Fri", abbrev_length) == 0) *wday = 5; else return FALSE; break; default: return FALSE; } (*buf) += abbrev_length; (*left) -= abbrev_length; return TRUE; } gboolean scan_month_abbrev(const gchar **buf, gint *left, gint *mon) { *mon = -1; const gsize abbrev_length = 3; if (*left < abbrev_length) return FALSE; switch (**buf) { case 'J': if (strncasecmp(*buf, "Jan", abbrev_length) == 0) *mon = 0; else if (strncasecmp(*buf, "Jun", abbrev_length) == 0) *mon = 5; else if (strncasecmp(*buf, "Jul", abbrev_length) == 0) *mon = 6; else return FALSE; break; case 'F': if (strncasecmp(*buf, "Feb", abbrev_length) == 0) *mon = 1; else return FALSE; break; case 'M': if (strncasecmp(*buf, "Mar", abbrev_length) == 0) *mon = 2; else if (strncasecmp(*buf, "May", abbrev_length) == 0) *mon = 4; else return FALSE; break; case 'A': if (strncasecmp(*buf, "Apr", abbrev_length) == 0) *mon = 3; else if (strncasecmp(*buf, "Aug", abbrev_length) == 0) *mon = 7; else return FALSE; break; case 'S': if (strncasecmp(*buf, "Sep", abbrev_length) == 0) *mon = 8; else return FALSE; break; case 'O': if (strncasecmp(*buf, "Oct", abbrev_length) == 0) *mon = 9; else return FALSE; break; case 'N': if (strncasecmp(*buf, "Nov", abbrev_length) == 0) *mon = 10; else return FALSE; break; case 'D': if (strncasecmp(*buf, "Dec", abbrev_length) == 0) *mon = 11; else return FALSE; break; default: return FALSE; } (*buf) += abbrev_length; (*left) -= abbrev_length; return TRUE; } /******************************************************************************* * RFC 3164 timestamp, expected format: "MMM DD HH:MM:SS" ... *******************************************************************************/ static gboolean __is_bsd_rfc_3164(const guchar *src, guint32 left) { return left >= 15 && src[3] == ' ' && src[6] == ' ' && src[9] == ':' && src[12] == ':'; } gboolean scan_bsd_timestamp(const gchar **buf, gint *left, WallClockTime *wct) { if (!scan_month_abbrev(buf, left, &wct->wct_mon) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_mday) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_hour) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_min) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_sec)) return FALSE; return TRUE; } /******************************************************************************* * ISO timestamp as specified in RFC5424, expected format "YYYY-MM-DDTHH:MM:SS" *******************************************************************************/ static gboolean __is_iso_stamp(const gchar *stamp, gint length) { return (length >= 19 && stamp[4] == '-' && stamp[7] == '-' && (stamp[10] == 'T' || stamp[10] == ' ') && stamp[13] == ':' && stamp[16] == ':' ); } gboolean scan_iso_timestamp(const gchar **buf, gint *left, WallClockTime *wct) { if (!scan_positive_int(buf, left, 4, &wct->wct_year) || !scan_expect_char(buf, left, '-') || !scan_positive_int(buf, left, 2, &wct->wct_mon) || !scan_expect_char(buf, left, '-') || !scan_positive_int(buf, left, 2, &wct->wct_mday) || !(scan_expect_char(buf, left, 'T') || scan_expect_char(buf, left, ' ')) || !scan_positive_int(buf, left, 2, &wct->wct_hour) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_min) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_sec)) return FALSE; wct->wct_year -= 1900; wct->wct_mon -= 1; return TRUE; } /******************************************************************************* * Cisco modified RFC3164 timestamp, expected format: * "MMM DD YYYY HH:MM:SS:" * "MMM DD YYYY HH:MM:SS " *******************************************************************************/ static gboolean __is_bsd_pix_or_asa(const guchar *src, guint32 left) { return (left >= 21 && src[3] == ' ' && src[6] == ' ' && src[11] == ' ' && src[14] == ':' && src[17] == ':' && (src[20] == ':' || src[20] == ' ') && isdigit(src[7]) && isdigit(src[8]) && isdigit(src[9]) && isdigit(src[10]) ); } gboolean scan_pix_timestamp(const gchar **buf, gint *left, WallClockTime *wct) { if (!scan_month_abbrev(buf, left, &wct->wct_mon) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_mday) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 4, &wct->wct_year) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_hour) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_min) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_sec)) return FALSE; wct->wct_year -= 1900; return TRUE; } /******************************************************************************* * LinkSys modified RFC3164 timestamp, expected format: * "MMM DD HH:MM:SS YYYY " *******************************************************************************/ static gboolean __is_bsd_linksys(const guchar *src, guint32 left) { /* "MMM DD HH:MM:SS YYYY " */ return (left >= 21 && src[3] == ' ' && src[6] == ' ' && src[9] == ':' && src[12] == ':' && src[15] == ' ' && isdigit(src[16]) && isdigit(src[17]) && isdigit(src[18]) && isdigit(src[19]) && isspace(src[20]) ); } gboolean scan_linksys_timestamp(const gchar **buf, gint *left, WallClockTime *wct) { /* LinkSys timestamp, expected format: MMM DD HH:MM:SS YYYY */ if (!scan_month_abbrev(buf, left, &wct->wct_mon) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_mday) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_hour) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_min) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_sec) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 4, &wct->wct_year)) return FALSE; wct->wct_year -= 1900; return TRUE; } /******************************************************************************* * Parse ISO timestamp *******************************************************************************/ static guint32 __parse_usec(const guchar **data, gint *length) { guint32 usec = 0; const guchar *src = *data; /* Fractions of a second are in most cases using a dot, but some devices * use a comma (e.g. Aruba) to separate the fractions of a seconds part */ if (*length > 0 && (*src == '.' || *src == ',')) { gulong frac = 0; gint div = 1; /* process second fractions */ src++; (*length)--; while (*length > 0 && div < 10e5 && isdigit(*src)) { frac = 10 * frac + (*src) - '0'; div = div * 10; src++; (*length)--; } while (*length > 0 && isdigit(*src)) { src++; (*length)--; } usec = frac * (1000000 / div); } *data = src; return usec; } static gboolean __has_iso_timezone(const guchar *src, gint length) { return (length >= 6) && (*src == '+' || *src == '-') && isdigit(*(src+1)) && isdigit(*(src+2)) && *(src+3) == ':' && isdigit(*(src+4)) && isdigit(*(src+5)) && (length < 7 || !isdigit(*(src+6))); } static guint32 __parse_iso_timezone(const guchar **data, gint *length) { g_assert(*length >= 6); gint hours, mins; const guchar *src = *data; guint32 tz = 0; /* timezone offset */ gint sign = *src == '-' ? -1 : 1; hours = (*(src + 1) - '0') * 10 + *(src + 2) - '0'; mins = (*(src + 4) - '0') * 10 + *(src + 5) - '0'; tz = sign * (hours * 3600 + mins * 60); src += 6; (*length) -= 6; *data = src; return tz; } gboolean scan_iso_timezone(const guchar **data, gint *length, gint *gmtoff) { if (__has_iso_timezone(*data, *length)) { *gmtoff = __parse_iso_timezone(data, length); return TRUE; } return FALSE; } static gboolean __parse_iso_stamp(WallClockTime *wct, const guchar **data, gint *length) { /* RFC3339 timestamp, expected format: YYYY-MM-DDTHH:MM:SS[.frac]<+/->ZZ:ZZ */ const guchar *src = *data; if (!scan_iso_timestamp((const gchar **) &src, length, wct)) { return FALSE; } wct->wct_usec = __parse_usec(&src, length); if (*length > 0 && *src == 'Z') { /* Z is special, it means UTC */ wct->wct_gmtoff = 0; src++; (*length)--; } else if (__has_iso_timezone(src, *length)) { wct->wct_gmtoff = __parse_iso_timezone(&src, length); } else { wct->wct_gmtoff = -1; } *data = src; return TRUE; } /******************************************************************************* * Parse BSD timestamp *******************************************************************************/ static gboolean __parse_bsd_timestamp(const guchar **data, gint *length, WallClockTime *wct) { gint left = *length; const guchar *src = *data; if (__is_bsd_pix_or_asa(src, left)) { if (!scan_pix_timestamp((const gchar **) &src, &left, wct)) return FALSE; if (left && *src == ':') { src++; left--; } } else if (__is_bsd_linksys(src, left)) { if (!scan_linksys_timestamp((const gchar **) &src, &left, wct)) return FALSE; } else if (__is_bsd_rfc_3164(src, left)) { if (!scan_bsd_timestamp((const gchar **) &src, &left, wct)) return FALSE; wct->wct_usec = __parse_usec(&src, &left); wall_clock_time_guess_missing_year(wct); } else { return FALSE; } *data = src; *length = left; return TRUE; } gboolean scan_rfc3164_timestamp(const guchar **data, gint *length, WallClockTime *wct) { const guchar *src = *data; gint left = *length; /* If the next chars look like a date, then read them as a date. */ if (__is_iso_stamp((const gchar *)src, left)) { if (!__parse_iso_stamp(wct, &src, &left)) return FALSE; } else { if (!__parse_bsd_timestamp(&src, &left, wct)) return FALSE; } /* we might have a closing colon at the end of the timestamp, "Cisco" I am * looking at you, skip that as well, so we can reliably detect IPv6 * addresses as hostnames, which would be using ":" as well. */ if (left && *src == ':') { ++src; --left; } *data = src; *length = left; return TRUE; } gboolean scan_rfc5424_timestamp(const guchar **data, gint *length, WallClockTime *wct) { const guchar *src = *data; gint left = *length; if (!__parse_iso_stamp(wct, &src, &left)) return FALSE; *data = src; *length = left; return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/scan-timestamp.h000066400000000000000000000035711450431004300232440ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_SCAN_TIMESTAMP_H_INCLUDED #define TIMEUTILS_SCAN_TIMESTAMP_H_INCLUDED #include "syslog-ng.h" #include "timeutils/wallclocktime.h" #include "timeutils/unixtime.h" gboolean scan_iso_timezone(const guchar **buf, gint *length, gint *gmtoff); gboolean scan_iso_timestamp(const gchar **buf, gint *left, WallClockTime *wct); gboolean scan_pix_timestamp(const gchar **buf, gint *left, WallClockTime *wct); gboolean scan_linksys_timestamp(const gchar **buf, gint *left, WallClockTime *wct); gboolean scan_bsd_timestamp(const gchar **buf, gint *left, WallClockTime *wct); gboolean scan_rfc3164_timestamp(const guchar **data, gint *length, WallClockTime *wct); gboolean scan_rfc5424_timestamp(const guchar **data, gint *length, WallClockTime *wct); gboolean scan_day_abbrev(const gchar **buf, gint *left, gint *wday); gboolean scan_month_abbrev(const gchar **buf, gint *left, gint *mon); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/000077500000000000000000000000001450431004300213025ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/CMakeLists.txt000066400000000000000000000003371450431004300240450ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_scan-timestamp) add_unit_test(LIBTEST CRITERION TARGET test_conv) add_unit_test(LIBTEST CRITERION TARGET test_wallclocktime) add_unit_test(LIBTEST CRITERION TARGET test_unixtime) syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/Makefile.am000066400000000000000000000023121450431004300233340ustar00rootroot00000000000000lib_timeutils_tests_TESTS = \ lib/timeutils/tests/test_scan_timestamp \ lib/timeutils/tests/test_conv \ lib/timeutils/tests/test_wallclocktime \ lib/timeutils/tests/test_unixtime check_PROGRAMS += ${lib_timeutils_tests_TESTS} lib_timeutils_tests_test_conv_SOURCES = lib/timeutils/tests/test_conv.c lib_timeutils_tests_test_conv_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/timeutils lib_timeutils_tests_test_conv_LDADD = \ $(TEST_LDADD) lib_timeutils_tests_test_scan_timestamp_SOURCES = lib/timeutils/tests/test_scan-timestamp.c lib_timeutils_tests_test_scan_timestamp_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/timeutils lib_timeutils_tests_test_scan_timestamp_LDADD = \ $(TEST_LDADD) lib_timeutils_tests_test_wallclocktime_SOURCES = lib/timeutils/tests/test_wallclocktime.c lib_timeutils_tests_test_wallclocktime_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/timeutils lib_timeutils_tests_test_wallclocktime_LDADD = \ $(TEST_LDADD) lib_timeutils_tests_test_unixtime_SOURCES = lib/timeutils/tests/test_unixtime.c lib_timeutils_tests_test_unixtime_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/lib/timeutils lib_timeutils_tests_test_unixtime_LDADD = \ $(TEST_LDADD) EXTRA_DIST += lib/timeutils/tests/CMakeLists.txt syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/test_conv.c000066400000000000000000000211561450431004300234570ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/fake-time.h" #include "timeutils/unixtime.h" #include "timeutils/wallclocktime.h" #include "timeutils/conv.h" static void _wct_initialize(WallClockTime *wct, const gchar *timestamp) { gchar *end = wall_clock_time_strptime(wct, "%b %d %Y %H:%M:%S", timestamp); cr_assert(*end == 0, "error parsing WallClockTime initialization timestamp: %s, end: %s", timestamp, end); } static void _wct_initialize_with_tz(WallClockTime *wct, const gchar *timestamp) { gchar *end = wall_clock_time_strptime(wct, "%b %d %Y %H:%M:%S %z", timestamp); cr_assert(*end == 0, "error parsing WallClockTime initialization timestamp: %s, end: %s", timestamp, end); } Test(conv, convert_wall_clock_time_to_unix_time) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Jan 19 2019 18:58:48"); wct.wct_gmtoff = 3600; convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == 3600); cr_expect(ut.ut_sec == 1547920728); } Test(conv, convert_wall_clock_time_to_unix_time_without_timezone_assumes_local_tz) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Jan 19 2019 18:58:48"); cr_expect(wct.wct_gmtoff == -1); convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == 3600); cr_expect(ut.ut_sec == 1547920728); } Test(conv, convert_and_normalize_wall_clock_time_to_unix_time_changes_the_wct_to_normalize_values) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Mar 31 2019 02:11:00"); /* pre normalized values, just as we parsed it from the input */ cr_expect(wct.wct_gmtoff == -1); cr_expect(wct.wct_hour == 2); convert_and_normalize_wall_clock_time_to_unix_time(&wct, &ut); /* at this point normalization changes the wct as well! */ cr_expect(wct.wct_gmtoff == 7200); cr_expect(wct.wct_hour == 2); cr_expect(ut.ut_gmtoff == 7200); cr_expect(ut.ut_sec == 1553994660 - 3600); } Test(conv, unix_time_set_from_a_specific_timezone_which_happens_at_the_spring_transition_hour) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; /* this timestamp is in the DST transition hour but is from a timezone * where the daylight saving happens at another time (Mar 10th) */ _wct_initialize_with_tz(&wct, "Mar 31 2019 02:11:00 EDT"); /* pre normalized values, just as we parsed it from the input */ cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_isdst == 1); cr_expect(wct.wct_hour == 2); convert_and_normalize_wall_clock_time_to_unix_time(&wct, &ut); /* at this point normalization (e.g. the stuff mktime() does) might * change the wct as well, but * convert_and_normalize_wall_clock_time_to_unix_time() tries to behave as if * they didn't happen. */ cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_hour == 2); cr_expect(ut.ut_gmtoff == -5*3600 + 3600); cr_expect(ut.ut_sec == 1554012660); /* going back from UnixTime to WallClockTime, we should get the same * gmtoff and hour values */ convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_hour == 2); cr_expect(wct.wct_min == 11); } Test(conv, unix_time_set_from_a_specific_timezone_which_happens_at_the_autumn_transition_hour) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; /* this timestamp is in the DST transition hour but is from a timezone * where the daylight saving happens at another time (Nov 3rd) */ _wct_initialize_with_tz(&wct, "Oct 27 2019 02:11:00 EDT"); /* pre normalized values, just as we parsed it from the input */ cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_isdst == 1); cr_expect(wct.wct_hour == 2); convert_and_normalize_wall_clock_time_to_unix_time(&wct, &ut); /* at this point normalization (e.g. the stuff mktime() does) might * change the wct as well, but * convert_and_normalize_wall_clock_time_to_unix_time() tries to behave as if * they didn't happen. */ cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_hour == 2); cr_expect(ut.ut_gmtoff == -5*3600 + 3600); cr_expect(ut.ut_sec == 1572156660); /* going back from UnixTime to WallClockTime, we should get the same * gmtoff and hour values */ convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_gmtoff == -5*3600 + 3600); cr_expect(wct.wct_hour == 2); cr_expect(wct.wct_min == 11); } Test(conv, convert_wall_clock_time_to_unix_time_without_timezone_and_tz_hint_uses_the_hint) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Jan 19 2019 18:58:48"); cr_expect(wct.wct_gmtoff == -1); convert_wall_clock_time_to_unix_time_with_tz_hint(&wct, &ut, 7200); cr_expect(wct.wct_gmtoff == -1); cr_expect(ut.ut_gmtoff == 7200); cr_expect(ut.ut_sec == 1547917128); wct.wct_gmtoff = -1; convert_wall_clock_time_to_unix_time_with_tz_hint(&wct, &ut, -5*3600); cr_expect(wct.wct_gmtoff == -1); cr_expect(ut.ut_gmtoff == -5*3600); cr_expect(ut.ut_sec == 1547942328); } Test(conv, set_from_unixtime_sets_wct_fields_properly) { WallClockTime wct = WALL_CLOCK_TIME_INIT; UnixTime ut = UNIX_TIME_INIT; /* Thu Dec 19 22:25:44 CET 2019 */ ut.ut_sec = 1576790744; ut.ut_usec = 567000; ut.ut_gmtoff = 3600; convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 11); cr_expect(wct.wct_mday == 19); cr_expect(wct.wct_hour == 22); cr_expect(wct.wct_min == 25); cr_expect(wct.wct_sec == 44); cr_expect(wct.wct_usec == 567000); cr_expect(wct.wct_gmtoff == 3600); } Test(conv, set_from_unixtime_with_a_different_gmtoff_changes_hours_properly) { WallClockTime wct = WALL_CLOCK_TIME_INIT; UnixTime ut = UNIX_TIME_INIT; /* Thu Dec 19 16:25:44 EST 2019 */ ut.ut_sec = 1576790744; ut.ut_usec = 567000; ut.ut_gmtoff = -5*3600; convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 11); cr_expect(wct.wct_mday == 19); cr_expect(wct.wct_hour == 16); cr_expect(wct.wct_min == 25); cr_expect(wct.wct_sec == 44); cr_expect(wct.wct_usec == 567000); cr_expect(wct.wct_gmtoff == -5*3600); } Test(conv, set_from_unixtime_without_timezone_information_assumes_local_timezone) { WallClockTime wct = WALL_CLOCK_TIME_INIT; UnixTime ut = UNIX_TIME_INIT; /* Thu Dec 19 22:25:44 CET 2019 */ ut.ut_sec = 1576790744; ut.ut_usec = 567000; ut.ut_gmtoff = -1; convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 11); cr_expect(wct.wct_mday == 19); cr_expect(wct.wct_hour == 22); cr_expect(wct.wct_min == 25); cr_expect(wct.wct_sec == 44); cr_expect(wct.wct_usec == 567000); cr_expect(wct.wct_gmtoff == 3600); } Test(conv, set_from_unixtime_with_tz_override_changes_the_timezone_to_the_overridden_value) { WallClockTime wct = WALL_CLOCK_TIME_INIT; UnixTime ut = UNIX_TIME_INIT; /* Thu Dec 19 22:25:44 CET 2019 */ ut.ut_sec = 1576790744; ut.ut_usec = 567000; ut.ut_gmtoff = 3600; /* +05:30 */ convert_unix_time_to_wall_clock_time_with_tz_override(&ut, &wct, 5*3600 + 1800); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 11); cr_expect(wct.wct_mday == 20); cr_expect(wct.wct_hour == 2); cr_expect(wct.wct_min == 55); cr_expect(wct.wct_sec == 44); cr_expect(wct.wct_usec == 567000); cr_expect(wct.wct_gmtoff == 5*3600 + 1800); } static void setup(void) { setenv("TZ", "CET", TRUE); tzset(); } static void teardown(void) { } TestSuite(conv, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/test_scan-timestamp.c000066400000000000000000000476051450431004300254460ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/stopwatch.h" #include "timeutils/scan-timestamp.h" #include "timeutils/cache.h" #include "timeutils/format.h" #include "timeutils/conv.h" #include "apphook.h" static void fake_time(time_t now) { GTimeVal tv = { now, 123 * 1000 }; set_cached_time(&tv); } static void fake_time_add(time_t diff) { GTimeVal tv; cached_g_current_time(&tv); tv.tv_sec += diff; set_cached_time(&tv); } static gboolean _parse_rfc3164(const gchar *ts, gint len, gchar isotimestamp[32]) { UnixTime stamp; const guchar *tsu = (const guchar *) ts; gint tsu_len = len < 0 ? strlen(ts) : len; GString *result = g_string_new(""); WallClockTime wct = WALL_CLOCK_TIME_INIT; const guchar *data = tsu; gint length = tsu_len; gboolean success = scan_rfc3164_timestamp(&data, &length, &wct); cr_assert(length >= 0); cr_assert(data == &tsu[tsu_len - length]); unix_time_unset(&stamp); convert_wall_clock_time_to_unix_time(&wct, &stamp); append_format_unix_time(&stamp, result, TS_FMT_ISO, stamp.ut_gmtoff, 3); strncpy(isotimestamp, result->str, 32); g_string_free(result, TRUE); return success; } static gboolean _parse_rfc5424(const gchar *ts, gint len, gchar isotimestamp[32]) { UnixTime stamp; const guchar *tsu = (const guchar *) ts; gint tsu_len = len < 0 ? strlen(ts) : len; GString *result = g_string_new(""); WallClockTime wct = WALL_CLOCK_TIME_INIT; const guchar *data = tsu; gint length = tsu_len; gboolean success = scan_rfc5424_timestamp(&data, &length, &wct); cr_assert(length >= 0); cr_assert(data == &tsu[tsu_len - length]); unix_time_unset(&stamp); convert_wall_clock_time_to_unix_time(&wct, &stamp); append_format_unix_time(&stamp, result, TS_FMT_ISO, stamp.ut_gmtoff, 3); strncpy(isotimestamp, result->str, 32); g_string_free(result, TRUE); return success; } static gboolean _rfc3164_timestamp_eq(const gchar *ts, gint len, const gchar *expected, gchar converted[32]) { cr_assert(_parse_rfc3164(ts, len, converted)); return strcmp(converted, expected) == 0; } static gboolean _rfc5424_timestamp_eq(const gchar *ts, gint len, const gchar *expected, gchar converted[32]) { cr_assert(_parse_rfc5424(ts, len, converted)); return strcmp(converted, expected) == 0; } #define _expect_rfc3164_timestamp_eq(ts, expected) \ ({ \ gchar converted[32]; \ cr_expect(_rfc3164_timestamp_eq(ts, -1, expected, converted), "Parsed RFC3164 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ }) #define _expect_rfc3164_timestamp_len_eq(ts, len, expected) \ ({ \ gchar converted[32]; \ cr_expect(_rfc3164_timestamp_eq(ts, len, expected, converted), "Parsed RFC3164 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ }) #define _expect_rfc3164_fails(ts, len) \ ({ \ WallClockTime wct = WALL_CLOCK_TIME_INIT; \ const guchar *data = (guchar *) ts; \ gint length = len < 0 ? strlen(ts) : len; \ cr_assert_not(scan_rfc3164_timestamp(&data, &length, &wct)); \ }) #define _expect_rfc5424_timestamp_eq(ts, expected) \ ({ \ gchar converted[32]; \ cr_expect(_rfc5424_timestamp_eq(ts, -1, expected, converted), "Parsed RFC5424 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ }) #define _expect_rfc5424_timestamp_len_eq(ts, len, expected) \ ({ \ gchar converted[32]; \ cr_expect(_rfc5424_timestamp_eq(ts, len, expected, converted), "Parsed RFC5424 timestamp does not equal expected, ts=%s, converted=%s, expected=%s", ts, converted, expected); \ }) #define _expect_rfc5424_fails(ts, len) \ ({ \ WallClockTime wct = WALL_CLOCK_TIME_INIT; \ const guchar *data = (guchar *) ts; \ gint length = len < 0 ? strlen(ts) : len; \ cr_assert_not(scan_rfc5424_timestamp(&data, &length, &wct)); \ }) Test(parse_timestamp, standard_bsd_format) { _expect_rfc3164_timestamp_eq("Oct 1 17:46:12", "2017-10-01T17:46:12.000+02:00"); } Test(parse_timestamp, bsd_extensions) { /* fractions of a second */ _expect_rfc3164_timestamp_eq("Dec 3 09:10:12.987", "2017-12-03T09:10:12.987+01:00"); _expect_rfc3164_timestamp_eq("Dec 3 09:10:12,987", "2017-12-03T09:10:12.987+01:00"); /* year added at the end (linksys) */ _expect_rfc3164_timestamp_eq("Dec 3 09:10:12 2019 ", "2019-12-03T09:10:12.000+01:00"); /* year after the mon/day (cisco) */ _expect_rfc3164_timestamp_eq("Dec 3 2019 09:10:12:", "2019-12-03T09:10:12.000+01:00"); _expect_rfc3164_timestamp_eq("Dec 3 2019 09:10:12 ", "2019-12-03T09:10:12.000+01:00"); } Test(parse_timestamp, accept_iso_timestamps_with_space) { _expect_rfc3164_timestamp_eq("2017-12-03 09:10:12.987+01:00", "2017-12-03T09:10:12.987+01:00"); _expect_rfc3164_timestamp_eq("2017-12-03 09:10:12,987+01:00", "2017-12-03T09:10:12.987+01:00"); _expect_rfc3164_timestamp_eq("2017-12-03 09:10:12.987", "2017-12-03T09:10:12.987+01:00"); _expect_rfc3164_timestamp_eq("2017-12-03 09:10:12,987", "2017-12-03T09:10:12.987+01:00"); _expect_rfc3164_timestamp_eq("2017-12-03 09:10:12", "2017-12-03T09:10:12.000+01:00"); _expect_rfc5424_timestamp_eq("2017-12-03 09:10:12.987+01:00", "2017-12-03T09:10:12.987+01:00"); _expect_rfc5424_timestamp_eq("2017-12-03 09:10:12,987+01:00", "2017-12-03T09:10:12.987+01:00"); _expect_rfc5424_timestamp_eq("2017-12-03 09:10:12.987", "2017-12-03T09:10:12.987+01:00"); _expect_rfc5424_timestamp_eq("2017-12-03 09:10:12,987", "2017-12-03T09:10:12.987+01:00"); _expect_rfc5424_timestamp_eq("2017-12-03 09:10:12", "2017-12-03T09:10:12.000+01:00"); } Test(parse_timestamp, standard_bsd_format_year_in_the_future) { /* compared to 2017-12-13, this timestamp is from the future, so in the year 2018 */ _expect_rfc3164_timestamp_eq("Jan 3 17:46:12.000", "2018-01-03T17:46:12.000+01:00"); } Test(parse_timestamp, standard_bsd_format_year_in_the_past) { /* Jan 03 09:32:21 CET 2018 */ fake_time(1514968341); /* compared to 2018-03-03, this timestamp is from the past, so in the year 2017 */ _expect_rfc3164_timestamp_eq("Dec 31 17:46:12", "2017-12-31T17:46:12.000+01:00"); } Test(parse_timestamp, non_zero_terminated_rfc3164_iso_input_is_handled_properly) { gchar *ts = "2022-08-17T05:02:28.417Z whatever"; gint ts_len = 24; _expect_rfc3164_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.417+00:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.417+00:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.417+00:00"); /* no "Z" parsed, timezone defaults to local, forced CET */ _expect_rfc3164_timestamp_len_eq(ts, ts_len - 1, "2022-08-17T05:02:28.417+02:00"); /* msec is partially parsed as we trim the string from the right */ _expect_rfc3164_timestamp_len_eq(ts, ts_len - 2, "2022-08-17T05:02:28.410+02:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len - 3, "2022-08-17T05:02:28.400+02:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len - 4, "2022-08-17T05:02:28.000+02:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len - 5, "2022-08-17T05:02:28.000+02:00"); for (gint i = 6; i < ts_len; i++) _expect_rfc3164_fails(ts, ts_len - i); } Test(parse_timestamp, non_zero_terminated_rfc3164_bsd_pix_or_asa_input_is_handled_properly) { gchar *ts = "Aug 17 2022 05:02:28: whatever"; gint ts_len = 21; _expect_rfc3164_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.000+02:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.000+02:00"); _expect_rfc3164_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.000+02:00"); /* no ":" at the end, that's a problem, unrecognized */ _expect_rfc3164_fails(ts, ts_len - 1); for (gint i = 1; i < ts_len; i++) _expect_rfc3164_fails(ts, ts_len - i); } Test(parse_timestamp, non_zero_terminated_rfc5424_input_is_handled_properly) { gchar *ts = "2022-08-17T05:02:28.417Z whatever"; gint ts_len = 24; _expect_rfc5424_timestamp_len_eq(ts, strlen(ts), "2022-08-17T05:02:28.417+00:00"); _expect_rfc5424_timestamp_len_eq(ts, ts_len + 5, "2022-08-17T05:02:28.417+00:00"); _expect_rfc5424_timestamp_len_eq(ts, ts_len, "2022-08-17T05:02:28.417+00:00"); /* no "Z" parsed, timezone defaults to local, forced CET */ _expect_rfc5424_timestamp_len_eq(ts, ts_len - 1, "2022-08-17T05:02:28.417+02:00"); /* msec is partially parsed as we trim the string from the right */ _expect_rfc5424_timestamp_len_eq(ts, ts_len - 2, "2022-08-17T05:02:28.410+02:00"); _expect_rfc5424_timestamp_len_eq(ts, ts_len - 3, "2022-08-17T05:02:28.400+02:00"); _expect_rfc5424_timestamp_len_eq(ts, ts_len - 4, "2022-08-17T05:02:28.000+02:00"); _expect_rfc5424_timestamp_len_eq(ts, ts_len - 5, "2022-08-17T05:02:28.000+02:00"); for (gint i = 6; i < ts_len; i++) _expect_rfc5424_fails(ts, ts_len - i); } Test(parse_timestamp, non_zero_terminated_rfc5424_timestamp_only) { const gchar *ts = "2022-08-17T05:02:28.417+03:00"; gint ts_len = strlen(ts); _expect_rfc5424_timestamp_len_eq(ts, ts_len, ts); } Test(parse_timestamp, daylight_saving_behavior_at_spring_with_explicit_timezones) { /* Mar 25 01:59:59 CET 2018 */ fake_time(1521939599); for (gint i = 0; i < 3; i++) { _expect_rfc3164_timestamp_eq("2018-03-25T01:59:59+01:00", "2018-03-25T01:59:59.000+01:00"); /* this is an invalid timestamp, in CEST we don't have any valid hours * between 02:00:00 and 02:59:59 AM. * * We need to ensure that the incoming timezone offset stays intact and * the hour remains. */ _expect_rfc3164_timestamp_eq("2018-03-25T02:00:00+01:00", "2018-03-25T02:00:00.000+01:00"); _expect_rfc3164_timestamp_eq("2018-03-25T02:00:00+02:00", "2018-03-25T02:00:00.000+02:00"); _expect_rfc3164_timestamp_eq("2018-03-25T02:59:59+01:00", "2018-03-25T02:59:59.000+01:00"); _expect_rfc3164_timestamp_eq("2018-03-25T02:59:59+02:00", "2018-03-25T02:59:59.000+02:00"); /* 03:00:00 AM is already valid and DST is enabled */ _expect_rfc3164_timestamp_eq("2018-03-25T03:00:00+02:00", "2018-03-25T03:00:00.000+02:00"); fake_time_add(3600); } } Test(parse_timestamp, daylight_saving_behavior_at_spring_without_timezones) { /* Mar 25 01:59:59 CET 2018 */ fake_time(1521939599); /* iterate _before_, _within_, _after_ the transition hour */ for (gint i = 0; i < 3; i++) { _expect_rfc3164_timestamp_eq("Mar 25 01:59:59", "2018-03-25T01:59:59.000+01:00"); /* this is an invalid timestamp, in CEST we don't have any valid hours * between 02:00:00 and 02:59:59 AM. * * This behavior actually moves these timestamp 1 hour early, as the * "hour" value remains intact, but the timezone changes. * * Devices with timezone support should not be emitting these timestamps * at all, otherwise if we don't send timezone information, the hour * remains as we've received. We could adjust the hour to 03:00, but in * that case, when the device actually reaches 03:00 we would go back in * time. (e.g. 02:59:59 automatically changed by syslog-ng to 03:59:59, * then we would go back to 03:00:00 as that's already a valid timestamp. * */ _expect_rfc3164_timestamp_eq("Mar 25 02:00:00", "2018-03-25T02:00:00.000+02:00"); _expect_rfc3164_timestamp_eq("Mar 25 02:59:59", "2018-03-25T02:59:59.000+02:00"); /* 03:00:00 AM is already valid and DST is enabled */ _expect_rfc3164_timestamp_eq("Mar 25 03:00:00", "2018-03-25T03:00:00.000+02:00"); fake_time_add(3600); } } Test(parse_timestamp, daylight_saving_detection_at_autumn_with_timezones) { /* Oct 28 01:59:59 CEST 2018 */ fake_time(1540684799); /* iterate _before_, _within_, _after_ the transition hour */ for (gint i = 0; i < 3; i++) { _expect_rfc3164_timestamp_eq("2018-10-28T01:59:59.000+01:00", "2018-10-28T01:59:59.000+01:00"); _expect_rfc3164_timestamp_eq("2018-10-28T01:59:59.000+02:00", "2018-10-28T01:59:59.000+02:00"); _expect_rfc3164_timestamp_eq("2018-10-28T02:00:00.000+01:00", "2018-10-28T02:00:00.000+01:00"); _expect_rfc3164_timestamp_eq("2018-10-28T02:00:00.000+02:00", "2018-10-28T02:00:00.000+02:00"); _expect_rfc3164_timestamp_eq("2018-10-28T02:59:59.000+01:00", "2018-10-28T02:59:59.000+01:00"); _expect_rfc3164_timestamp_eq("2018-10-28T02:59:59.000+02:00", "2018-10-28T02:59:59.000+02:00"); _expect_rfc3164_timestamp_eq("2018-10-28T03:00:00.000+01:00", "2018-10-28T03:00:00.000+01:00"); _expect_rfc3164_timestamp_eq("2018-10-28T03:00:00.000+02:00", "2018-10-28T03:00:00.000+02:00"); fake_time_add(3600); } } /* NOTE: Platform specific issues * * At least macOS seems to do something funny thing when trying * to find out whether DST is in effect in a timestamp within the * transition period. (e.g. mktime() with tm_isdst set to -1). * * On macOS For some reason, 02:00:00 - 02:25:17 is considered DST enabled, * while 02:25:18-02:59:59 are considered DST disabled. The entire hour * is considered DST enabled on Linux. * * For this reason, I've dropped 02:59:59 testcases where there's no * timezone information, and added this note. */ Test(parse_timestamp, daylight_saving_detection_at_autumn_without_timezones) { /* Oct 28 01:59:59 CEST 2018 */ fake_time(1540684799); /* iterate _before_, _within_, _after_ the transition hour */ for (gint i = 0; i < 3; i++) { _expect_rfc3164_timestamp_eq("Oct 28 01:59:59", "2018-10-28T01:59:59.000+02:00"); _expect_rfc3164_timestamp_eq("Oct 28 02:00:00", "2018-10-28T02:00:00.000+02:00"); _expect_rfc3164_timestamp_eq("Oct 28 03:00:00", "2018-10-28T03:00:00.000+01:00"); fake_time_add(3600); } } Test(parse_timestamp, cisco_timestamps) { /* BSD with fractions of a second */ _expect_rfc3164_timestamp_eq("Apr 29 13:58:40", "2017-04-29T13:58:40.000+02:00"); _expect_rfc3164_timestamp_eq("Apr 29 13:58:40:", "2017-04-29T13:58:40.000+02:00"); _expect_rfc3164_timestamp_eq("Apr 29 13:58:40.411", "2017-04-29T13:58:40.411+02:00"); _expect_rfc3164_timestamp_eq("Apr 29 13:58:40.411:", "2017-04-29T13:58:40.411+02:00"); /* MMM DD YYYY HH:MM:SS */ _expect_rfc3164_timestamp_eq("Apr 29 2016 13:58:40 ", "2016-04-29T13:58:40.000+02:00"); _expect_rfc3164_timestamp_eq("Apr 29 2016 13:58:40:", "2016-04-29T13:58:40.000+02:00"); /* NOTE: fractions of a second are not supported now * _expect_rfc3164_timestamp_eq("Apr 29 2016 13:58:40.411 ", "2016-04-29T13:58:40.411+02:00"); * _expect_rfc3164_timestamp_eq("Apr 29 2016 13:58:40.411:", "2016-04-29T13:58:40.411+02:00"); */ /* LinkSys: MMM DD HH:MM:SS YYYY (maybe we should accept ":" as a terminator character? */ _expect_rfc3164_timestamp_eq("Apr 29 13:58:40 2016 ", "2016-04-29T13:58:40.000+02:00"); /* NOTE: fractions of a second causes the year to be ignored. * _expect_rfc3164_timestamp_eq("Apr 29 13:58:40.411 2016 ", "2016-04-29T13:58:40.411+02:00"); * _expect_rfc3164_timestamp_eq("Apr 29 13:58:40.411 2016:", "2016-04-29T13:58:40.411+02:00"); */ /* Additional things we should cover in timestamp parsing (and tests) * - msecs * - timezone * - AM/PM markers * - year at various locations * * Cisco call manager produces this: * _expect_rfc3164_timestamp_eq("Jun 14 11:57:27 PM.685 UTC:", "2017-06-14T23:57:27.685+00:00"); */ } Test(parse_timestamp, rfc5424_timestamps) { _expect_rfc5424_timestamp_eq("2017-06-14T23:57:27+02:00", "2017-06-14T23:57:27.000+02:00"); _expect_rfc5424_timestamp_eq("2017-06-14T23:57:27Z", "2017-06-14T23:57:27.000+00:00"); } Test(parse_timestamp, rfc3164_performance) { const gchar *ts = "Dec 14 05:27:22"; const guchar *data = (const guchar *) ts; gint length = strlen(ts); WallClockTime wct = WALL_CLOCK_TIME_INIT; gint it = 1000000; start_stopwatch(); for (gint i = 0; i < it; i++) { scan_rfc3164_timestamp(&data, &length, &wct); } stop_stopwatch_and_display_result(it, "RFC3164 timestamp parsing speed"); } Test(parse_timestamp, rfc5424_performance) { const gchar *ts = "2019-12-14T05:27:22"; const guchar *data = (const guchar *) ts; gint length = strlen(ts); WallClockTime wct = WALL_CLOCK_TIME_INIT; gint it = 1000000; start_stopwatch(); for (gint i = 0; i < it; i++) { scan_rfc5424_timestamp(&data, &length, &wct); } stop_stopwatch_and_display_result(it, "RFC5424 timestamp parsing speed"); } static void _parse_valid_month(const gchar *month, const gint expected_month) { gint left = strlen(month); gint mon = -1; cr_assert(scan_month_abbrev(&month, &left, &mon)); cr_assert_eq(mon, expected_month); cr_assert_eq(left, 0); } Test(scan_month_abbrev, valid_months) { _parse_valid_month("Jan", 0); _parse_valid_month("Feb", 1); _parse_valid_month("Mar", 2); _parse_valid_month("Apr", 3); _parse_valid_month("May", 4); _parse_valid_month("Jun", 5); _parse_valid_month("Jul", 6); _parse_valid_month("Aug", 7); _parse_valid_month("Sep", 8); _parse_valid_month("Oct", 9); _parse_valid_month("Nov", 10); _parse_valid_month("Dec", 11); } static void _parse_invalid_month(const gchar *month) { gint left = strlen(month); gint original_left = left; gint mon = -1; cr_assert_not(scan_month_abbrev(&month, &left, &mon)); cr_assert_eq(mon, -1); cr_assert_eq(left, original_left); } Test(scan_month_abbrev, invalid_month_names) { _parse_invalid_month(""); _parse_invalid_month("Set"); _parse_invalid_month("Jit"); _parse_invalid_month("abcdefg"); _parse_invalid_month("JaX"); _parse_invalid_month("FeX"); _parse_invalid_month("MaX"); _parse_invalid_month("ApX"); _parse_invalid_month("MaX"); _parse_invalid_month("JuX"); _parse_invalid_month("JuX"); _parse_invalid_month("AuX"); _parse_invalid_month("SeX"); _parse_invalid_month("OcX"); _parse_invalid_month("NoX"); _parse_invalid_month("DeX"); } static void _parse_valid_day(const gchar *day, const gint expected_day) { gint left = strlen(day); gint daynum = -1; cr_assert(scan_day_abbrev(&day, &left, &daynum)); cr_assert_eq(daynum, expected_day); cr_assert_eq(left, 0); } Test(scan_day_abbrev, valid_days) { _parse_valid_day("Sun", 0); _parse_valid_day("Mon", 1); _parse_valid_day("Tue", 2); _parse_valid_day("Wed", 3); _parse_valid_day("Thu", 4); _parse_valid_day("Fri", 5); _parse_valid_day("Sat", 6); } static void _parse_invalid_day(const gchar *day) { gint left = strlen(day); gint original_left = left; gint daynum = -1; cr_assert_not(scan_day_abbrev(&day, &left, &daynum)); cr_assert_eq(daynum, -1); cr_assert_eq(left, original_left); } Test(scan_day_abbrev, invalid_day_names) { _parse_invalid_day(""); _parse_invalid_day("Set"); _parse_invalid_day("abcdefg"); _parse_invalid_day("SuX"); _parse_invalid_day("MoX"); _parse_invalid_day("TuX"); _parse_invalid_day("WeX"); _parse_invalid_day("ThX"); _parse_invalid_day("FrX"); _parse_invalid_day("SaX"); } void setup(void) { app_startup(); setenv("TZ", "CET", TRUE); tzset(); /* Dec 13 09:10:23 CET 2017 */ fake_time(1513152623); } void teardown(void) { app_shutdown(); } TestSuite(parse_timestamp, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/test_unixtime.c000066400000000000000000000464541450431004300243640ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/fake-time.h" #include "timeutils/unixtime.h" #include "timeutils/wallclocktime.h" #include "timeutils/conv.h" #include "timeutils/cache.h" #include "timeutils/format.h" static void _wct_initialize(WallClockTime *wct, const gchar *timestamp) { gchar *end = wall_clock_time_strptime(wct, "%b %d %Y %H:%M:%S", timestamp); cr_assert(*end == 0, "error parsing WallClockTime initialization timestamp: %s, end: %s", timestamp, end); } Test(unixtime, unix_time_initialization) { UnixTime ut = UNIX_TIME_INIT; cr_assert(!unix_time_is_set(&ut)); /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); unix_time_set_now(&ut); cr_assert(unix_time_is_set(&ut)); cr_expect(ut.ut_sec == 1576790744); cr_expect(ut.ut_usec == 123000); cr_expect(ut.ut_gmtoff == 3600); unix_time_unset(&ut); cr_assert(!unix_time_is_set(&ut)); } Test(unixtime, unix_time_fix_timezone_adjusts_timestamp_as_if_was_parsed_assuming_the_incorrect_timezone) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Jan 19 2019 18:58:48"); wct.wct_gmtoff = 3600; convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == 3600); unix_time_fix_timezone(&ut, -5*3600); cr_expect(ut.ut_gmtoff == -5*3600); convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_hour == 18); cr_expect(wct.wct_min == 58); cr_expect(wct.wct_sec == 48); } static void _fix_timezone_with_tzinfo(UnixTime *base_ut, UnixTime *ut, gint base_ofs, const gchar *zone_name) { *ut = *base_ut; ut->ut_sec += base_ofs; unix_time_fix_timezone_with_tzinfo(ut, cached_get_time_zone_info(zone_name)); } Test(unixtime, unix_time_fix_timezone_with_tzinfo_to_a_zone_backwards_during_sprint_daylight_saving_hour) { UnixTime ut = UNIX_TIME_INIT; UnixTime base_ut; /* We are assuming a timestamp in CET and fixing that to be US Eastern * time EST5EDT, e.g. the timezone offset is being decreased from +3600 * to -18000/-14400 (depending on DST). This testcase contains a series * of tests as we go through the daylight saving start hour in the spring. * */ /* Base timestamp: Mar 10 2019 02:00:00 CET, * * e.g. if interpreted in EST5DST this is the start of the DST transition * hour in 2019. We simulate that we assumed it was CET and then we "fix" * the timezone to EST5EDT */ base_ut.ut_sec = 1552179600; base_ut.ut_usec = 0; base_ut.ut_gmtoff = 3600; /* TESTCASE: 1 second earlier than the DST transition hour */ /* this "fix" will cause ut->ut_sec to be changed, it will go forward, but * still not be reaching the daylight saving start, short of a second */ _fix_timezone_with_tzinfo(&base_ut, &ut, -1, "EST5EDT"); /* still has not reached the DST start time */ cr_assert(ut.ut_sec == 1552201200 - 1); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == -5*3600); /* TESTCASE: 1 second later, e.g. Mar 10 2019 02:00:00 CET, which is * exactly the daylight saving start second. It should be converted to * Mar 10 2019 03:00:00 EDT */ _fix_timezone_with_tzinfo(&base_ut, &ut, 0, "EST5EDT"); /* we are at exactly the DST start time */ cr_assert(ut.ut_sec == 1552201200); /* thus the resulting timezone is EDT and not EST */ cr_assert(ut.ut_gmtoff == -4*3600); /* TESTCASE: 30 minutes later, e.g. 02:30:00, that is converted to 03:30:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 1800, "EST5EDT"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1552201200 + 1800); /* thus the resulting timezone is EDT */ cr_assert(ut.ut_gmtoff == -4*3600); /* TESTCASE: 1 hour second later, e.g. 03:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 3600, "EST5EDT"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1552201200); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == -4*3600); /* TESTCASE: 2 hours second later, e.g. 04:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 7200, "EST5EDT"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1552201200 + 3600); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == -4*3600); } Test(unixtime, unix_time_fix_timezone_with_tzinfo_to_a_zone_forwards_during_sprint_daylight_saving_hour) { UnixTime ut = UNIX_TIME_INIT; UnixTime base_ut; /* Base timestamp: Mar 31 2019 02:00:00 EST5EDT, * * e.g. if interpreted in CET this is the start of the DST transition * hour in 2019. We simulate that we assumed it was EST5EDT and then we "fix" * the timezone to CET */ base_ut.ut_sec = 1554012000; base_ut.ut_usec = 0; base_ut.ut_gmtoff = -4*3600; /* TESTCASE: 1 second earlier than the DST transition hour */ /* this "fix" will cause ut->ut_sec to be changed, it will go forward, but * still not be reaching the daylight saving start, short of a second */ _fix_timezone_with_tzinfo(&base_ut, &ut, -1, "CET"); /* still has not reached the DST start time */ cr_assert(ut.ut_sec == 1553994000 - 1); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == 3600); /* TESTCASE: 1 second later, e.g. Mar 31 2019 02:00:00 CET, which is * exactly the daylight saving start second. It should be converted to * Mar 31 2019 03:00:00 CEST */ _fix_timezone_with_tzinfo(&base_ut, &ut, 0, "CET"); /* we are at exactly the DST start time */ cr_assert(ut.ut_sec == 1553994000); /* thus the resulting timezone is EDT and not EST */ cr_assert(ut.ut_gmtoff == 2*3600); /* TESTCASE: 30 minutes later, e.g. 02:30:00, that is converted to 03:30:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 1800, "CET"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1553994000 + 1800); /* thus the resulting timezone is EDT */ cr_assert(ut.ut_gmtoff == 2*3600); /* TESTCASE: 1 hour second later, e.g. 03:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 3600, "CET"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1553994000); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == 2*3600); /* TESTCASE: 2 hours second later, e.g. 04:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 7200, "CET"); /* we lose the hour, so the DST start time */ cr_assert(ut.ut_sec == 1553994000 + 3600); /* thus the resulting timezone is still EST and not the daylight saving variant */ cr_assert(ut.ut_gmtoff == 2*3600); } Test(unixtime, unix_time_fix_timezone_with_tzinfo_to_a_zone_backwards_during_autumn_daylight_saving_hour) { UnixTime ut = UNIX_TIME_INIT; UnixTime base_ut; /* Base timestamp: Nov 3 2019 02:00:00 CET, * * e.g. if interpreted in EST5DST this is the end of the DST transition * hour in 2019. We simulate that we assumed it was CET and then we "fix" * the timezone to EST5EDT */ base_ut.ut_sec = 1572742800; base_ut.ut_usec = 0; base_ut.ut_gmtoff = 3600; /* TESTCASE: 1 second earlier than the DST transition hour */ /* this "fix" will cause ut->ut_sec to be changed, it will go forward, but * still not be reaching the daylight saving start, short of a second */ _fix_timezone_with_tzinfo(&base_ut, &ut, -1, "EST5EDT"); /* still has not reached the DST start time */ cr_assert(ut.ut_sec == 1572760800 - 1); /* thus the resulting timezone is still EDT */ cr_assert(ut.ut_gmtoff == -4*3600); /* TESTCASE: 1 second later, e.g. Mar 10 2019 02:00:00 CET, which is * exactly the daylight saving start second. It should be converted to * Mar 10 2019 03:00:00 EDT */ _fix_timezone_with_tzinfo(&base_ut, &ut, 0, "EST5EDT"); /* once passed the DST end threshold, we assume the 2nd 02:00:00AM, e.g. * the one with -05:00 offset. This means that an hour is skipped in this * case in the seconds since 1970.01.01, while the offset decreased with * the same. This means that it is not possible to represent a time * between 02:00:00 to 02:59:59 in the daylight saving period, unless the * timezone is explicitly available in the timestamp. */ cr_assert(ut.ut_sec == 1572760800 + 3600); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == -5*3600); /* TESTCASE: 30 minutes later, e.g. 02:30:00, that is converted to 03:30:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 1800, "EST5EDT"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572760800 + 3600 + 1800); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == -5*3600); /* TESTCASE: 1 hour second later, e.g. 03:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 3600, "EST5EDT"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572760800 + 3600 + 3600); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == -5*3600); /* TESTCASE: 2 hours second later, e.g. 04:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 7200, "EST5EDT"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572760800 + 3600 + 7200); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == -5*3600); } Test(unixtime, unix_time_fix_timezone_with_tzinfo_to_a_zone_forwards_during_autumn_daylight_saving_hour) { UnixTime ut = UNIX_TIME_INIT; UnixTime base_ut; /* Base timestamp: Oct 27 2019 02:00:00 EST5EDT, * * e.g. if interpreted in CET this is the end of the DST transition * hour in 2019. We simulate that we assumed it was EST5EDT and then we "fix" * the timezone to CET */ base_ut.ut_sec = 1572156000; base_ut.ut_usec = 0; base_ut.ut_gmtoff = -4*3600; /* testcase, 1 second earlier than the DST transition hour */ /* this "fix" will cause ut->ut_sec to be changed, it will go forward, but * still not be reaching the daylight saving start, short of a second */ _fix_timezone_with_tzinfo(&base_ut, &ut, -1, "CET"); /* still has not reached the DST start time */ cr_assert(ut.ut_sec == 1572134400 - 1); /* thus the resulting timezone is still CEST */ cr_assert(ut.ut_gmtoff == 2*3600); /* TESTCASE: 1 second later, e.g. Oct 27 2019 02:00:00 EDT, which is * exactly the daylight saving start second if interpreted in CET. It * should be converted to Oct 27 2019 03:00:00 CET */ _fix_timezone_with_tzinfo(&base_ut, &ut, 0, "CET"); /* once passed the DST end threshold, we assume the 2nd 02:00:00AM, e.g. * the one with -05:00 offset. This means that an hour is skipped in this * case in the seconds since 1970.01.01, while the offset decreased with * the same. This means that it is not possible to represent a time * between 02:00:00 to 02:59:59 in the daylight saving period, unless the * timezone is explicitly available in the timestamp. */ cr_assert(ut.ut_sec == 1572134400 + 3600); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == 3600); /* TESTCASE: 30 minutes later, e.g. 02:30:00, that is converted to 03:30:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 1800, "CET"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572134400 + 3600 + 1800); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == 3600); /* TESTCASE: 1 hour second later, e.g. 03:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 3600, "CET"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572134400 + 3600 + 3600); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == 3600); /* TESTCASE: 2 hours second later, e.g. 04:00:00 */ _fix_timezone_with_tzinfo(&base_ut, &ut, 7200, "CET"); /* we lose the hour in ut_sec */ cr_assert(ut.ut_sec == 1572134400 + 3600 + 7200); /* thus the resulting timezone is EST and not EDT */ cr_assert(ut.ut_gmtoff == 3600); } Test(unixtime, unix_time_set_timezone_converts_the_timestamp_to_a_target_timezone_assuming_the_source_was_correct) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Jan 19 2019 18:58:48"); wct.wct_gmtoff = 3600; convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == 3600); unix_time_set_timezone(&ut, -5*3600); cr_expect(ut.ut_gmtoff == -5*3600); convert_unix_time_to_wall_clock_time(&ut, &wct); cr_expect(wct.wct_hour == 12); cr_expect(wct.wct_min == 58); cr_expect(wct.wct_sec == 48); } Test(unixtime, unix_time_set_timezone_with_tzinfo_calculates_dst_automatically) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; _wct_initialize(&wct, "Mar 10 2019 01:59:59"); wct.wct_gmtoff = -5*3600; convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == -5*3600); unix_time_set_timezone_with_tzinfo(&ut, cached_get_time_zone_info("EST5EDT")); cr_expect(ut.ut_gmtoff == -5*3600); ut.ut_sec += 1; unix_time_set_timezone_with_tzinfo(&ut, cached_get_time_zone_info("EST5EDT")); cr_expect(ut.ut_gmtoff == -4*3600); _wct_initialize(&wct, "Nov 3 2019 01:59:59"); wct.wct_gmtoff = -4*3600; convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_gmtoff == -4*3600); unix_time_set_timezone_with_tzinfo(&ut, cached_get_time_zone_info("EST5EDT")); cr_expect(ut.ut_gmtoff == -4*3600); ut.ut_sec += 1; unix_time_set_timezone_with_tzinfo(&ut, cached_get_time_zone_info("EST5EDT")); cr_expect(ut.ut_gmtoff == -5*3600); } Test(unixtime, unix_time_guess_timezone_for_even_hour_differences) { UnixTime ut = UNIX_TIME_INIT; WallClockTime wct = WALL_CLOCK_TIME_INIT; /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); /* this is one hour earlier than current time */ _wct_initialize(&wct, "Dec 19 2019 21:25:44"); convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_sec == 1576790744 - 3600); cr_expect(ut.ut_gmtoff == 3600); unix_time_fix_timezone_assuming_the_time_matches_real_time(&ut); cr_expect(ut.ut_sec == 1576790744); cr_expect(ut.ut_gmtoff == 0); /* 13 hours earlier to test one extreme of the timezones, that is -12:00 */ _wct_initialize(&wct, "Dec 19 2019 09:25:44"); convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_sec == 1576790744 - 13*3600); cr_expect(ut.ut_gmtoff == 3600); unix_time_fix_timezone_assuming_the_time_matches_real_time(&ut); cr_expect(ut.ut_sec == 1576790744); cr_expect(ut.ut_gmtoff == -12*3600); /* 13 hours later to test the other extreme, that is +14:00 */ _wct_initialize(&wct, "Dec 20 2019 11:25:44"); convert_wall_clock_time_to_unix_time(&wct, &ut); cr_expect(ut.ut_sec == 1576790744 + 13*3600); cr_expect(ut.ut_gmtoff == 3600); unix_time_fix_timezone_assuming_the_time_matches_real_time(&ut); cr_expect(ut.ut_sec == 1576790744); cr_expect(ut.ut_gmtoff == +14*3600, "%d", ut.ut_gmtoff); } Test(unixtime, unix_time_guess_timezone_for_quarter_hour_differences) { UnixTime ut = UNIX_TIME_INIT; glong t, diff; gint number_of_noneven_timezones = 0; gint number_of_even_timezones = 0; /* Thu Dec 19 22:25:44 CET 2019 */ t = 1576790744; fake_time(t); for (diff = - 13 * 3600; diff <= 14*3600; diff += 900) { ut.ut_sec = t + diff; ut.ut_gmtoff = 3600; if (unix_time_fix_timezone_assuming_the_time_matches_real_time(&ut)) { cr_expect(ut.ut_sec == 1576790744); cr_expect(ut.ut_gmtoff == diff + 3600); if ((diff % 3600) != 0) number_of_noneven_timezones++; else number_of_even_timezones++; } } cr_assert(number_of_noneven_timezones == 17, "The expected number of timezones that are not at an even hour boundary does not match expectations: %d", number_of_noneven_timezones); /* -12:00 .. 00:00 .. +14:00 */ cr_assert(number_of_even_timezones == 12 + 1 + 14, "The expected number of timezones that are at an even hour boundary does not match expectations: %d", number_of_even_timezones); } Test(unixtime, test_unix_time_diff_in_seconds) { UnixTime ut1 = { 1, 123000 }; UnixTime ut2 = { 2, 123000 }; cr_assert(unix_time_diff_in_seconds(&ut1, &ut2) == -1); cr_assert(unix_time_diff_in_seconds(&ut2, &ut1) == 1); ut2.ut_sec = 1; ut2.ut_usec = 623000; cr_assert(unix_time_diff_in_seconds(&ut1, &ut2) == -1); cr_assert(unix_time_diff_in_seconds(&ut2, &ut1) == 1); ut2.ut_sec = 1; ut2.ut_usec = 622000; cr_assert(unix_time_diff_in_seconds(&ut1, &ut2) == 0); cr_assert(unix_time_diff_in_seconds(&ut2, &ut1) == 0); ut2.ut_sec = 1; ut2.ut_usec = 624000; cr_assert(unix_time_diff_in_seconds(&ut1, &ut2) == -1); cr_assert(unix_time_diff_in_seconds(&ut2, &ut1) == 1); /* >0.5 seconds in fractions rounded up */ ut1.ut_sec = 0; ut1.ut_usec = 0; ut2.ut_sec = 1; ut2.ut_usec = 500001; cr_assert_eq(unix_time_diff_in_seconds(&ut1, &ut2), -2); cr_assert_eq(unix_time_diff_in_seconds(&ut2, &ut1), 2); /* < 0.5 seconds rounded down */ ut1.ut_sec = 0; ut1.ut_usec = 980000; ut2.ut_sec = 1; ut2.ut_usec = 20000; cr_assert_eq(unix_time_diff_in_seconds(&ut2, &ut1), 0); cr_assert_eq(unix_time_diff_in_seconds(&ut1, &ut2), 0); } Test(unixtime, test_unix_time_diff_in_msec) { UnixTime ut1 = { 1, 123000 }; UnixTime ut2 = { 2, 123000 }; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -1000); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 1000); ut2.ut_sec = 1; ut2.ut_usec = 623000; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -500); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 500); ut2.ut_sec = 1; ut2.ut_usec = 622000; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -499); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 499); ut2.ut_sec = 1; ut2.ut_usec = 622499; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -499); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 499); ut2.ut_sec = 1; ut2.ut_usec = 622500; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -500); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 500); ut2.ut_sec = 1; ut2.ut_usec = 623499; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -500); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 500); ut2.ut_sec = 1; ut2.ut_usec = 623501; cr_assert(unix_time_diff_in_msec(&ut1, &ut2) == -501); cr_assert(unix_time_diff_in_msec(&ut2, &ut1) == 501); } static void setup(void) { setenv("TZ", "CET", TRUE); tzset(); } static void teardown(void) { } TestSuite(unixtime, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/timeutils/tests/test_wallclocktime.c000066400000000000000000000343541450431004300253500ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/fake-time.h" #include "timeutils/wallclocktime.h" #include "timeutils/cache.h" #include "timeutils/conv.h" /* timeutils cache mock */ gboolean tz_mock_empty_dst_tzname = FALSE; const gchar *const * cached_get_system_tznames(void) { static gchar *tznames[] = { "CET", "CEST" }; if (tz_mock_empty_dst_tzname) tznames[1] = ""; return (const gchar *const *) &tznames; } glong cached_get_system_tzofs(void) { return -1 * 3600; } Test(wallclocktime, test_wall_clock_time_init) { WallClockTime wct; wall_clock_time_unset(&wct); cr_assert(wall_clock_time_is_set(&wct) == FALSE); } Test(wallclocktime, test_strptime_parses_broken_down_time) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S.%f", "Jan 16 2019 18:23:12.012345"); cr_assert(*end == 0); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 0); cr_expect(wct.wct_mday == 16); cr_expect(wct.wct_hour == 18); cr_expect(wct.wct_min == 23); cr_expect(wct.wct_sec == 12); cr_expect(wct.wct_usec == 12345); cr_expect(wct.wct_gmtoff == -1); } Test(wallclocktime, test_strptime_parses_truncated_usec) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S.%f", "Jan 16 2019 18:23:12.012X"); cr_assert(*end == 'X'); cr_expect(wct.wct_usec == 12000); } Test(wallclocktime, test_strptime_parses_overflowed_usec) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S.%f", "Jan 16 2019 18:23:12.0123456X"); cr_assert(*end == 'X'); cr_expect(wct.wct_usec == 12345); } Test(wallclocktime, test_strptime_usec_parse_finds_character) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S.%f", "Jan 16 2019 18:23:12.boom"); cr_assert(end == NULL); cr_expect(wct.wct_usec == 0); } Test(wallclocktime, test_strptime_percent_z_parses_rfc822_timezone) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* quoting RFC822: * * Time zone may be indicated in several ways. "UT" is Universal Time * (formerly called "Greenwich Mean Time"); "GMT" is permitted as a * reference to Universal Time. The military standard uses a single * character for each zone. "Z" is Universal Time. "A" indicates one * hour earlier, and "M" indicates 12 hours earlier; "N" is one hour * later, and "Y" is 12 hours later. The letter "J" is not used. The * other remaining two forms are taken from ANSI standard X3.51-1975. One * allows explicit indication of the amount of offset from UT; the other * uses common 3-character strings for indicating time zones in North * America. */ end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 PST"); cr_assert(*end == 0); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 0); cr_expect(wct.wct_mday == 16); cr_expect(wct.wct_hour == 18); cr_expect(wct.wct_min == 23); cr_expect(wct.wct_sec == 12); cr_expect(wct.wct_usec == 0); cr_expect(wct.wct_gmtoff == -8*3600, "Unexpected timezone offset: %ld, expected -8*3600", wct.wct_gmtoff); /* white space in front of the timezone is skipped with %z */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S%z", "Jan 16 2019 18:23:12 PST"); cr_expect(wct.wct_gmtoff == -8*3600, "Unexpected timezone offset: %ld, expected -8*3600", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S%z", "Jan 16 2019 18:23:12PST"); cr_expect(wct.wct_gmtoff == -8*3600, "Unexpected timezone offset: %ld, expected -8*3600", wct.wct_gmtoff); end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 EDT"); cr_expect(wct.wct_gmtoff == -4*3600, "Unexpected timezone offset: %ld, expected -4*3600", wct.wct_gmtoff); end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 GMT"); cr_expect(wct.wct_gmtoff == 0, "Unexpected timezone offset: %ld, expected 0", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 UTC"); cr_expect(wct.wct_gmtoff == 0, "Unexpected timezone offset: %ld, expected 0", wct.wct_gmtoff); /* local timezone */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 CET"); cr_expect(wct.wct_gmtoff == 1*3600, "Unexpected timezone offset: %ld, expected 1*3600", wct.wct_gmtoff); /* military zones */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 Z"); cr_expect(wct.wct_gmtoff == 0, "Unexpected timezone offset: %ld, expected 0", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 M"); cr_expect(wct.wct_gmtoff == -12*3600, "Unexpected timezone offset: %ld, expected -12*3600", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 Y"); cr_expect(wct.wct_gmtoff == 12*3600, "Unexpected timezone offset: %ld, expected 12*3600", wct.wct_gmtoff); end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 J"); cr_expect(end == NULL); /* hours only */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 +05"); cr_expect(wct.wct_gmtoff == 5*3600, "Unexpected timezone offset: %ld, expected 5*3600", wct.wct_gmtoff); /* hours & minutes */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 +0500"); cr_expect(wct.wct_gmtoff == 5*3600, "Unexpected timezone offset: %ld, expected 5*3600", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 +05:00"); cr_expect(wct.wct_gmtoff == 5*3600, "Unexpected timezone offset: %ld, expected 5*3600", wct.wct_gmtoff); /* non-zero minutes */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Jan 16 2019 18:23:12 +05:30"); cr_expect(wct.wct_gmtoff == 5*3600+30*60, "Unexpected timezone offset: %ld, expected 5*3600+30*60", wct.wct_gmtoff); } Test(wallclocktime, test_strptime_percent_Z_allows_timezone_to_be_optional) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* NOTE: %Z accepts the same formats as %z, except that it allows the timezone to be optional */ end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S%Z", "Jan 16 2019 18:23:12PST"); cr_assert(*end == 0); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 0); cr_expect(wct.wct_mday == 16); cr_expect(wct.wct_hour == 18); cr_expect(wct.wct_min == 23); cr_expect(wct.wct_sec == 12); cr_expect(wct.wct_usec == 0); cr_expect(wct.wct_gmtoff == -8*3600, "Unexpected timezone offset: %ld, expected -8*3600", wct.wct_gmtoff); /* initial whitespace is not skipped */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S%Z", "Jan 16 2019 18:23:12 PST"); cr_expect(end != NULL); cr_expect_str_eq(end, " PST"); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %Z", "Jan 16 2019 18:23:12 PST"); cr_expect(wct.wct_gmtoff == -8*3600, "Unexpected timezone offset: %ld, expected -8*3600", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %Z", "Jan 16 2019 18:23:12"); cr_expect(wct.wct_gmtoff == -1, "Unexpected timezone offset: %ld, expected -1", wct.wct_gmtoff); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %Z", "Jan 16 2019 18:23:12 Y"); cr_expect(wct.wct_gmtoff == 12*3600, "Unexpected timezone offset: %ld, expected 12*3600", wct.wct_gmtoff); /* invalid timezone offset, too short */ wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %Z", "Jan 16 2019 18:23:12 +300"); cr_expect(end != NULL); cr_expect_str_eq(end, "+300"); wct.wct_gmtoff = -1; end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %Z", "Jan 16 2019 18:23:12 +3"); cr_expect(end != NULL); cr_expect_str_eq(end, "+3"); } Test(wallclocktime, test_strptime_zone_parsing_takes_daylight_saving_into_account_when_using_the_local_timezone) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* this is a daylight saving zone name, in which case both wct.wct_isdst * and wct.wct_gmtoff must indicate this */ end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "May 7 2021 09:29:12 CEST"); cr_assert(*end == 0); cr_expect(wct.wct_year == 121); cr_expect(wct.wct_mon == 4); cr_expect(wct.wct_mday == 7); cr_expect(wct.wct_hour == 9); cr_expect(wct.wct_min == 29); cr_expect(wct.wct_sec == 12); cr_expect(wct.wct_usec == 0); cr_expect(wct.wct_isdst > 0); cr_expect(wct.wct_gmtoff == 2*3600, "Unexpected timezone offset: %ld, expected 2*3600", wct.wct_gmtoff); end = wall_clock_time_strptime(&wct, "%b %d %Y %H:%M:%S %z", "Feb 7 2021 09:29:12 CET"); cr_assert(*end == 0); cr_expect(wct.wct_year == 121); cr_expect(wct.wct_mon == 1); cr_expect(wct.wct_mday == 7); cr_expect(wct.wct_hour == 9); cr_expect(wct.wct_min == 29); cr_expect(wct.wct_sec == 12); cr_expect(wct.wct_usec == 0); cr_expect(wct.wct_isdst == 0); cr_expect(wct.wct_gmtoff == 1*3600, "Unexpected timezone offset: %ld, expected 1*3600", wct.wct_gmtoff); } static void _guess_missing_year(WallClockTime *wct, gint mon) { wct->wct_year = -1; wct->wct_mon = mon; wall_clock_time_guess_missing_year(wct); } static gboolean _wct_year_matches(WallClockTime *wct, gint mon, gint ofs) { gint faked_year = 2019; _guess_missing_year(wct, mon); return wct->wct_year == (faked_year - 1900) + ofs; } static gboolean _guessed_year_is_next_year(WallClockTime *wct, gint mon) { return _wct_year_matches(wct, mon, +1); } static gboolean _guessed_year_is_current_year(WallClockTime *wct, gint mon) { return _wct_year_matches(wct, mon, 0); } static gboolean _guessed_year_is_last_year(WallClockTime *wct, gint mon) { return _wct_year_matches(wct, mon, -1); } Test(wallclocktime, guess_year_returns_last_year) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end = wall_clock_time_strptime(&wct, "%b %d %H:%M:%S", "Jan 16 18:23:12"); cr_assert(*end == 0); cr_assert(wct.wct_year == -1); /* Sat Jan 19 18:58:48 CET 2019 */ fake_time(1547920728); for (gint mon = 0; mon < 11; mon++) cr_assert(_guessed_year_is_current_year(&wct, mon)); /* december is assumed to be from the last year */ cr_assert(_guessed_year_is_last_year(&wct, 11)); } Test(wallclocktime, guess_year_returns_next_year) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end = wall_clock_time_strptime(&wct, "%b %d %H:%M:%S", "Jan 16 18:23:12"); cr_assert(*end == 0); cr_assert(wct.wct_year == -1); /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); /* january assumed to be from the future year */ cr_assert(_guessed_year_is_next_year(&wct, 0)); for (gint mon = 1; mon <= 11; mon++) cr_assert(_guessed_year_is_current_year(&wct, mon)); } Test(wallclocktime, test_strptime_parses_without_date) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); end = wall_clock_time_strptime(&wct, "%H:%M:%S %Z", "10:30:00 CET"); wall_clock_time_guess_missing_fields(&wct); cr_expect(end != NULL); cr_expect(wct.wct_year == 119); cr_expect(wct.wct_mon == 11); cr_expect(wct.wct_mday == 19); } Test(wallclocktime, test_strptime_parses_without_mday) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); end = wall_clock_time_strptime(&wct, "%Y-%m %H:%M:%S %Z", "2015-03 10:30:00 CET"); wall_clock_time_guess_missing_fields(&wct); cr_expect(end != NULL); cr_expect(wct.wct_mday == 1); } Test(wallclocktime, test_strptime_parses_without_time) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); end = wall_clock_time_strptime(&wct, "%Y-%m-%d %Z", "2015-03-01 CET"); wall_clock_time_guess_missing_fields(&wct); cr_expect(end != NULL); cr_expect(wct.wct_hour == 0); cr_expect(wct.wct_min == 0); cr_expect(wct.wct_sec == 0); } Test(wallclocktime, test_strptime_parses_without_second) { WallClockTime wct = WALL_CLOCK_TIME_INIT; gchar *end; /* Thu Dec 19 22:25:44 CET 2019 */ fake_time(1576790744); end = wall_clock_time_strptime(&wct, "%Y-%m-%d %H:%M %Z", "2015-03-01 10:30 CET"); wall_clock_time_guess_missing_fields(&wct); cr_expect(end != NULL); cr_expect(wct.wct_min == 30); cr_expect(wct.wct_sec == 0); } Test(wallclocktime, test_strptime_percent_z_is_mandatory) { /* This imitates musl libc behavior to test a bugfix: * if Daylight Saving Time is never used (no past, present or future tzdata), tzname[1] is the empty string. */ tz_mock_empty_dst_tzname = TRUE; WallClockTime wct = WALL_CLOCK_TIME_INIT; cr_assert_null(wall_clock_time_strptime(&wct, "%Y-%m-%d %T%z", "2011-06-25 20:00:04")); } static void setup(void) { setenv("TZ", "CET", TRUE); invalidate_timeutils_cache(); } static void teardown(void) { } TestSuite(wallclocktime, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/timeutils/timeutils.c000066400000000000000000000032341450431004300223250ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/timeutils.h" #include "timeutils/cache.h" #include "apphook.h" static void _reset_timezone_apphook(gint type, gpointer user_data) { invalidate_timeutils_cache(); } void timeutils_global_init(void) { invalidate_timeutils_cache(); /* We are using the STOPPED hook as the timezone related variables (tzname * and timezone) may be changed without locking by other threads. At * AH_CONFIG_STOPPED those threads should have stopped already, so nothing * touches the global variables. Hopefully. */ register_application_hook(AH_CONFIG_STOPPED, _reset_timezone_apphook, NULL, AHM_RUN_REPEAT); } syslog-ng-syslog-ng-4.4.0/lib/timeutils/timeutils.h000066400000000000000000000021521450431004300223300ustar00rootroot00000000000000/* * Copyright (c) 2021 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_TIMEUTILS_H_INCLUDED #define TIMEUTILS_TIMEUTILS_H_INCLUDED #include "syslog-ng.h" void timeutils_global_init(void); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/unixtime.c000066400000000000000000000251531450431004300221540ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/unixtime.h" #include "timeutils/wallclocktime.h" #include "timeutils/cache.h" #include "timeutils/names.h" #include "timeutils/misc.h" #include void unix_time_unset(UnixTime *self) { UnixTime val = UNIX_TIME_INIT; *self = val; } void unix_time_set_now(UnixTime *self) { GTimeVal tv; cached_g_current_time(&tv); self->ut_sec = tv.tv_sec; self->ut_usec = tv.tv_usec; self->ut_gmtoff = get_local_timezone_ofs(self->ut_sec); } static glong _div_round(glong n, glong d) { if ((n < 0) ^ (d < 0)) return ((n - d/2)/d); else return ((n + d/2)/d); } static gboolean _binary_search(glong *haystack, gint haystack_size, glong needle) { gint l = 0; gint h = haystack_size; gint m; while (l <= h) { m = (l + h) / 2; if (haystack[m] == needle) return TRUE; else if (haystack[m] > needle) h = m - 1; else if (haystack[m] < needle) l = m + 1; } return FALSE; } static gboolean _is_gmtoff_valid(long gmtoff) { /* this list was produced by this shell script: * * $ find /usr/share/zoneinfo/ -type f | xargs zdump -v > x.raw * $ grep '20[0-9][0-9].*gmtoff' x.raw | awk '{ i=int(substr($16, 8)); if (i % 3600 != 0) print i; }' | sort -n | uniq * * all of these are either 30 or 45 minutes into the hour. Earlier we * also had timezones like +1040, e.g. 40 minutes into the hour, but * fortunately that has changed. * * Also, this is only consulted wrt real-time timestamps, so we don't need * historical offsets. How often this needs to change? Well, people do * all kinds of crazy stuff with timezones, but I hope this will work for * the foreseeable future. If there's a bug, you can always use the * command above to update this list, provided you have tzdata installed. * */ long valid_non_even_hour_gmtofs[] = { -34200, -16200, -12600, -9000, 12600, 16200, 19800, 20700, 23400, 30600, 31500, 34200, 35100, 37800, 41400, 45900, 49500, }; /* too far off */ if (gmtoff < -12*3600 || gmtoff > 14 * 3600) return FALSE; /* even hours accepted */ if ((gmtoff % 3600) == 0) return TRUE; /* non-even hours are checked using the valid arrays above */ if (_binary_search(valid_non_even_hour_gmtofs, G_N_ELEMENTS(valid_non_even_hour_gmtofs), gmtoff)) return TRUE; return FALSE; } static glong _guess_recv_timezone_offset_based_on_time_difference(UnixTime *self) { GTimeVal now; cached_g_current_time(&now); glong diff_in_sec = now.tv_sec - self->ut_sec; /* More than 24 hours means that this is definitely not a real time * timestamp, so we shouldn't try to auto detect timezone based on the * current time. */ if (labs(diff_in_sec) >= 24 * 3600) return -1; glong diff_rounded_to_quarters = _div_round(diff_in_sec, 3600/4) * 3600/4; if (labs(now.tv_sec - self->ut_sec - diff_rounded_to_quarters) <= 30) { /* roughly quarter of an hour difference, with 30s accuracy */ glong result = self->ut_gmtoff - diff_rounded_to_quarters; if (!_is_gmtoff_valid(result)) return -1; return result; } return -1; } /* change timezone, assuming that the original timezone value has * incorrectly been used to parse the timestamp */ void unix_time_fix_timezone(UnixTime *self, gint new_gmtoff) { long implied_gmtoff = self->ut_gmtoff != -1 ? self->ut_gmtoff : 0; if (new_gmtoff != -1) { self->ut_sec -= (new_gmtoff - implied_gmtoff); self->ut_gmtoff = new_gmtoff; } } /* change timezone, assuming that the original timezone was correct, but we * want to change the timezone reference to a different one */ void unix_time_set_timezone(UnixTime *self, gint new_gmtoff) { if (new_gmtoff != -1) self->ut_gmtoff = new_gmtoff; } /* change timezone, assuming that the original timezone was correct, but we * want to change the timezone reference to a different one */ void unix_time_set_timezone_with_tzinfo(UnixTime *self, TimeZoneInfo *tzinfo) { glong new_gmtoff = time_zone_info_get_offset(tzinfo, self->ut_sec); unix_time_set_timezone(self, new_gmtoff); } gboolean unix_time_fix_timezone_assuming_the_time_matches_real_time(UnixTime *self) { long target_gmtoff = _guess_recv_timezone_offset_based_on_time_difference(self); unix_time_fix_timezone(self, target_gmtoff); return target_gmtoff != -1; } void unix_time_fix_timezone_with_tzinfo(UnixTime *self, TimeZoneInfo *tzinfo) { /* * This function fixes the timezone (e.g. gmtoff) value of the incoming * timestamp in case it was incorrectly recognized at its previous * parsing and converts it to the correct timezone as specified by tzinfo. * * The complexity of this function is that daylight saving thresholds are * specified in local time (e.g. whichever sunday in March/October) and * not as an UTC timestamp. If the current UnixTime instance in @self was * incorrectly parsed, then its UTC timestamp will be off by a few hours. * (more specifically off by the number of hours between the two * timezones). We have to take this inaccuracy into account. * * The basic algorithm is as follows: * 1) first, we look up the gmtoff value of the target timezone based on * the ut_sec value in the original timestamp. This will only be * correct if we don't cross a daylight saving transition hour (of * the target timezone) in any direction. We adjust the * ut_sec/ut_gmtoff pair based on the result of this lookup, by: * * ut_sec += target_gmtoff - source_gmtoff; * ut_gmtoff = target_gmtoff; * * 2) It might happen that this changed ut_sec value (as pointed out * above) either moves past the DST transition hour or moves * right before it, changing the target gmtoff we've guessed at point * #1 above. We detect this by doing another lookup of the target * timezone and then adjusting ut_sec/ut_gmtoff again. This handles * cases properly where we don't fall INTO the transition hour at * this step. * * 3) If we are _within_ the transition hour, we need a final step, as * in this case the transition between the two timezones is not * linear we either need to lose or add an extra hour. This one is * detected using a 3rd lookup, as we if we are in the transition * hour, the 2nd step will be incorrect and the final step would * return the same gmtoff as the 1st. There are two cases here: * * * a) 1st_gmtoff < 2nd_gmtoff: we were in DST but then the 2nd step * moved us before, so let's add an hour to ut_sec so it's again * _after_ the threshold. * * b) 1st_gmtoff > 2nd_gmtoff: we were before DST and the 2nd step * moved us into ut_sec wise, but our gmtoff does not reflect that. * Add an hour to ut_gmtoff. * * This will then nicely move any second between 02:00am and 03:00am * to be between 03:00am and 04:00am, just as it happens when we * convert these timestamps via mktime(). * */ /* STEP 1: * use the ut_sec in the incorrectly parsed timestamp to find * an initial gmtoff value in target */ glong fixed_gmtoff = time_zone_info_get_offset(tzinfo, self->ut_sec); if (fixed_gmtoff != self->ut_gmtoff) { /* adjust gmtoff to the possibly inaccurate gmtoff */ unix_time_fix_timezone(self, fixed_gmtoff); /* STEP 2: check if our initial idea was correct */ glong alt_gmtoff = time_zone_info_get_offset(tzinfo, self->ut_sec); if (alt_gmtoff != fixed_gmtoff) { /* if alt_gmtoff is not equal to fixed_gmtoff then initial idea * was wrong, we are crossing the daylight saving change hour. * but stamp->ut_sec should be more accurate now */ unix_time_fix_timezone(self, alt_gmtoff); /* STEP 3: check if the final fix was good, e.g. are we within the transition hour */ if (time_zone_info_get_offset(tzinfo, self->ut_sec) == fixed_gmtoff) { /* we are within the transition hour, we need to skip 1 hour in the timestamp */ if (alt_gmtoff > fixed_gmtoff) { /* step 2 moved ut_sec right before the transition second, * while ut_gmtoff is already reflecting the changed * offset, move ut_sec forward */ self->ut_sec += alt_gmtoff - fixed_gmtoff; } else { /* step 2 changed ut_gmtoff to be an "old" offset. update gmtoff */ self->ut_gmtoff += fixed_gmtoff - alt_gmtoff; } } } } } gboolean unix_time_eq(const UnixTime *a, const UnixTime *b) { return a->ut_sec == b->ut_sec && a->ut_usec == b->ut_usec && a->ut_gmtoff == b->ut_gmtoff; } /* NOTE: returns sec */ gint64 unix_time_diff_in_seconds(const UnixTime *a, const UnixTime *b) { gint64 diff_sec = a->ut_sec - b->ut_sec; gint64 diff_usec = (gint64) a->ut_usec - (gint64) b->ut_usec; if (diff_usec > -500000 && diff_usec < 500000) ; else if (diff_usec <= -500000) diff_sec--; else diff_sec++; return diff_sec; } gint64 unix_time_diff_in_msec(const UnixTime *a, const UnixTime *b) { gint64 diff_msec = (a->ut_sec - b->ut_sec) * 1000 + ((gint64) a->ut_usec - (gint64) b->ut_usec) / 1000; gint64 diff_usec = ((gint64) a->ut_usec - (gint64) b->ut_usec) % 1000; if (diff_usec > -500 && diff_usec < 500) ; else if (diff_usec <= -500) diff_msec--; else diff_msec++; return diff_msec; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/unixtime.h000066400000000000000000000057331450431004300221630ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef UNIXTIME_H_INCLUDED #define UNIXTIME_H_INCLUDED #include "timeutils/zoneinfo.h" /* * This class represents a UNIX timestamp (as measured in time_t), the * fractions of a second (in microseconds) and an associated GMT timezone * offset. In concept it is the combination of "struct timeval" and the * number of seconds compared to GMT. * * In concept, this is similar to WallClockTime, with the difference that * this represents the time in seconds since the UNIX epoch. * * In design, it is also similar to WallClockTime, the original intention * was to use an embedded "struct timeval", however that would enlarge the * LogMessage structure with a lot of padding (the struct would go from 16 * to 24 bytes and we have 3 of these structs in LogMessage). */ typedef struct _UnixTime UnixTime; struct _UnixTime { gint64 ut_sec; guint32 ut_usec; /* zone offset in seconds, add this to UTC to get the time in local. This * is just 32 bits, contrary to all other gmtoff variables, as we are * squeezed in space with this struct. 32 bit is more than enough for * +/-24*3600 */ gint32 ut_gmtoff; }; #define UNIX_TIME_INIT { -1, 0, -1 } static inline gboolean unix_time_is_set(const UnixTime *ut) { return ut->ut_sec != -1; } static inline gboolean unix_time_is_timezone_set(const UnixTime *self) { return self->ut_gmtoff != -1; } void unix_time_unset(UnixTime *ut); void unix_time_set_now(UnixTime *self); void unix_time_set_timezone(UnixTime *self, gint new_gmtoff); void unix_time_set_timezone_with_tzinfo(UnixTime *self, TimeZoneInfo *tzinfo); void unix_time_fix_timezone(UnixTime *self, gint new_gmtoff); void unix_time_fix_timezone_with_tzinfo(UnixTime *self, TimeZoneInfo *tzinfo); gboolean unix_time_fix_timezone_assuming_the_time_matches_real_time(UnixTime *self); gboolean unix_time_eq(const UnixTime *a, const UnixTime *b); gint64 unix_time_diff_in_seconds(const UnixTime *a, const UnixTime *b); gint64 unix_time_diff_in_msec(const UnixTime *a, const UnixTime *b); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/wallclocktime.c000066400000000000000000000673141450431004300231510ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ /* $NetBSD: strptime.c,v 1.49 2015/10/09 17:21:45 christos Exp $ */ /*- * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * All rights reserved. * * This code was contributed to The NetBSD Foundation by Klaus Klein. * Heavily optimised by David Laight * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * MIT: musl http://git.musl-libc.org/cgit/musl/tree/src/time/strftime.c?id=6ad514e4e278f0c3b18eb2db1d45638c9af1c07f#n19 * The license below only applies for the ISO8601 week calculation in this file. * */ /* * * Copyright © 2005-2019 Rich Felker, et al. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "timeutils/wallclocktime.h" #include "timeutils/unixtime.h" #include "timeutils/cache.h" #include "timeutils/misc.h" void wall_clock_time_unset(WallClockTime *self) { WallClockTime val = WALL_CLOCK_TIME_INIT; *self = val; } #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) #define TM_YEAR_BASE 1900 #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 #define TM_WEDNESDAY 3 #define TM_THURSDAY 4 #define TM_FRIDAY 5 #define TM_SATURDAY 6 #define TM_JANUARY 0 #define TM_FEBRUARY 1 #define TM_MARCH 2 #define TM_APRIL 3 #define TM_MAY 4 #define TM_JUNE 5 #define TM_JULY 6 #define TM_AUGUST 7 #define TM_SEPTEMBER 8 #define TM_OCTOBER 9 #define TM_NOVEMBER 10 #define TM_DECEMBER 11 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) static gboolean _is_jan1_3_days_past_monday(WallClockTime *wct) { return ((wct->wct_wday + 371 - wct->wct_yday - 2) % 7 <= 2); } static gint _get_dec31_day_of_week(WallClockTime *wct) { return (wct->wct_wday + 7 - wct->wct_yday - 1) % 7; } static gint _get_jan1_day_of_week(WallClockTime *wct) { return (wct->wct_wday + 371 - wct->wct_yday) % 7; } guint32 wall_clock_time_iso_week_number(WallClockTime *wct) { gint week_number = (wct->wct_yday - (wct->wct_wday - 1 + 7) % 7 + 7 ) / 7; if (_is_jan1_3_days_past_monday(wct)) week_number++; if (week_number == 0) { gint last_dec31 = _get_dec31_day_of_week(wct); if (last_dec31 == 4 || (last_dec31 == 5 && isleap(wct->wct_year-1))) return 53; return 52; } if (week_number == 53) { int jan1 = _get_jan1_day_of_week(wct); if (jan1 != 4 && (jan1 != 3 || !isleap(wct->wct_year))) return 1; } return week_number; } typedef struct { const char *abday[7]; const char *day[7]; const char *abmon[12]; const char *mon[12]; const char *am_pm[2]; const char *d_t_fmt; const char *d_fmt; const char *t_fmt; const char *t_fmt_ampm; } _TimeLocale; static const _TimeLocale _DefaultTimeLocale = { /* abbreviated day */ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }, /* days */ { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }, /* abbreviated month */ { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }, /* month */ { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, /* ampm */ { "AM", "PM" }, "%a %b %e %H:%M:%S %Y", "%m/%d/%y", "%H:%M:%S", "%I:%M:%S %p" }; #define _TIME_LOCALE(loc) \ (&_DefaultTimeLocale) static const unsigned char *conv_num(const unsigned char *, int *, unsigned int, unsigned int); static const unsigned char *find_string(const unsigned char *, int *, const char *const *, const char *const *, int); static int first_wday_of(int yr); /* * We do not implement alternate representations. However, we always * check whether a given modifier is allowed for a certain conversion. */ #define ALT_E 0x01 #define ALT_O 0x02 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } #define S_YEAR (1 << 0) #define S_MON (1 << 1) #define S_YDAY (1 << 2) #define S_MDAY (1 << 3) #define S_WDAY (1 << 4) #define S_HOUR (1 << 5) #define S_USEC (1 << 6) #define HAVE_MDAY(s) (s & S_MDAY) #define HAVE_MON(s) (s & S_MON) #define HAVE_WDAY(s) (s & S_WDAY) #define HAVE_YDAY(s) (s & S_YDAY) #define HAVE_YEAR(s) (s & S_YEAR) #define HAVE_HOUR(s) (s & S_HOUR) #define HAVE_USEC(s) (s & S_USEC) static char utc[] = { "UTC" }; /* RFC-822/RFC-2822 */ static const char *const nast[5] = { "EST", "CST", "MST", "PST", "\0\0\0" }; static const char *const nadt[5] = { "EDT", "CDT", "MDT", "PDT", "\0\0\0" }; /* * Table to determine the ordinal date for the start of a month. * Ref: http://en.wikipedia.org/wiki/ISO_week_date */ static const int start_of_month[2][13] = { /* non-leap year */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* leap year */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; static inline gboolean _is_str_empty(const gchar *str) { return !str || strcmp(str, "") == 0; } gchar * wall_clock_time_strptime(WallClockTime *wct, const gchar *format, const gchar *input) { unsigned char c; const unsigned char *bp, *ep, *zname; int alt_format, i, split_year = 0, neg = 0, state = 0, day_offset = -1, week_offset = 0, offs, mandatory; const char *new_fmt; const char *const *system_tznames; int system_tznames_len; bp = (const unsigned char *)input; while (bp != NULL && (c = *format++) != '\0') { /* Clear `alternate' modifier prior to new conversion. */ alt_format = 0; i = 0; /* Eat up white-space. */ if (isspace(c)) { while (isspace(*bp)) bp++; continue; } if (c != '%') goto literal; again: switch (c = *format++) { case '%': /* "%%" is converted to "%". */ literal: if (c != *bp++) return NULL; LEGAL_ALT(0); continue; /* * "Alternative" modifiers. Just set the appropriate flag * and start over again. */ case 'E': /* "%E?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_E; goto again; case 'O': /* "%O?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_O; goto again; /* * "Complex" conversion rules, implemented through recursion. */ case 'c': /* Date and time, using the locale's format. */ new_fmt = _TIME_LOCALE(loc)->d_t_fmt; state |= S_WDAY | S_MON | S_MDAY | S_YEAR; goto recurse; case 'D': /* The date as "%m/%d/%y". */ new_fmt = "%m/%d/%y"; LEGAL_ALT(0); state |= S_MON | S_MDAY | S_YEAR; goto recurse; case 'F': /* The date as "%Y-%m-%d". */ new_fmt = "%Y-%m-%d"; LEGAL_ALT(0); state |= S_MON | S_MDAY | S_YEAR; goto recurse; case 'R': /* The time as "%H:%M". */ new_fmt = "%H:%M"; LEGAL_ALT(0); goto recurse; case 'r': /* The time in 12-hour clock representation. */ new_fmt = _TIME_LOCALE(loc)->t_fmt_ampm; LEGAL_ALT(0); goto recurse; case 'T': /* The time as "%H:%M:%S". */ new_fmt = "%H:%M:%S"; LEGAL_ALT(0); goto recurse; case 'X': /* The time, using the locale's format. */ new_fmt = _TIME_LOCALE(loc)->t_fmt; goto recurse; case 'x': /* The date, using the locale's format. */ new_fmt = _TIME_LOCALE(loc)->d_fmt; state |= S_MON | S_MDAY | S_YEAR; recurse: bp = (const unsigned char *)wall_clock_time_strptime(wct, new_fmt, (const char *)bp); LEGAL_ALT(ALT_E); continue; /* * "Elementary" conversion rules. */ case 'A': /* The day of week, using the locale's form. */ case 'a': bp = find_string(bp, &wct->tm.tm_wday, _TIME_LOCALE(loc)->day, _TIME_LOCALE(loc)->abday, 7); LEGAL_ALT(0); state |= S_WDAY; continue; case 'B': /* The month, using the locale's form. */ case 'b': case 'h': bp = find_string(bp, &wct->tm.tm_mon, _TIME_LOCALE(loc)->mon, _TIME_LOCALE(loc)->abmon, 12); LEGAL_ALT(0); state |= S_MON; continue; case 'C': /* The century number. */ i = 20; bp = conv_num(bp, &i, 0, 99); i = i * 100 - TM_YEAR_BASE; if (split_year) i += wct->tm.tm_year % 100; split_year = 1; wct->tm.tm_year = i; LEGAL_ALT(ALT_E); state |= S_YEAR; continue; case 'd': /* The day of month. */ case 'e': bp = conv_num(bp, &wct->tm.tm_mday, 1, 31); LEGAL_ALT(ALT_O); state |= S_MDAY; continue; case 'f': { const unsigned char *end = conv_num(bp, &wct->wct_usec, 0, 999999); if (!end) return NULL; int digits = end - bp; /* * We have read up to 6 digits, but if the message has * sub-microsecond precision, eat-up the digits we cannot handle. */ while (isdigit(*end)) { end++; } /* * If we read less than 6 digits, we need to adjust the value: * "012" was parsed as 12 but is 12000 us. */ while (digits++ < 6) { wct->wct_usec *= 10; } bp = end; LEGAL_ALT(0); state |= S_USEC; continue; } case 'k': /* The hour (24-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'H': bp = conv_num(bp, &wct->tm.tm_hour, 0, 23); LEGAL_ALT(ALT_O); state |= S_HOUR; continue; case 'l': /* The hour (12-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'I': bp = conv_num(bp, &wct->tm.tm_hour, 1, 12); if (wct->tm.tm_hour == 12) wct->tm.tm_hour = 0; LEGAL_ALT(ALT_O); state |= S_HOUR; continue; case 'j': /* The day of year. */ i = 1; bp = conv_num(bp, &i, 1, 366); wct->tm.tm_yday = i - 1; LEGAL_ALT(0); state |= S_YDAY; continue; case 'M': /* The minute. */ bp = conv_num(bp, &wct->tm.tm_min, 0, 59); LEGAL_ALT(ALT_O); continue; case 'm': /* The month. */ i = 1; bp = conv_num(bp, &i, 1, 12); wct->tm.tm_mon = i - 1; LEGAL_ALT(ALT_O); state |= S_MON; continue; case 'p': /* The locale's equivalent of AM/PM. */ bp = find_string(bp, &i, _TIME_LOCALE(loc)->am_pm, NULL, 2); if (HAVE_HOUR(state) && wct->tm.tm_hour > 11) return NULL; wct->tm.tm_hour += i * 12; LEGAL_ALT(0); continue; case 'S': /* The seconds. */ bp = conv_num(bp, &wct->tm.tm_sec, 0, 61); LEGAL_ALT(ALT_O); continue; #ifndef TIME_MAX #define TIME_MAX INT64_MAX #endif case 's': /* seconds since the epoch */ { time_t sse = 0; uint64_t rulim = TIME_MAX; if (*bp < '0' || *bp > '9') { bp = NULL; continue; } do { sse *= 10; sse += *bp++ - '0'; rulim /= 10; } while ((sse * 10 <= TIME_MAX) && rulim && *bp >= '0' && *bp <= '9'); if (sse < 0 || (uint64_t)sse > TIME_MAX) { bp = NULL; continue; } cached_localtime(&sse, &wct->tm); state |= S_YDAY | S_WDAY | S_MON | S_MDAY | S_YEAR; } continue; case 'U': /* The week of year, beginning on sunday. */ case 'W': /* The week of year, beginning on monday. */ /* * XXX This is bogus, as we can not assume any valid * information present in the tm structure at this * point to calculate a real value, so just check the * range for now. */ bp = conv_num(bp, &i, 0, 53); LEGAL_ALT(ALT_O); if (c == 'U') day_offset = TM_SUNDAY; else day_offset = TM_MONDAY; week_offset = i; continue; case 'w': /* The day of week, beginning on sunday. */ bp = conv_num(bp, &wct->tm.tm_wday, 0, 6); LEGAL_ALT(ALT_O); state |= S_WDAY; continue; case 'u': /* The day of week, monday = 1. */ bp = conv_num(bp, &i, 1, 7); wct->tm.tm_wday = i % 7; LEGAL_ALT(ALT_O); state |= S_WDAY; continue; case 'g': /* The year corresponding to the ISO week * number but without the century. */ bp = conv_num(bp, &i, 0, 99); continue; case 'G': /* The year corresponding to the ISO week * number with century. */ do bp++; while (isdigit(*bp)); continue; case 'V': /* The ISO 8601:1988 week number as decimal */ bp = conv_num(bp, &i, 0, 53); continue; case 'Y': /* The year. */ i = TM_YEAR_BASE; /* just for data sanity... */ bp = conv_num(bp, &i, 0, 9999); wct->tm.tm_year = i - TM_YEAR_BASE; LEGAL_ALT(ALT_E); state |= S_YEAR; continue; case 'y': /* The year within 100 years of the epoch. */ /* LEGAL_ALT(ALT_E | ALT_O); */ bp = conv_num(bp, &i, 0, 99); if (split_year) /* preserve century */ i += (wct->tm.tm_year / 100) * 100; else { split_year = 1; if (i <= 68) i = i + 2000 - TM_YEAR_BASE; else i = i + 1900 - TM_YEAR_BASE; } wct->tm.tm_year = i; state |= S_YEAR; continue; case 'Z': case 'z': mandatory = c == 'z'; /* * We recognize all ISO 8601 formats: * Z = Zulu time/UTC * [+-]hhmm * [+-]hh:mm * [+-]hh * We recognize all RFC-822/RFC-2822 formats: * UT|GMT * North American : UTC offsets * E[DS]T = Eastern : -4 | -5 * C[DS]T = Central : -5 | -6 * M[DS]T = Mountain: -6 | -7 * P[DS]T = Pacific : -7 | -8 * Military * [A-IL-M] = -1 ... -9 (J not used) * [N-Y] = +1 ... +12 */ if (mandatory) while (isspace(*bp)) bp++; zname = bp; switch (*bp++) { case 'G': if (*bp++ != 'M') return NULL; /*FALLTHROUGH*/ case 'U': if (*bp++ != 'T') return NULL; /*FALLTHROUGH*/ case 'Z': wct->tm.tm_isdst = 0; wct->wct_gmtoff = 0; wct->wct_zone = utc; continue; case '+': neg = 0; break; case '-': neg = 1; break; default: --bp; ep = find_string(bp, &i, nast, NULL, 4); if (ep != NULL) { wct->wct_gmtoff = (-5 - i) * 3600; wct->wct_zone = __UNCONST(nast[i]); bp = ep; continue; } ep = find_string(bp, &i, nadt, NULL, 4); if (ep != NULL) { wct->tm.tm_isdst = 1; wct->wct_gmtoff = (-4 - i) * 3600; wct->wct_zone = __UNCONST(nadt[i]); bp = ep; continue; } system_tznames = cached_get_system_tznames(); system_tznames_len = _is_str_empty(system_tznames[1]) ? 1 : 2; ep = find_string(bp, &i, system_tznames, NULL, system_tznames_len); if (ep != NULL) { wct->tm.tm_isdst = i; wct->wct_gmtoff = -cached_get_system_tzofs() + wct->tm.tm_isdst*3600; wct->wct_zone = system_tznames[i]; bp = ep; continue; } if ((*bp >= 'A' && *bp <= 'I') || (*bp >= 'L' && *bp <= 'Y')) { /* Argh! No 'J'! */ if (*bp >= 'A' && *bp <= 'I') wct->wct_gmtoff = (('A' - 1) - (int)*bp) * 3600; else if (*bp >= 'L' && *bp <= 'M') wct->wct_gmtoff = ('A' - (int)*bp) * 3600; else if (*bp >= 'N' && *bp <= 'Y') wct->wct_gmtoff = ((int)*bp - 'M') * 3600; wct->wct_zone = utc; /* XXX */ bp++; continue; } if (mandatory) return NULL; bp = zname; continue; } offs = 0; for (i = 0; i < 4; ) { if (isdigit(*bp)) { offs = offs * 10 + (*bp++ - '0'); i++; continue; } if (i == 2 && *bp == ':') { bp++; continue; } break; } switch (i) { case 2: offs *= 3600; break; case 4: i = offs % 100; offs /= 100; if (i >= 60) goto out; /* Convert minutes into decimal */ offs = offs * 3600 + i * 60; break; default: out: if (mandatory) return NULL; bp = zname; continue; } if (neg) offs = -offs; wct->tm.tm_isdst = 0; /* XXX */ wct->wct_gmtoff = offs; wct->wct_zone = utc; /* XXX */ continue; /* * Miscellaneous conversions. */ case 'n': /* Any kind of white-space. */ case 't': while (isspace(*bp)) bp++; LEGAL_ALT(0); continue; default: /* Unknown/unsupported conversion. */ return NULL; } } if (!HAVE_YDAY(state) && HAVE_YEAR(state)) { if (HAVE_MON(state) && HAVE_MDAY(state)) { /* calculate day of year (ordinal date) */ wct->tm.tm_yday = start_of_month[isleap_sum(wct->tm.tm_year, TM_YEAR_BASE)][wct->tm.tm_mon] + (wct->tm.tm_mday - 1); state |= S_YDAY; } else if (day_offset != -1) { /* * Set the date to the first Sunday (or Monday) * of the specified week of the year. */ if (!HAVE_WDAY(state)) { wct->tm.tm_wday = day_offset; state |= S_WDAY; } wct->tm.tm_yday = (7 - first_wday_of(wct->tm.tm_year + TM_YEAR_BASE) + day_offset) % 7 + (week_offset - 1) * 7 + wct->tm.tm_wday - day_offset; state |= S_YDAY; } } if (HAVE_YDAY(state) && HAVE_YEAR(state)) { int isleap; if (!HAVE_MON(state)) { /* calculate month of day of year */ i = 0; isleap = isleap_sum(wct->tm.tm_year, TM_YEAR_BASE); while (wct->tm.tm_yday >= start_of_month[isleap][i]) i++; if (i > 12) { i = 1; wct->tm.tm_yday -= start_of_month[isleap][12]; wct->tm.tm_year++; } wct->tm.tm_mon = i - 1; state |= S_MON; } if (!HAVE_MDAY(state)) { /* calculate day of month */ isleap = isleap_sum(wct->tm.tm_year, TM_YEAR_BASE); wct->tm.tm_mday = wct->tm.tm_yday - start_of_month[isleap][wct->tm.tm_mon] + 1; state |= S_MDAY; } if (!HAVE_WDAY(state)) { /* calculate day of week */ i = 0; week_offset = first_wday_of(wct->tm.tm_year); while (i++ <= wct->tm.tm_yday) { if (week_offset++ >= 6) week_offset = 0; } wct->tm.tm_wday = week_offset; state |= S_WDAY; } } if (!HAVE_USEC(state)) { wct->wct_usec = 0; } return __UNCONST(bp); } /* Determine (guess) the year for the month. * * It can be used for BSD logs, where year is missing. */ static gint determine_year_for_month(gint month, const struct tm *now) { if (month == 11 && now->tm_mon == 0) return now->tm_year - 1; else if (month == 0 && now->tm_mon == 11) return now->tm_year + 1; else return now->tm_year; } void wall_clock_time_guess_missing_year(WallClockTime *self) { if (self->wct_year == -1) { time_t now; struct tm tm; now = cached_g_current_time_sec(); cached_localtime(&now, &tm); self->wct_year = determine_year_for_month(self->wct_mon, &tm); } } void wall_clock_time_guess_missing_fields(WallClockTime *self) { /* * The missing cases for date can be divided into three types: * 1) missing all fileds -> use current date * 2) only miss year -> guess year based on current year and month (current * year, last year or next year) * 3) the rest of the cases don't make much sense, so zero initialization of * the missing field makes sense. And the year is initializeed to the current * one. */ time_t now; struct tm tm; now = cached_g_current_time_sec(); cached_localtime(&now, &tm); if (self->wct_year == -1 && self->wct_mon == -1 && self->wct_mday == -1) { self->wct_year = tm.tm_year; self->wct_mon = tm.tm_mon; self->wct_mday = tm.tm_mday; } else if (self->wct_year == -1 && self->wct_mon != -1 && self->wct_mday != -1) { self->wct_year = determine_year_for_month(self->wct_mon, &tm); } else { if (self->wct_year == -1) self->wct_year = tm.tm_year; if (self->wct_mon == -1) self->wct_mon = 0; if (self->wct_mday == -1) self->wct_mday = 1; // day of the month - [1, 31] } if (self->wct_hour == -1) self->wct_hour = 0; if (self->wct_min == -1) self->wct_min = 0; if (self->wct_sec == -1) self->wct_sec = 0; } /* * Calculate the week day of the first day of a year. Valid for * the Gregorian calendar, which began Sept 14, 1752 in the UK * and its colonies. Ref: * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week */ static int first_wday_of(int yr) { return ((2 * (3 - (yr / 100) % 4)) + (yr % 100) + ((yr % 100) / 4) + (isleap(yr) ? 6 : 0) + 1) % 7; } static const unsigned char * conv_num(const unsigned char *input, int *dest, unsigned int llim, unsigned int ulim) { unsigned int result = 0; unsigned char ch; /* The limit also determines the number of valid digits. */ unsigned int rulim = ulim; ch = *input; if (ch < '0' || ch > '9') return NULL; do { result *= 10; result += ch - '0'; rulim /= 10; ch = *++input; } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9'); if (result < llim || result > ulim) return NULL; *dest = result; return input; } static const unsigned char * find_string(const unsigned char *bp, int *tgt, const char *const *n1, const char *const *n2, int c) { int i; size_t len; /* check full name - then abbreviated ones */ for (; n1 != NULL; n1 = n2, n2 = NULL) { for (i = 0; i < c; i++, n1++) { len = strlen(*n1); if (strncasecmp(*n1, (const char *)bp, len) == 0) { *tgt = i; return bp + len; } } } /* Nothing matched */ return NULL; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/wallclocktime.h000066400000000000000000000116621450431004300231510ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 1998-2018 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef WALLCLOCKTIME_H_INCLUDED #define WALLCLOCKTIME_H_INCLUDED #include "syslog-ng.h" /* * This is a simple wrapper over "struct tm" with fields that are not * portable across all platforms or are not present at all, but which we * would use. * * For instance, wct_gmtoff is not present on a number of platforms but would * be very useful internally, so we _always_ have the capability to * represent a broken-down time with all the properties needed for proper * timezone reference. * * Another example is wct_usec, which represents the number of microseconds * so we can carry fractions of a second information. * * The design of the class is so that we don't need to copy the contents of * "struct tm" around for conversions, rather we contain one instance and * provide wrapper macros so that fields that are present in struct tm are * used from there, those that aren't will be part of the wrapper structure. * * NOTE on thread safety: the wct_zone field is a pointer to a dynamically * allocated string, that is managed in a thread-specific location (in * cache.c), the pointer could become stale across a syslog-ng reload. In * general it is not a good idea to pass WallClockTime instances between * threads, if the wct_zone field was initialized by cached_localtime() and * friends, unless you ensure this field does not become stale. */ typedef struct _WallClockTime WallClockTime; struct _WallClockTime { #define wct_year tm.tm_year #define wct_mon tm.tm_mon #define wct_mday tm.tm_mday #define wct_wday tm.tm_wday #define wct_yday tm.tm_yday #define wct_hour tm.tm_hour #define wct_min tm.tm_min #define wct_sec tm.tm_sec #define wct_isdst tm.tm_isdst struct tm tm; /* We might need to separate tm_zone to a different conditional/autoconf * check. At least on Linux/FreeBSD they were introduced the same time. * Some platforms may lack tm_zone, even though they have tm_gmtoff */ #ifndef SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF long wct_gmtoff; const char *wct_zone; #else #define wct_gmtoff tm.tm_gmtoff #define wct_zone tm.tm_zone #endif int wct_usec; }; #ifdef SYSLOG_NG_HAVE_STRUCT_TM_TM_GMTOFF #define WALL_CLOCK_TIME_INIT \ { \ .tm = \ { \ .tm_year = -1, \ .tm_mon = -1, \ .tm_mday = -1, \ .tm_wday = -1, \ .tm_yday = -1, \ .tm_hour = -1, \ .tm_min = -1, \ .tm_sec = -1, \ .tm_isdst = -1, \ .tm_gmtoff = -1, \ .tm_zone = NULL, \ }, \ .wct_usec = 0, \ } #else #define WALL_CLOCK_TIME_INIT \ { \ .tm = \ { \ .tm_year = -1, \ .tm_mon = -1, \ .tm_mday = -1, \ .tm_wday = -1, \ .tm_yday = -1, \ .tm_hour = -1, \ .tm_min = -1, \ .tm_sec = -1, \ .tm_isdst = -1, \ }, \ .wct_gmtoff = -1, \ .wct_zone = NULL, \ .wct_usec = 0, \ } #endif guint32 wall_clock_time_iso_week_number(WallClockTime *wct); static inline gboolean wall_clock_time_is_set(WallClockTime *wct) { return wct->wct_hour != -1; } void wall_clock_time_unset(WallClockTime *wct); gchar *wall_clock_time_strptime(WallClockTime *wct, const gchar *format, const gchar *input); void wall_clock_time_guess_missing_year(WallClockTime *self); void wall_clock_time_guess_missing_fields(WallClockTime *self); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/zonecache.c000066400000000000000000000032601450431004300222440ustar00rootroot00000000000000/* * Copyright (c) 2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/zonecache.h" #include "timeutils/zoneinfo.h" #include "timeutils/zonedb.h" #include "tls-support.h" #include "../cache.h" typedef struct _TimeZoneResolver { CacheResolver super; } TimeZoneResolver; static gpointer time_zone_resolver_resolve(CacheResolver *s, const gchar *tz) { if (is_time_zone_valid(tz)) return time_zone_info_new(tz); return NULL; } static CacheResolver * time_zone_resolver_new(void) { TimeZoneResolver *self = g_new0(TimeZoneResolver, 1); self->super.resolve_elem = time_zone_resolver_resolve; self->super.free_elem = (GDestroyNotify) time_zone_info_free; return &self->super; } Cache * time_zone_cache_new(void) { return cache_new(time_zone_resolver_new()); } syslog-ng-syslog-ng-4.4.0/lib/timeutils/zonecache.h000066400000000000000000000022001450431004300222420ustar00rootroot00000000000000/* * Copyright (c) 2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_ZONECACHE_H_INCLUDED #define TIMEUTILS_ZONECACHE_H_INCLUDED 1 #include "zoneinfo.h" #include "../cache.h" Cache *time_zone_cache_new(void); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/zonedb.c000066400000000000000000000041241450431004300215660ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/zonedb.h" #include "pathutils.h" #include "reloc.h" #include static const gchar *time_zone_path_list[] = { #ifdef PATH_TIMEZONEDIR PATH_TIMEZONEDIR, /* search the user specified dir */ #endif SYSLOG_NG_PATH_PREFIX "/share/zoneinfo/", /* then local installation first */ "/usr/share/zoneinfo/", /* linux */ "/usr/share/lib/zoneinfo/", /* solaris, AIX */ NULL, }; static const gchar *time_zone_basedir = NULL; const gchar * get_time_zone_basedir(void) { int i = 0; if (!time_zone_basedir) { for (i = 0; time_zone_path_list[i] != NULL; i++) { const gchar *candidate = get_installation_path_for(time_zone_path_list[i]); if (is_file_directory(candidate)) { time_zone_basedir = candidate; break; } } } return time_zone_basedir; } gboolean is_time_zone_valid(const gchar *tz) { gchar *filename = g_build_path(G_DIR_SEPARATOR_S, get_time_zone_basedir(), tz, NULL); gboolean result = access(filename, R_OK) == 0; g_free(filename); return result; } syslog-ng-syslog-ng-4.4.0/lib/timeutils/zonedb.h000066400000000000000000000022551450431004300215760ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_ZONEDB_H_INCLUDED #define TIMEUTILS_ZONEDB_H_INCLUDED #include "syslog-ng.h" const gchar *get_time_zone_basedir(void); gboolean is_time_zone_valid(const gchar *tz); #endif syslog-ng-syslog-ng-4.4.0/lib/timeutils/zoneinfo.c000066400000000000000000000414161450431004300221410ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "timeutils/zoneinfo.h" #include "timeutils/zonedb.h" #include "reloc.h" #include "messages.h" #include #include #define TZCACHE_SIZE 4 #define TZCACHE_SIZE_MASK (TZCACHE_SIZE - 1) #define TZ_MAGIC "TZif" const gint64 LOWEST_TIME32 = (gint64)((gint32)0x80000000); /** Time zone file parser code **/ /* ** TZ file header ** * * struct tzhead * { * char tzh_magic[4]; TZ_MAGIC "TZif" * char tzh_version[1]; '\0' or '2' or '3' as of 2013 * char tzh_reserved[15]; reserved--must be zero * char tzh_ttisutcnt[4]; coded number of trans. time flags * char tzh_ttisstdcnt[4]; coded number of trans. time flags * char tzh_leapcnt[4]; coded number of leap seconds * char tzh_timecnt[4]; coded number of transition times * char tzh_typecnt[4]; coded number of local time types * char tzh_charcnt[4]; coded number of abbr. chars * }; * ** TZ file body part ** * * tzh_timecnt (char [4])s coded transition times a la time(2) * tzh_timecnt (unsigned char)s types of local time starting at above * tzh_typecnt repetitions of * one (char [4]) coded UT offset in seconds * one (unsigned char) used to set tm_isdst * one (unsigned char) that's an abbreviation list index * tzh_charcnt (char)s '\0'-terminated zone abbreviations * tzh_leapcnt repetitions of * one (char [4]) coded leap second transition times * one (char [4]) total correction after above * tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition time is standard time, if FALSE, transition time is wall clock time; if absent, * transition times are assumed to be wall clock time * tzh_ttisutcnt (char)s indexed by type; if TRUE, transition time is UT, if FALSE, transition time is local time; if absent, * transition times are assumed to be local time. * When this is TRUE, the corresponding std/wall indicator must also be 1. */ /* * A transition from one ZoneType to another * Minimal size = 5 bytes (4+1) */ typedef struct _Transition { gint64 time; /* seconds, 1970 epoch */ gint32 gmtoffset; /* raw seconds offset from GMT */ } Transition; /* A collection of transitions from one zone_type to another, together * with a list of the zone_types. A zone_info object may have a long * list of transitions between a smaller list of zone_types. * * This object represents the contents of a single zic-created * zoneinfo file. */ struct _ZoneInfo { Transition *transitions; gint64 timecnt; gint32 last_transitions_index; }; struct _TimeZoneInfo { ZoneInfo *zone; ZoneInfo *zone64; glong zone_offset; }; /* Read zic-coded 32-bit integer from file*/ static gint64 readcoded32(unsigned char **input, gint64 minv, gint64 maxv) { unsigned char buf[4]; /* must be UNSIGNED */ gint64 val = 0; gint32 i = 0; gint32 shift = 0; memcpy (buf, *input, sizeof(buf)); *input += 4; for (i = 0, shift = 24; i < 4; ++i, shift -= 8) val |= (gint64)(buf[i]) << shift; if (val < minv || val > maxv) { msg_error("Error while processing the time zone file", evt_tag_str("message", "Coded value out-of-range"), evt_tag_int("value", val), evt_tag_printf("expected", "[%"G_GINT64_FORMAT", %"G_GINT64_FORMAT"]", minv, maxv)); g_assert_not_reached(); } return val; } /* Read zic-coded 64-bit integer from file */ static gint64 readcoded64(unsigned char **input, gint64 minv, gint64 maxv) { unsigned char buf[8]; /* must be UNSIGNED */ gint64 val = 0; gint32 i = 0; gint32 shift = 0; memcpy (buf, *input, sizeof(buf)); *input += 8; for (i = 0, shift = 56; i < 8; ++i, shift -= 8) val |= (gint64)buf[i] << shift; if (val < minv || val > maxv) { msg_error("Error while processing the time zone file", evt_tag_str("message", "Coded value out-of-range"), evt_tag_int("value", val), evt_tag_printf("expected", "[%"G_GINT64_FORMAT", %"G_GINT64_FORMAT"]", minv, maxv)); g_assert_not_reached(); } return val; } /* Read a booleanean value */ static gboolean readbool(unsigned char **input) { gchar c; c = **input; *input += 1; if (c!=0 && c!=1) { msg_error("Error while processing the time zone file", evt_tag_str("message", "Boolean value out-of-range"), evt_tag_int("value", c)); g_assert_not_reached(); } return (c != 0); } /* Read a character value */ static gchar readchar(unsigned char **input) { unsigned char c; c = **input; *input += 1; return c; } static ZoneInfo * zone_info_new(gint64 timecnt) { ZoneInfo *self = g_new0(ZoneInfo, 1); self->transitions = g_new0(Transition, timecnt); self->timecnt = timecnt; self->last_transitions_index = -1; return self; } static void zone_info_free(ZoneInfo *self) { if (!self) return; g_free(self->transitions); g_free(self); } /** * Parse the zoneinfo file structure (see tzfile.h) into a ZoneInfo */ static ZoneInfo * zone_info_parser(unsigned char **input, gboolean is64bitData, gint *version) { gint32 i = 0; unsigned char *buf = NULL; ZoneInfo *info = NULL; gint64 *transition_times = NULL; guint8 *transition_types = NULL; gint32 *gmt_offsets = NULL; gint64 isutcnt, isstdcnt, leapcnt, timecnt, typecnt, charcnt; gboolean insertInitial = FALSE; buf = *input; *input += 4; if (strncmp((gchar *)buf, TZ_MAGIC, 4) != 0) { msg_error("Error while processing the time zone file", evt_tag_str("message", TZ_MAGIC" signature is missing")); goto error; } /* read the version byte */ buf = *input; *input += 1; /* * if '\0', we have just one copy of data, * if '2', there is additional 64 bit version at the end. */ if (buf[0] != 0 && buf[0] != '2' && buf[0] != '3') { msg_error("Error in the time zone file", evt_tag_str("message", "Bad Olson version info")); goto error; } else { if (buf[0] != 0) *version = buf[0] - '0'; else *version = 0; } /* Read reserved bytes */ *input += 15; /* Read array sizes */ isutcnt = readcoded32(input, 0, G_MAXINT64); isstdcnt = readcoded32(input, 0, G_MAXINT64); leapcnt = readcoded32(input, 0, G_MAXINT64); timecnt = readcoded32(input, 0, G_MAXINT64); typecnt = readcoded32(input, 0, G_MAXINT64); charcnt = readcoded32(input, 0, G_MAXINT64); /* * Used temporarily to store transition times and types. We need * to do this because the times and types are stored in two * separate arrays. */ transition_times = g_new0(gint64, timecnt); transition_types = g_new0(guint8, timecnt); gmt_offsets = g_new0(gint32, typecnt); /* Read transition times */ for (i = 0; i < timecnt; ++i) { if (is64bitData) { transition_times[i] = readcoded64(input, G_MININT64, G_MAXINT64); } else { transition_times[i] = readcoded32(input, G_MININT64, G_MAXINT64); } } /* Read transition types */ for (i = 0; i < timecnt; ++i) { guint8 t = (guint8)readchar(input); if (t >= typecnt) { msg_warning("Error in the time zone file", evt_tag_str("message", "Illegal type number"), evt_tag_printf("val", "%ld", (long) t), evt_tag_printf("expected", "[0, %" G_GINT64_FORMAT "]", typecnt-1)); goto error; } transition_types[i] = t; } /* Read types (except for the isstd and isut flags, which come later (why??)) */ for (i = 0; i offs * 60 * 60 || gmt_offsets[i] < -1 * offs * 60 * 60) { msg_warning("Error in the time zone file", evt_tag_str("message", "Illegal gmtoffset number"), evt_tag_int("val", gmt_offsets[i]), evt_tag_printf("expected", "[%d, %d]", -1 * offs * 60 * 60, offs * 60 * 60)); goto error; } /* ignore isdst flag */ readbool(input); /* ignore abbr index */ readchar(input); } /* allocate a new ZoneInfo structure */ if (typecnt > 0 && timecnt == 0) { /* only one type info is in the time zone file so add it with 1901 */ info = zone_info_new(1); info->transitions[0].time = LOWEST_TIME32; info->transitions[0].gmtoffset = gmt_offsets[0]; } else { info = zone_info_new(timecnt); } /* Build transitions vector out of corresponding times and types. */ insertInitial = FALSE; if (is64bitData) { if (timecnt > 0) { gint32 minidx = -1; gint32 last_transition_index = 0; for (i = 0; i < timecnt; ++i) { if (transition_times[i] < LOWEST_TIME32) { if (minidx == -1 || transition_times[i] > transition_times[minidx]) { /* Preserve the latest transition before the 32bit minimum time */ minidx = i; } } else { info->transitions[last_transition_index].time = transition_times[i]; info->transitions[last_transition_index].gmtoffset = gmt_offsets[transition_types[i]]; last_transition_index++; } } if (minidx != -1) { /* * If there are any transitions before the 32bit minimum time, * put the type information with the 32bit minimum time */ memmove(&info->transitions[1], &info->transitions[0], sizeof(Transition) * (timecnt-1)); info->transitions[0].time = LOWEST_TIME32; info->transitions[0].gmtoffset = gmt_offsets[transition_types[minidx]]; info->timecnt -= minidx; } else { /* Otherwise, we need insert the initial type later */ insertInitial = TRUE; } } } else { for (i = 0; i < timecnt; ++i) { info->transitions[i].time = transition_times[i]; info->transitions[i].gmtoffset = gmt_offsets[transition_types[i]]; } } if (insertInitial) { g_assert(timecnt > 0); g_assert(typecnt > 0); /* reallocate the transitions vector to be able to store a new entry */ info->timecnt ++; timecnt ++; info->transitions = g_renew(Transition, info->transitions, timecnt); /* Add the initial type associated with the lowest int32 time */ memmove(&info->transitions[1], &info->transitions[0], sizeof(Transition) * (timecnt-1)); info->transitions[0].time = LOWEST_TIME32; info->transitions[0].gmtoffset = gmt_offsets[0]; } /* ignore the abbreviation string */ if (charcnt) *input += charcnt; /* ignore leap second info, if any */ for (i=0; itransitions == NULL) return 0; if (self->last_transitions_index != -1 && self->last_transitions_index < (self->timecnt - 1) && self->transitions[self->last_transitions_index].time <= timestamp && self->transitions[self->last_transitions_index + 1].time > timestamp) { return self->transitions[ self->last_transitions_index ].gmtoffset; } else { for (i = 0; i < (self->timecnt - 1); i++) if (self->transitions[i].time <= timestamp && self->transitions[i+1].time > timestamp) break; self->last_transitions_index = i; } return self->transitions[self->last_transitions_index].gmtoffset; } static gboolean zone_info_read(const gchar *zonename, ZoneInfo **zone, ZoneInfo **zone64) { unsigned char *buff = NULL; gchar *filename = NULL; int byte_read = 0; int version; GError *error = NULL; GMappedFile *file_map = NULL; *zone = NULL; *zone64 = NULL; filename = g_build_path(G_DIR_SEPARATOR_S, get_time_zone_basedir(), zonename, NULL); file_map = g_mapped_file_new(filename, FALSE, &error); if (!file_map) { msg_error("Failed to open the time zone file", evt_tag_str("filename", filename), evt_tag_str("message", error->message)); g_error_free(error); g_free(filename); return FALSE; } byte_read = g_mapped_file_get_length(file_map); buff = (unsigned char *)g_mapped_file_get_contents(file_map); if (byte_read == -1) { msg_error("Failed to read the time zone file", evt_tag_str("filename", filename)); g_mapped_file_unref(file_map); g_free(filename); return FALSE; } msg_debug("Processing the time zone file (32bit part)", evt_tag_str("filename", filename)); *zone = zone_info_parser(&buff, FALSE, &version); if (version == 2) { msg_debug("Processing the time zone file (64bit part)", evt_tag_str("filename", filename)); *zone64 = zone_info_parser(&buff, TRUE, &version); } g_mapped_file_unref(file_map); g_free(filename); return *zone != NULL || *zone64 != NULL; } gint32 time_zone_info_get_offset(const TimeZoneInfo *self, time_t stamp) { if (self == NULL) return -1; if (self->zone_offset != -1) return self->zone_offset; if (self->zone64) return zone_info_get_offset(self->zone64, stamp); if (self->zone) return zone_info_get_offset(self->zone, stamp); return -1; } TimeZoneInfo * time_zone_info_new(const gchar *tz) { TimeZoneInfo *self = g_new0(TimeZoneInfo, 1); self->zone_offset = -1; /* if no time zone was specified return with an empty TimeZoneInfo pointer */ if (!tz) return self; if ((*tz == '+' || *tz == '-') && strlen(tz) == 6 && isdigit((int) *(tz+1)) && isdigit((int) *(tz+2)) && (*(tz+3) == ':') && isdigit((int) *(tz+4)) && isdigit((int) *(tz+5))) { /* timezone offset */ gint sign = *tz == '-' ? -1 : 1; gint hours, mins; tz++; hours = (*tz - '0') * 10 + *(tz+1) - '0'; mins = (*(tz+3) - '0') * 10 + *(tz+4) - '0'; if ((hours < 24 && mins <= 60) || (hours == 24 && mins == 0)) { self->zone_offset = sign * (hours * 3600 + mins * 60); return self; } } else if (zone_info_read(tz, &self->zone, &self->zone64)) { return self; } time_zone_info_free(self); /* failed to read time zone data */ msg_error("Bogus timezone spec, must be in the format [+-]HH:MM, offset must be less than 24:00", evt_tag_str("value", tz)); return NULL; } void time_zone_info_free(TimeZoneInfo *self) { g_assert(self); zone_info_free(self->zone); zone_info_free(self->zone64); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/timeutils/zoneinfo.h000066400000000000000000000025241450431004300221430ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TIMEUTILS_ZONEINFO_H_INCLUDED #define TIMEUTILS_ZONEINFO_H_INCLUDED #include "syslog-ng.h" typedef struct _ZoneInfo ZoneInfo; typedef struct _TimeZoneInfo TimeZoneInfo; gint32 time_zone_info_get_offset(const TimeZoneInfo *self, time_t stamp); TimeZoneInfo *time_zone_info_new(const gchar *tz); void time_zone_info_free(TimeZoneInfo *self); #endifsyslog-ng-syslog-ng-4.4.0/lib/tls-support.h000066400000000000000000000052111450431004300206050ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TLS_SUPPORT_H_INCLUDED #define TLS_SUPPORT_H_INCLUDED /* this header is about Thread Local Storage and not about Transport Layer Security */ #include #ifndef SYSLOG_NG_HAVE_THREAD_KEYWORD #include #include static struct __tls_variables * __tls_init_thread(pthread_key_t key, size_t size) { struct __tls_variables *ptr; ptr = calloc(1, size); if (!ptr) abort(); pthread_setspecific(key, ptr); return ptr; } static inline struct __tls_variables *__tls_deref_helper(pthread_key_t key, size_t size) { struct __tls_variables *ptr; ptr = pthread_getspecific(key); if (!ptr) ptr = __tls_init_thread(key, size); return ptr; } #define TLS_BLOCK_START \ static pthread_key_t __tls_key; \ static void __attribute__((constructor)) __tls_init_key(void) \ { \ pthread_key_create(&__tls_key, free); \ } \ \ struct __tls_variables #define TLS_BLOCK_END #define __tls_deref(var) (*({ struct __tls_variables *__ptr = __tls_deref_helper(__tls_key, sizeof(struct __tls_variables)); &__ptr->var; })) #define __thread # #else /* SYSLOG_NG_HAVE_TLS */ #define TLS_BLOCK_START \ struct __tls_variables #define TLS_BLOCK_END \ ; \ static __thread struct __tls_variables __tls #define __tls_deref(var) (__tls.var) #endif #endif syslog-ng-syslog-ng-4.4.0/lib/transport/000077500000000000000000000000001450431004300201555ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/transport/CMakeLists.txt000066400000000000000000000021731450431004300227200ustar00rootroot00000000000000set(TRANSPORT_HEADERS transport/logtransport.h transport/transport-aux-data.h transport/transport-tls.h transport/transport-file.h transport/transport-pipe.h transport/transport-socket.h transport/transport-udp-socket.h transport/transport-factory-id.h transport/transport-factory.h transport/transport-factory-registry.h transport/multitransport.h transport/transport-factory-tls.h transport/transport-factory-socket.h transport/tls-context.h transport/tls-verifier.h transport/tls-session.h PARENT_SCOPE) set(TRANSPORT_SOURCES transport/logtransport.c transport/transport-aux-data.c transport/transport-file.c transport/transport-pipe.c transport/transport-socket.c transport/transport-udp-socket.c transport/transport-tls.c transport/transport-factory-id.c transport/transport-factory-registry.c transport/multitransport.c transport/transport-factory-tls.c transport/transport-factory-socket.c transport/tls-context.c transport/tls-verifier.c transport/tls-session.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/transport/Makefile.am000066400000000000000000000024761450431004300222220ustar00rootroot00000000000000transportincludedir = ${pkgincludedir}/transport EXTRA_DIST += lib/transport/CMakeLists.txt transportinclude_HEADERS = \ lib/transport/logtransport.h \ lib/transport/transport-aux-data.h \ lib/transport/transport-tls.h \ lib/transport/transport-file.h \ lib/transport/transport-pipe.h \ lib/transport/transport-socket.h \ lib/transport/transport-udp-socket.h \ lib/transport/transport-factory-id.h \ lib/transport/transport-factory.h \ lib/transport/transport-factory-registry.h \ lib/transport/multitransport.h \ lib/transport/transport-factory-tls.h \ lib/transport/transport-factory-socket.h \ lib/transport/tls-context.h \ lib/transport/tls-verifier.h \ lib/transport/tls-session.h transport_sources = \ lib/transport/logtransport.c \ lib/transport/transport-aux-data.c \ lib/transport/transport-file.c \ lib/transport/transport-pipe.c \ lib/transport/transport-socket.c \ lib/transport/transport-udp-socket.c \ lib/transport/transport-factory-id.c \ lib/transport/transport-factory-registry.c \ lib/transport/multitransport.c \ lib/transport/transport-factory-tls.c \ lib/transport/transport-factory-socket.c \ lib/transport/tls-context.c \ lib/transport/tls-verifier.c \ lib/transport/tls-session.c transport_crypto_sources = \ lib/transport/transport-tls.c include lib/transport/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/transport/logtransport.c000066400000000000000000000031001450431004300230510ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logtransport.h" #include "messages.h" #include void log_transport_free_method(LogTransport *s) { if (s->fd != -1) { msg_trace("Closing log transport fd", evt_tag_int("fd", s->fd)); close(s->fd); } } void log_transport_init_instance(LogTransport *self, gint fd) { self->fd = fd; self->cond = 0; self->free_fn = log_transport_free_method; } void log_transport_free(LogTransport *self) { self->free_fn(self); g_free(self); } gint log_transport_release_fd(LogTransport *s) { gint fd = s->fd; s->fd = -1; return fd; } syslog-ng-syslog-ng-4.4.0/lib/transport/logtransport.h000066400000000000000000000042201450431004300230620ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOGTRANSPORT_H_INCLUDED #define LOGTRANSPORT_H_INCLUDED #include "syslog-ng.h" #include "transport/transport-aux-data.h" typedef struct _LogTransport LogTransport; struct _LogTransport { gint fd; GIOCondition cond; const gchar *name; gssize (*read)(LogTransport *self, gpointer buf, gsize count, LogTransportAuxData *aux); gssize (*write)(LogTransport *self, const gpointer buf, gsize count); gssize (*writev)(LogTransport *self, struct iovec *iov, gint iov_count); void (*free_fn)(LogTransport *self); }; static inline gssize log_transport_write(LogTransport *self, const gpointer buf, gsize count) { return self->write(self, buf, count); } static inline gssize log_transport_writev(LogTransport *self, struct iovec *iov, gint iov_count) { return self->writev(self, iov, iov_count); } static inline gssize log_transport_read(LogTransport *self, gpointer buf, gsize count, LogTransportAuxData *aux) { return self->read(self, buf, count, aux); } void log_transport_init_instance(LogTransport *s, gint fd); void log_transport_free_method(LogTransport *s); void log_transport_free(LogTransport *s); gint log_transport_release_fd(LogTransport *s); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/multitransport.c000066400000000000000000000117561450431004300234420ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport/multitransport.h" #include "transport/transport-factory-registry.h" #include "messages.h" void multitransport_add_factory(MultiTransport *self, TransportFactory *transport_factory) { transport_factory_registry_add(self->registry, transport_factory); } static void _do_transport_switch(MultiTransport *self, LogTransport *new_transport, const TransportFactory *new_transport_factory) { self->super.fd = log_transport_release_fd(self->active_transport); self->super.cond = new_transport->cond; log_transport_free(self->active_transport); self->active_transport = new_transport; self->active_transport_factory = new_transport_factory; } static const TransportFactory * _lookup_transport_factory(TransportFactoryRegistry *registry, const TransportFactoryId *factory_id) { const TransportFactory *factory = transport_factory_registry_lookup(registry, factory_id); if (!factory) { msg_error("Requested transport not found", evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id))); return NULL; } return factory; } static LogTransport * _construct_transport(const TransportFactory *factory, gint fd) { LogTransport *transport = transport_factory_construct_transport(factory, fd); const TransportFactoryId *factory_id = transport_factory_get_id(factory); if (!transport) { msg_error("Failed to construct transport", evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id))); return NULL; } return transport; } gboolean multitransport_switch(MultiTransport *self, const TransportFactoryId *factory_id) { msg_debug("Transport switch requested", evt_tag_str("active-transport", self->active_transport->name), evt_tag_str("requested-transport", transport_factory_id_get_transport_name(factory_id))); const TransportFactory *transport_factory = _lookup_transport_factory(self->registry, factory_id); if (!transport_factory) return FALSE; LogTransport *transport = _construct_transport(transport_factory, self->super.fd); if (!transport) return FALSE; _do_transport_switch(self, transport, transport_factory); msg_debug("Transport switch succeeded", evt_tag_str("new-active-transport", self->active_transport->name)); return TRUE; } gboolean multitransport_contains_factory(MultiTransport *self, const TransportFactoryId *factory_id) { const TransportFactory *factory = transport_factory_registry_lookup(self->registry, factory_id); return (factory != NULL); } static gssize _multitransport_write(LogTransport *s, gpointer buf, gsize count) { MultiTransport *self = (MultiTransport *)s; gssize r = log_transport_write(self->active_transport, buf, count); self->super.cond = self->active_transport->cond; return r; } static gssize _multitransport_read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux) { MultiTransport *self = (MultiTransport *)s; gssize r = log_transport_read(self->active_transport, buf, count, aux); self->super.cond = self->active_transport->cond; return r; } static void _multitransport_free(LogTransport *s) { MultiTransport *self = (MultiTransport *)s; s->fd = log_transport_release_fd(self->active_transport); log_transport_free(self->active_transport); transport_factory_registry_free(self->registry); log_transport_free_method(s); } LogTransport * multitransport_new(TransportFactory *default_transport_factory, gint fd) { MultiTransport *self = g_new0(MultiTransport, 1); self->registry = transport_factory_registry_new(); transport_factory_registry_add(self->registry, default_transport_factory); log_transport_init_instance(&self->super, fd); self->super.read = _multitransport_read; self->super.write = _multitransport_write; self->super.free_fn = _multitransport_free; self->active_transport = transport_factory_construct_transport(default_transport_factory, fd); self->active_transport_factory = default_transport_factory; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/multitransport.h000066400000000000000000000033601450431004300234370ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MULTITRANSPORT_H_INCLUDED #define MULTITRANSPORT_H_INCLUDED #include "transport/logtransport.h" #include "transport/transport-factory.h" #include "transport/transport-factory-registry.h" typedef struct _MultiTransport MultiTransport; struct _MultiTransport { LogTransport super; TransportFactoryRegistry *registry; LogTransport *active_transport; const TransportFactory *active_transport_factory; }; LogTransport *multitransport_new(TransportFactory *default_transport_factory, gint fd); void multitransport_add_factory(MultiTransport *, TransportFactory *); gboolean multitransport_switch(MultiTransport *, const TransportFactoryId *); gboolean multitransport_contains_factory(MultiTransport *, const TransportFactoryId *); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/tests/000077500000000000000000000000001450431004300213175ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/transport/tests/CMakeLists.txt000066400000000000000000000004231450431004300240560ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_aux_data) add_unit_test(CRITERION TARGET test_transport_factory_id) add_unit_test(CRITERION TARGET test_transport_factory) add_unit_test(CRITERION TARGET test_transport_factory_registry) add_unit_test(CRITERION TARGET test_multitransport) syslog-ng-syslog-ng-4.4.0/lib/transport/tests/Makefile.am000066400000000000000000000033271450431004300233600ustar00rootroot00000000000000lib_transport_tests_TESTS = \ lib/transport/tests/test_aux_data \ lib/transport/tests/test_transport_factory_id \ lib/transport/tests/test_transport_factory \ lib/transport/tests/test_transport_factory_registry \ lib/transport/tests/test_multitransport EXTRA_DIST += lib/transport/tests/CMakeLists.txt check_PROGRAMS += ${lib_transport_tests_TESTS} lib_transport_tests_test_aux_data_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/transport/tests lib_transport_tests_test_aux_data_LDADD = $(TEST_LDADD) lib_transport_tests_test_aux_data_SOURCES = \ lib/transport/tests/test_aux_data.c lib_transport_tests_test_transport_factory_id_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/transport/tests lib_transport_tests_test_transport_factory_id_LDADD = $(TEST_LDADD) lib_transport_tests_test_transport_factory_id_SOURCES = \ lib/transport/tests/test_transport_factory_id.c lib_transport_tests_test_transport_factory_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/transport/tests lib_transport_tests_test_transport_factory_LDADD = $(TEST_LDADD) lib_transport_tests_test_transport_factory_SOURCES = \ lib/transport/tests/test_transport_factory.c lib_transport_tests_test_transport_factory_registry_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/transport/tests lib_transport_tests_test_transport_factory_registry_LDADD = $(TEST_LDADD) lib_transport_tests_test_transport_factory_registry_SOURCES = \ lib/transport/tests/test_transport_factory_registry.c lib_transport_tests_test_multitransport_CFLAGS = $(TEST_CFLAGS) \ -I${top_srcdir}/lib/transport/tests lib_transport_tests_test_multitransport_LDADD = $(TEST_LDADD) lib_transport_tests_test_multitransport_SOURCES = \ lib/transport/tests/test_multitransport.c syslog-ng-syslog-ng-4.4.0/lib/transport/tests/test_aux_data.c000066400000000000000000000114241450431004300243120ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include #include "transport/transport-aux-data.h" #include "apphook.h" LogTransportAuxData *aux = NULL; static LogTransportAuxData * construct_empty_aux(void) { LogTransportAuxData *self = g_new(LogTransportAuxData, 1); log_transport_aux_data_init(self); return self; } static void free_aux(LogTransportAuxData *self) { log_transport_aux_data_destroy(self); g_free(self); } static LogTransportAuxData * construct_aux_with_some_data(void) { LogTransportAuxData *self = construct_empty_aux(); /* set peer_addr twice to validate that peer_addr is correctly reference counted */ log_transport_aux_data_set_peer_addr_ref(self, g_sockaddr_inet_new("1.2.3.4", 5555)); log_transport_aux_data_set_peer_addr_ref(self, g_sockaddr_inet_new("1.2.3.4", 5555)); log_transport_aux_data_add_nv_pair(self, "foo", "bar"); return self; } Test(aux_data, test_aux_data_reinit_returns_aux_into_initial_state_without_leaks) { log_transport_aux_data_reinit(aux); cr_assert_null(aux->peer_addr, "aux->peer_addr is not NULL after reinit"); } static void _concat_nvpairs_helper(const gchar *name, const gchar *value, gsize value_len, gpointer user_data) { GString *concatenated = (GString *) user_data; g_string_append_printf(concatenated, "%s=%s\n", name, value); cr_assert_eq(value_len, strlen(value), "foreach() length mismatch"); } static gchar * _concat_nvpairs(LogTransportAuxData *self) { GString *concatenated = g_string_sized_new(0); log_transport_aux_data_foreach(self, _concat_nvpairs_helper, concatenated); return g_string_free(concatenated, FALSE); } static void assert_concatenated_nvpairs(LogTransportAuxData *self, const gchar *expected) { gchar *concatenated = _concat_nvpairs(self); cr_assert_str_eq(concatenated, expected, "foreach() didn't return all-added nvpairs"); g_free(concatenated); } Test(aux_data, test_aux_data_added_nvpairs_are_returned_by_foreach_in_order) { log_transport_aux_data_add_nv_pair(aux, "super", "lativus"); assert_concatenated_nvpairs(aux, "foo=bar\nsuper=lativus\n"); } Test(aux_data, test_aux_data_copy_creates_an_identical_copy) { LogTransportAuxData aux_copy; gchar *orig, *copy; log_transport_aux_data_copy(&aux_copy, aux); orig = _concat_nvpairs(aux); copy = _concat_nvpairs(&aux_copy); cr_assert_str_eq(orig, copy, "copy incorrectly copied aux->nvpairs"); g_free(orig); g_free(copy); log_transport_aux_data_destroy(&aux_copy); } Test(aux_data, test_aux_data_copy_separates_the_copies) { LogTransportAuxData aux_copy; gchar *orig, *copy; log_transport_aux_data_copy(&aux_copy, aux); log_transport_aux_data_add_nv_pair(aux, "super", "lativus"); orig = _concat_nvpairs(aux); copy = _concat_nvpairs(&aux_copy); cr_assert_str_neq(orig, copy, "copy incorrectly copied aux->nvpairs as change to one of them affected the other, orig=%s, copy=%s", orig, copy); g_free(orig); g_free(copy); log_transport_aux_data_destroy(&aux_copy); } Test(aux_data, test_add_nv_pair_to_a_NULL_aux_data_will_do_nothing) { log_transport_aux_data_add_nv_pair(NULL, "foo", "bar"); assert_concatenated_nvpairs(NULL, ""); } Test(aux_data, test_aux_data_functions_with_NULL_instance_does_nothing) { aux = NULL; log_transport_aux_data_init(aux); log_transport_aux_data_reinit(aux); log_transport_aux_data_destroy(aux); log_transport_aux_data_init(aux); /* set peer_addr twice to validate that peer_addr is correctly reference counted */ log_transport_aux_data_set_peer_addr_ref(aux, g_sockaddr_inet_new("1.2.3.4", 5555)); log_transport_aux_data_set_peer_addr_ref(aux, g_sockaddr_inet_new("1.2.3.4", 5555)); } static void setup(void) { app_startup(); aux = construct_aux_with_some_data(); } static void teardown(void) { free_aux(aux); app_shutdown(); } TestSuite(aux_data, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/transport/tests/test_multitransport.c000066400000000000000000000107271450431004300256400ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "transport/multitransport.h" #include "transport/transport-factory.h" #include "apphook.h" #define DEFINE_TEST_TRANSPORT_WITH_FACTORY(TypePrefix, FunPrefix) \ typedef struct TypePrefix ## Transport_ TypePrefix ## Transport; \ typedef struct TypePrefix ## TransportFactory_ TypePrefix ## TransportFactory; \ struct TypePrefix ## Transport_ \ { \ LogTransport super; \ }; \ static gssize \ FunPrefix ## _read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux) \ { \ return count; \ }\ static gssize \ FunPrefix ## _write(LogTransport *s, const gpointer buf, gsize count) \ { \ return count; \ }\ LogTransport * \ FunPrefix ## _transport_new(void) \ { \ TypePrefix ## Transport *self = g_new0(TypePrefix ## Transport, 1); \ self->super.read = FunPrefix ## _read; \ self->super.write = FunPrefix ## _write; \ return &self->super; \ } \ struct TypePrefix ## TransportFactory_\ { \ TransportFactory super; \ }; \ DEFINE_TRANSPORT_FACTORY_ID_FUN(#FunPrefix, FunPrefix ## _transport_factory_id); \ static LogTransport * \ FunPrefix ## _factory_construct(const TransportFactory *s, gint fd) \ {\ LogTransport *transport = FunPrefix ## _transport_new(); \ log_transport_init_instance(transport, fd); \ return transport; \ } \ TransportFactory * \ FunPrefix ## _transport_factory_new(void) \ { \ TypePrefix ## TransportFactory *self = g_new0(TypePrefix ## TransportFactory, 1); \ self->super.id = FunPrefix ## _transport_factory_id(); \ self->super.construct_transport = FunPrefix ## _factory_construct; \ return &self->super; \ } \ TestSuite(multitransport, .init = app_startup, .fini = app_shutdown); DEFINE_TEST_TRANSPORT_WITH_FACTORY(Fake, fake); DEFINE_TEST_TRANSPORT_WITH_FACTORY(Default, default); DEFINE_TEST_TRANSPORT_WITH_FACTORY(Unregistered, unregistered); Test(multitransport, test_switch_transport) { TransportFactory *default_factory = default_transport_factory_new(); TransportFactory *fake_factory = fake_transport_factory_new(); gint fd = -2; MultiTransport *multi_transport = (MultiTransport *) multitransport_new(default_factory, fd); cr_expect_eq(multi_transport->active_transport->read, default_read); cr_expect_eq(multi_transport->active_transport->write, default_write); cr_expect_str_eq(multi_transport->active_transport->name, "default"); multitransport_add_factory(multi_transport, fake_factory); cr_expect_not(multitransport_contains_factory(multi_transport, unregistered_transport_factory_id())); cr_expect(multitransport_contains_factory(multi_transport, fake_transport_factory_id())); cr_expect(multitransport_contains_factory(multi_transport, default_transport_factory_id())); cr_expect_not(multitransport_switch(multi_transport, unregistered_transport_factory_id())); cr_expect_eq(multi_transport->active_transport->read, default_read); cr_expect_eq(multi_transport->active_transport->write, default_write); cr_expect_eq(multi_transport->active_transport_factory, default_factory); cr_expect_str_eq(multi_transport->active_transport->name, "default"); cr_expect(multitransport_switch(multi_transport, fake_transport_factory_id())); cr_expect_eq(multi_transport->active_transport->read, fake_read); cr_expect_eq(multi_transport->active_transport->write, fake_write); cr_expect_eq(multi_transport->active_transport_factory, fake_factory); cr_expect_str_eq(multi_transport->active_transport->name, "fake"); log_transport_free(&multi_transport->super); } syslog-ng-syslog-ng-4.4.0/lib/transport/tests/test_transport_factory.c000066400000000000000000000057051450431004300263140ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "transport/transport-factory.h" #include "apphook.h" typedef struct _FakeTransport FakeTransport; typedef struct _FakeTransportFactory FakeTransportFactory; struct _FakeTransport { LogTransport super; gboolean constructed; }; static gssize _fake_read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *auc) { return count; } static gssize _fake_write(LogTransport *s, const gpointer buf, gsize count) { return count; } static void _fake_free(LogTransport *s) { } LogTransport * _fake_transport_new(void) { FakeTransport *instance = g_new0(FakeTransport, 1); instance->super.read = _fake_read; instance->super.write = _fake_write; instance->constructed = TRUE; return &instance->super; } struct _FakeTransportFactory { TransportFactory super; }; DEFINE_TRANSPORT_FACTORY_ID_FUN("fake", _fake_transport_factory_id); static LogTransport * _transport_factory_construct(const TransportFactory *s, gint fd) { LogTransport *fake_transport = _fake_transport_new(); log_transport_init_instance(fake_transport, fd); fake_transport->free_fn = _fake_free; return fake_transport; } TransportFactory * _fake_transport_factory_new(void) { FakeTransportFactory *instance = g_new0(FakeTransportFactory, 1); instance->super.id = _fake_transport_factory_id(); instance->super.construct_transport = _transport_factory_construct; return &instance->super; } TestSuite(transport_factory, .init = app_startup, .fini = app_shutdown); Test(transport_factory, fake_transport_factory) { TransportFactory *fake_factory = _fake_transport_factory_new(); cr_expect_not_null(fake_factory->id); gint fd = 11; FakeTransport *fake_transport = (FakeTransport *) transport_factory_construct_transport(fake_factory, fd); cr_expect_eq(fake_transport->constructed, TRUE); cr_expect_eq(fake_transport->super.read, _fake_read); cr_expect_eq(fake_transport->super.write, _fake_write); log_transport_free(&fake_transport->super); transport_factory_free(fake_factory); } syslog-ng-syslog-ng-4.4.0/lib/transport/tests/test_transport_factory_id.c000066400000000000000000000051171450431004300267650ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "transport/transport-factory-id.h" #include "apphook.h" TestSuite(transport_factory_id, .init = transport_factory_id_global_init, .fini = transport_factory_id_global_deinit); Test(transport_factory_id_lifecycle, lifecycle) { transport_factory_id_global_init(); GList *ids = _transport_factory_id_clone_registered_ids(); cr_expect_null(ids); TransportFactoryId *id = _transport_factory_id_new("tcp"); TransportFactoryId *expected = _transport_factory_id_clone(id); _transport_factory_id_register(id); ids = _transport_factory_id_clone_registered_ids(); cr_assert_not_null(ids, "transport_factory_id_register failed"); cr_expect(transport_factory_id_equal(ids->data, expected)); transport_factory_id_free(expected); g_list_free_full(ids, (GDestroyNotify)transport_factory_id_free); transport_factory_id_global_deinit(); ids = _transport_factory_id_clone_registered_ids(); cr_expect_null(ids); } Test(transport_factory_id_basic_macros, generated_ids_are_uniq) { TransportFactoryId *id = _transport_factory_id_new("tcp"); TransportFactoryId *id2 = _transport_factory_id_new("tcp"); cr_expect_not(transport_factory_id_equal(id, id2)); transport_factory_id_free(id); transport_factory_id_free(id2); } Test(transport_factory_id_basic_macros, clones_are_equals) { TransportFactoryId *id = _transport_factory_id_new("tcp"); TransportFactoryId *cloned = _transport_factory_id_clone(id); cr_expect(transport_factory_id_equal(id, cloned)); cr_expect_eq(transport_factory_id_hash(id), transport_factory_id_hash(cloned)); transport_factory_id_free(id); transport_factory_id_free(cloned); } syslog-ng-syslog-ng-4.4.0/lib/transport/tests/test_transport_factory_registry.c000066400000000000000000000055711450431004300302450ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "transport/transport-factory-registry.h" #include "apphook.h" typedef struct _TestTransportFactory { TransportFactory super; } TestTransportFactory; DEFINE_TRANSPORT_FACTORY_ID_FUN("test", test_transport_factory_id); static TestTransportFactory * _test_transport_factory_new(void) { TestTransportFactory *instance = g_new0(TestTransportFactory, 1); instance->super.id = test_transport_factory_id(); return instance; } TestSuite(transport_factory_registry, .init = app_startup, .fini = app_shutdown); Test(transport_factory_registry, basic_functionality) { TransportFactoryRegistry *registry = transport_factory_registry_new(); TestTransportFactory *factory = _test_transport_factory_new(); transport_factory_registry_add(registry, &factory->super); const TransportFactory *looked_up_factory = (TransportFactory *)transport_factory_registry_lookup(registry, test_transport_factory_id()); cr_expect_eq((gpointer)factory, (gpointer)looked_up_factory); TestTransportFactory *removed_factory = (TestTransportFactory *)transport_factory_registry_remove(registry, test_transport_factory_id()); cr_expect_eq((gpointer)factory, (gpointer)removed_factory); cr_expect_null(transport_factory_registry_lookup(registry, test_transport_factory_id())); transport_factory_free(&removed_factory->super); transport_factory_registry_free(registry); } Test(transport_factory_registry, abort_when_add_different_factory_with_same_id, .signal=SIGABRT) { TransportFactoryRegistry *registry = transport_factory_registry_new(); TestTransportFactory *factory = _test_transport_factory_new(); TestTransportFactory *factory2 = _test_transport_factory_new(); transport_factory_registry_add(registry, &factory->super); transport_factory_registry_add(registry, &factory2->super); transport_factory_registry_free(registry); } syslog-ng-syslog-ng-4.4.0/lib/transport/tls-context.c000066400000000000000000000636111450431004300226140ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport/tls-context.h" #include "messages.h" #include "compat/openssl_support.h" #include "secret-storage/secret-storage.h" #include #include #include #include #include #include #include #include #include #include typedef enum { TLS_CONTEXT_OK, TLS_CONTEXT_ERROR, TLS_CONTEXT_FILE_ACCES_ERROR, TLS_CONTEXT_PASSWORD_ERROR } TLSContextLoadResult; /* TLSContext */ EVTTAG * tls_context_format_tls_error_tag(TLSContext *self) { gint ssl_error = ERR_get_error(); char buf[256]; ERR_error_string_n(ssl_error, buf, sizeof(buf)); return evt_tag_str("tls_error", buf); } EVTTAG * tls_context_format_location_tag(TLSContext *self) { return evt_tag_str("location", self->location); } static gboolean _is_file_accessible(TLSContext *self, const gchar *fname) { if (!fname) return FALSE; if (access(fname, R_OK) < 0) { msg_error("Error opening TLS related key or certificate file", evt_tag_str("filename", fname), evt_tag_error("error"), tls_context_format_location_tag(self)); return FALSE; } return TRUE; } static void _print_and_clear_tls_session_error(TLSContext *self) { msg_error("Error setting up TLS session context", tls_context_format_tls_error_tag(self), tls_context_format_location_tag(self)); ERR_clear_error(); } #if OPENSSL_VERSION_NUMBER >= 0x10101000L void _write_line_to_keylog_file(const char *file_path, const char *line, FILE *keylog_file, GMutex *mutex) { if(!keylog_file) return; g_mutex_lock(mutex); gint ret_val = fprintf(keylog_file, "%s\n", line); if (ret_val != strlen(line)+1) msg_error("Couldn't write to TLS keylogfile", evt_tag_errno("error", ret_val)); fflush(keylog_file); g_mutex_unlock(mutex); } static void _dump_tls_keylog(const SSL *ssl, const char *line) { if(!ssl) return; SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(ssl); TLSContext *self = SSL_CTX_get_app_data(ssl_ctx); _write_line_to_keylog_file(self->keylog_file_path, line, self->keylog_file, &self->keylog_file_lock); } static gboolean _setup_keylog_file(TLSContext *self) { if (!self->keylog_file_path) return TRUE; self->keylog_file = fopen(self->keylog_file_path, "a"); if(!self->keylog_file) { msg_error("Error opening keylog-file", evt_tag_str(EVT_TAG_FILENAME, self->keylog_file_path), evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } SSL_CTX_set_keylog_callback(self->ssl_ctx, _dump_tls_keylog); return TRUE; } #else static gboolean _setup_keylog_file(TLSContext *self) { return TRUE; } #endif static void tls_context_setup_session_tickets(TLSContext *self) { openssl_ctx_setup_session_tickets(self->ssl_ctx); } static void tls_context_setup_verify_mode(TLSContext *self) { gint verify_mode = 0; switch (self->verify_mode) { case TVM_OPTIONAL | TVM_UNTRUSTED: verify_mode = SSL_VERIFY_NONE; break; case TVM_OPTIONAL | TVM_TRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; break; case TVM_REQUIRED | TVM_UNTRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; break; case TVM_REQUIRED | TVM_TRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; break; default: g_assert_not_reached(); } SSL_CTX_set_verify(self->ssl_ctx, verify_mode, tls_session_verify_callback); } static void tls_context_setup_ocsp_stapling(TLSContext *self) { if (self->mode == TM_CLIENT && self->ocsp_stapling_verify) { long status_cb_set = SSL_CTX_set_tlsext_status_cb(self->ssl_ctx, tls_session_ocsp_client_verify_callback); g_assert(status_cb_set); return; } if (self->mode == TM_SERVER) { g_assert(!self->ocsp_stapling_verify && "OCSP stapling and its verification are currently not implemented on the server side"); } } static void tls_context_setup_ssl_options(TLSContext *self) { if (self->ssl_options != TSO_NONE) { glong ssl_options = 0; if(self->ssl_options & TSO_NOSSLv2) ssl_options |= SSL_OP_NO_SSLv2; if(self->ssl_options & TSO_NOSSLv3) ssl_options |= SSL_OP_NO_SSLv3; if(self->ssl_options & TSO_NOTLSv1) ssl_options |= SSL_OP_NO_TLSv1; #ifdef SSL_OP_NO_TLSv1_2 if(self->ssl_options & TSO_NOTLSv11) ssl_options |= SSL_OP_NO_TLSv1_1; if(self->ssl_options & TSO_NOTLSv12) ssl_options |= SSL_OP_NO_TLSv1_2; #endif #ifdef SSL_OP_NO_TLSv1_3 if(self->ssl_options & TSO_NOTLSv13) ssl_options |= SSL_OP_NO_TLSv1_3; #endif #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF if (self->ssl_options & TSO_IGNORE_UNEXPECTED_EOF) ssl_options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE if (self->mode == TM_SERVER) ssl_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; #endif SSL_CTX_set_options(self->ssl_ctx, ssl_options); } else { msg_debug("No special SSL options were specified", tls_context_format_location_tag(self)); } } static gboolean _set_optional_ecdh_curve_list(SSL_CTX *ctx, const gchar *ecdh_curve_list) { #if OPENSSL_VERSION_NUMBER >= 0x10002000L if (ecdh_curve_list && !SSL_CTX_set1_curves_list(ctx, ecdh_curve_list)) { msg_error("Error setting up TLS session context, invalid curve name in list", evt_tag_str("ecdh_curve_list", ecdh_curve_list)); return FALSE; } #endif return TRUE; } static gboolean tls_context_setup_ecdh(TLSContext *self) { if (!_set_optional_ecdh_curve_list(self->ssl_ctx, self->ecdh_curve_list)) return FALSE; openssl_ctx_setup_ecdh(self->ssl_ctx); return TRUE; } static gboolean tls_context_setup_dh(TLSContext *self) { if (!self->dhparam_file) return openssl_ctx_setup_dh(self->ssl_ctx); if(!_is_file_accessible(self, self->dhparam_file)) return FALSE; if (!openssl_ctx_load_dh_from_file(self->ssl_ctx, self->dhparam_file)) { msg_error("Error setting up TLS session context, invalid DH parameters", evt_tag_str("dhparam_file", self->dhparam_file)); return FALSE; } return TRUE; } static gboolean tls_context_setup_cipher_suite(TLSContext *self) { if (self->cipher_suite && !SSL_CTX_set_cipher_list(self->ssl_ctx, self->cipher_suite)) return FALSE; #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET_CIPHERSUITES if (self->tls13_cipher_suite && !SSL_CTX_set_ciphersuites(self->ssl_ctx, self->tls13_cipher_suite)) return FALSE; #endif return TRUE; } static gboolean tls_context_setup_sigalgs(TLSContext *self) { #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET1_SIGALGS_LIST if (self->sigalgs && !SSL_CTX_set1_sigalgs_list(self->ssl_ctx, self->sigalgs)) return FALSE; #endif #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET1_CLIENT_SIGALGS_LIST if (self->client_sigalgs && !SSL_CTX_set1_client_sigalgs_list(self->ssl_ctx, self->client_sigalgs)) return FALSE; #endif return TRUE; } static gboolean tls_context_setup_cmd_context(TLSContext *self) { SSL_CONF_CTX *ssl_conf_ctx = SSL_CONF_CTX_new(); const int ctx_flags = SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT | SSL_CONF_FLAG_SERVER | SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS; int set_flags = SSL_CONF_CTX_set_flags(ssl_conf_ctx, ctx_flags); gboolean result = (set_flags == ctx_flags); if (result) { SSL_CONF_CTX_set_ssl_ctx(ssl_conf_ctx, self->ssl_ctx); for (GList *next_pair = self->conf_cmds_list; next_pair; next_pair = next_pair->next) { gchar *cmd = next_pair->data; next_pair = next_pair->next; gchar *value = next_pair->data; int add_result = SSL_CONF_cmd(ssl_conf_ctx, cmd, value); if (add_result < 1) msg_error("Error setting up SSL conf context, invalid cmd or value in config list", evt_tag_str("cmd", cmd), evt_tag_str("value", value), tls_context_format_location_tag(self)); result = result && (add_result >= 1); } result = result && (SSL_CONF_CTX_finish(ssl_conf_ctx) == 1); } SSL_CONF_CTX_free(ssl_conf_ctx); return result; } static PKCS12 * _load_pkcs12_file(TLSContext *self, const gchar *pkcs12_file) { if (!_is_file_accessible(self, pkcs12_file)) return NULL; FILE *p12_file = fopen(pkcs12_file, "rb"); if (!p12_file) return NULL; PKCS12 *pkcs12 = d2i_PKCS12_fp(p12_file, NULL); fclose(p12_file); return pkcs12; } static gboolean _extract_pkcs12_content(PKCS12 *pkcs12, EVP_PKEY **private_key, X509 **cert, STACK_OF(X509) **ca_list) { return PKCS12_parse(pkcs12, "", private_key, cert, ca_list); } static gboolean tls_context_add_certs(TLSContext *self, STACK_OF(X509) *ca_list) { for (gint ca_index = 0; ca_index < sk_X509_num(ca_list); ++ca_index) { X509 *current_ca = sk_X509_value(ca_list, ca_index); if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(self->ssl_ctx), current_ca)) return FALSE; if (self->mode == TM_SERVER && !SSL_CTX_add_client_CA(self->ssl_ctx, current_ca)) return FALSE; } return TRUE; } static gboolean tls_context_load_pkcs12(TLSContext *self) { PKCS12 *pkcs12 = _load_pkcs12_file(self, self->pkcs12_file); if (!pkcs12) return FALSE; EVP_PKEY *private_key; X509 *cert; STACK_OF(X509) *ca_list = NULL; if (!_extract_pkcs12_content(pkcs12, &private_key, &cert, &ca_list)) { PKCS12_free(pkcs12); return FALSE; } PKCS12_free(pkcs12); gboolean loaded = FALSE; if (ca_list && !tls_context_add_certs(self, ca_list)) goto error; loaded = SSL_CTX_use_certificate(self->ssl_ctx, cert) && SSL_CTX_use_PrivateKey(self->ssl_ctx, private_key) && SSL_CTX_check_private_key(self->ssl_ctx); error: X509_free(cert); EVP_PKEY_free(private_key); sk_X509_pop_free(ca_list, X509_free); return loaded; } static gboolean _are_key_and_cert_files_accessible(TLSContext *self) { gboolean key_file_accessible = _is_file_accessible(self, self->key_file); gboolean cert_file_accessible = _is_file_accessible(self, self->cert_file); return key_file_accessible && cert_file_accessible; } static gboolean _key_or_cert_file_is_not_specified(TLSContext *self) { return (!self->key_file || !self->cert_file); } static TLSContextLoadResult tls_context_load_key_and_cert(TLSContext *self) { if (_key_or_cert_file_is_not_specified(self)) { if (self->mode == TM_SERVER) msg_warning("You have a TLS enabled source without a X.509 keypair. Make sure you have tls(key-file() and cert-file()) options, TLS handshake to this source will fail", tls_context_format_location_tag(self)); return TLS_CONTEXT_OK; } if (!_are_key_and_cert_files_accessible(self)) return TLS_CONTEXT_FILE_ACCES_ERROR; if (!SSL_CTX_use_PrivateKey_file(self->ssl_ctx, self->key_file, SSL_FILETYPE_PEM)) return TLS_CONTEXT_PASSWORD_ERROR; if (!SSL_CTX_use_certificate_chain_file(self->ssl_ctx, self->cert_file)) return TLS_CONTEXT_ERROR; if (self->cert_file && !SSL_CTX_check_private_key(self->ssl_ctx)) return TLS_CONTEXT_PASSWORD_ERROR; return TLS_CONTEXT_OK; } static void _ca_list_free(STACK_OF(X509_NAME) *ca_list) { for (gint i = 0; i < sk_X509_NAME_num(ca_list); i++) X509_NAME_free(sk_X509_NAME_value(ca_list, i)); sk_X509_NAME_free(ca_list); } static gboolean _set_client_ca_list(TLSContext *self) { #if SYSLOG_NG_HAVE_DECL_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK && SYSLOG_NG_HAVE_DECL_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null(); const STACK_OF(X509_NAME) *existing_ca_list = SSL_CTX_get_client_CA_list(self->ssl_ctx); for (gint i = 0; i < sk_X509_NAME_num(existing_ca_list); i++) { sk_X509_NAME_push(ca_list, X509_NAME_dup(sk_X509_NAME_value(existing_ca_list, i))); } if (_is_file_accessible(self, self->ca_dir) && !SSL_add_dir_cert_subjects_to_stack(ca_list, self->ca_dir)) { _ca_list_free(ca_list); return FALSE; } if (_is_file_accessible(self, self->ca_file) && !SSL_add_file_cert_subjects_to_stack(ca_list, self->ca_file)) { _ca_list_free(ca_list); return FALSE; } SSL_CTX_set_client_CA_list(self->ssl_ctx, ca_list); return TRUE; #else msg_warning_once("Setting the client CA list based on the ca-file() and ca-dir() options is not supported with the " "OpenSSL version syslog-ng was compiled with"); return TRUE; #endif } gboolean tls_context_verify_peer(TLSContext *self, X509 *peer_cert, const gchar *peer_name) { if ((tls_context_get_verify_mode(self) & TVM_TRUSTED) == 0) { msg_warning("Bypassing certificate validation, peer certificate is always accepted"); return TRUE; } if (!peer_name) return TRUE; if (!tls_verify_certificate_name(peer_cert, peer_name)) { if (tls_context_ignore_hostname_mismatch(self)) { msg_warning("Ignoring certificate subject validation error due to options(ignore-hostname-mismatch)", evt_tag_str("hostname", peer_name)); return TRUE; } return FALSE; } return TRUE; } TLSContextSetupResult tls_context_setup_context(TLSContext *self) { gint verify_flags = X509_V_FLAG_POLICY_CHECK; if (!self->ssl_ctx) goto error; if (!_setup_keylog_file(self)) goto error; if (self->pkcs12_file) { if (self->cert_file || self->key_file) msg_warning("WARNING: pkcs12-file() is specified, key-file() and cert-file() will be omitted", tls_context_format_location_tag(self)); if (!tls_context_load_pkcs12(self)) goto error; } else { TLSContextLoadResult r = tls_context_load_key_and_cert(self); if (r == TLS_CONTEXT_PASSWORD_ERROR) goto password_error; if (r != TLS_CONTEXT_OK) goto error; } if (_is_file_accessible(self, self->ca_dir) && !SSL_CTX_load_verify_locations(self->ssl_ctx, NULL, self->ca_dir)) goto error; if (_is_file_accessible(self, self->ca_file) && !SSL_CTX_load_verify_locations(self->ssl_ctx, self->ca_file, NULL)) goto error; if (_is_file_accessible(self, self->crl_dir) && !SSL_CTX_load_verify_locations(self->ssl_ctx, NULL, self->crl_dir)) goto error; if (self->mode == TM_SERVER && !_set_client_ca_list(self)) goto error; if (self->crl_dir) verify_flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(self->ssl_ctx), verify_flags); if (self->mode == TM_SERVER) tls_context_setup_session_tickets(self); tls_context_setup_verify_mode(self); tls_context_setup_ocsp_stapling(self); tls_context_setup_ssl_options(self); if (!tls_context_setup_ecdh(self)) goto error_no_print; if (!tls_context_setup_dh(self)) goto error; if (!tls_context_setup_cipher_suite(self)) goto error; if (!tls_context_setup_sigalgs(self)) goto error; if (!tls_context_setup_cmd_context(self)) goto error; return TLS_CONTEXT_SETUP_OK; error: _print_and_clear_tls_session_error(self); error_no_print: if (self->ssl_ctx) { SSL_CTX_free(self->ssl_ctx); self->ssl_ctx = NULL; } return TLS_CONTEXT_SETUP_ERROR; password_error: _print_and_clear_tls_session_error(self); return TLS_CONTEXT_SETUP_BAD_PASSWORD; } TLSSession * tls_context_setup_session(TLSContext *self) { if (!self->ssl_ctx) return NULL; SSL *ssl = SSL_new(self->ssl_ctx); if (self->mode == TM_CLIENT) SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); if (self->mode == TM_CLIENT && self->ocsp_stapling_verify) { long ocsp_enabled = SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); g_assert(ocsp_enabled); } TLSSession *session = tls_session_new(ssl, self); if (!session) { SSL_free(ssl); return NULL; } SSL_set_app_data(ssl, session); return session; } gboolean tls_context_set_verify_mode_by_name(TLSContext *self, const gchar *mode_str) { if (strcasecmp(mode_str, "optional-trusted") == 0 || strcasecmp(mode_str, "optional_trusted") == 0) self->verify_mode = TVM_OPTIONAL | TVM_TRUSTED; else if (strcasecmp(mode_str, "optional-untrusted") == 0 || strcasecmp(mode_str, "optional_untrusted") == 0 || strcasecmp(mode_str, "none") == 0) self->verify_mode = TVM_OPTIONAL | TVM_UNTRUSTED; else if (strcasecmp(mode_str, "required-trusted") == 0 || strcasecmp(mode_str, "required_trusted") == 0) self->verify_mode = TVM_REQUIRED | TVM_TRUSTED; else if (strcasecmp(mode_str, "required-untrusted") == 0 || strcasecmp(mode_str, "required_untrusted") == 0) self->verify_mode = TVM_REQUIRED | TVM_UNTRUSTED; else return FALSE; return TRUE; } gboolean tls_context_set_ssl_options_by_name(TLSContext *self, GList *options) { self->ssl_options = TSO_NONE; GList *l; for (l=options; l != NULL; l=l->next) { if (strcasecmp(l->data, "no-sslv2") == 0 || strcasecmp(l->data, "no_sslv2") == 0) self->ssl_options |= TSO_NOSSLv2; else if (strcasecmp(l->data, "no-sslv3") == 0 || strcasecmp(l->data, "no_sslv3") == 0) self->ssl_options |= TSO_NOSSLv3; else if (strcasecmp(l->data, "no-tlsv1") == 0 || strcasecmp(l->data, "no_tlsv1") == 0) self->ssl_options |= TSO_NOTLSv1; #ifdef SSL_OP_NO_TLSv1_2 else if (strcasecmp(l->data, "no-tlsv11") == 0 || strcasecmp(l->data, "no_tlsv11") == 0) self->ssl_options |= TSO_NOTLSv11; else if (strcasecmp(l->data, "no-tlsv12") == 0 || strcasecmp(l->data, "no_tlsv12") == 0) self->ssl_options |= TSO_NOTLSv12; #endif #ifdef SSL_OP_NO_TLSv1_3 else if (strcasecmp(l->data, "no-tlsv13") == 0 || strcasecmp(l->data, "no_tlsv13") == 0) self->ssl_options |= TSO_NOTLSv13; #endif #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF else if (strcasecmp(l->data, "ignore-unexpected-eof") == 0 || strcasecmp(l->data, "ignore_unexpected_eof") == 0) self->ssl_options |= TSO_IGNORE_UNEXPECTED_EOF; #endif else if (strcasecmp(l->data, "ignore-hostname-mismatch") == 0 || strcasecmp(l->data, "ignore_hostname_mismatch") == 0) self->ssl_options |= TSO_IGNORE_HOSTNAME_MISMATCH; else return FALSE; } return TRUE; } gint tls_context_get_verify_mode(const TLSContext *self) { return self->verify_mode; } void tls_context_set_verify_mode(TLSContext *self, gint verify_mode) { self->verify_mode = verify_mode; } gboolean tls_context_ignore_hostname_mismatch(TLSContext *self) { return self->ssl_options & TSO_IGNORE_HOSTNAME_MISMATCH; } static int _pem_passwd_callback(char *buf, int size, int rwflag, void *user_data) { if (!user_data) return 0; gchar *key = (gchar *)user_data; Secret *secret = secret_storage_get_secret_by_name(key); if (!secret) return 0; size_t len = secret->len; if (secret->len > size) { len = size; msg_warning("Password is too long, will be truncated", evt_tag_int("original_length", secret->len), evt_tag_int("truncated_length", size)); } memcpy(buf, secret->data, len); secret_storage_put_secret(secret); return len; } void tls_context_set_key_file(TLSContext *self, const gchar *key_file) { g_free(self->key_file); self->key_file = g_strdup(key_file); SSL_CTX_set_default_passwd_cb(self->ssl_ctx, _pem_passwd_callback); SSL_CTX_set_default_passwd_cb_userdata(self->ssl_ctx, self->key_file); } gboolean tls_context_set_keylog_file(TLSContext *self, gchar *keylog_file_path, GError **error) { #if OPENSSL_VERSION_NUMBER >= 0x10101000L g_free(self->keylog_file_path); msg_warning_once("WARNING: TLS keylog file has been set up, it should only be used during debugging sessions"); self->keylog_file_path = g_strdup(keylog_file_path); return TRUE; #else g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_UNSUPPORTED, "keylog-file() requires OpenSSL >= v1.1.1"); return FALSE; #endif } void tls_context_set_cert_file(TLSContext *self, const gchar *cert_file) { g_free(self->cert_file); self->cert_file = g_strdup(cert_file); } void tls_context_set_pkcs12_file(TLSContext *self, const gchar *pkcs12_file) { g_free(self->pkcs12_file); self->pkcs12_file = g_strdup(pkcs12_file); } void tls_context_set_ca_dir(TLSContext *self, const gchar *ca_dir) { g_free(self->ca_dir); self->ca_dir = g_strdup(ca_dir); } void tls_context_set_crl_dir(TLSContext *self, const gchar *crl_dir) { g_free(self->crl_dir); self->crl_dir = g_strdup(crl_dir); } void tls_context_set_ca_file(TLSContext *self, const gchar *ca_file) { g_free(self->ca_file); self->ca_file = g_strdup(ca_file); } void tls_context_set_cipher_suite(TLSContext *self, const gchar *cipher_suite) { g_free(self->cipher_suite); self->cipher_suite = g_strdup(cipher_suite); } gboolean tls_context_set_tls13_cipher_suite(TLSContext *self, const gchar *tls13_cipher_suite, GError **error) { #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET_CIPHERSUITES g_free(self->tls13_cipher_suite); self->tls13_cipher_suite = g_strdup(tls13_cipher_suite); return TRUE; #else g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_UNSUPPORTED, "Setting TLS 1.3 ciphers is not supported with the OpenSSL version syslog-ng was compiled with"); return FALSE; #endif } gboolean tls_context_set_sigalgs(TLSContext *self, const gchar *sigalgs, GError **error) { #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET1_SIGALGS_LIST g_free(self->sigalgs); self->sigalgs = g_strdup(sigalgs); return TRUE; #else g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_UNSUPPORTED, "Setting sigalgs is not supported with the OpenSSL version syslog-ng was compiled with"); return FALSE; #endif } gboolean tls_context_set_client_sigalgs(TLSContext *self, const gchar *sigalgs, GError **error) { #if SYSLOG_NG_HAVE_DECL_SSL_CTX_SET1_CLIENT_SIGALGS_LIST g_free(self->client_sigalgs); self->client_sigalgs = g_strdup(sigalgs); return TRUE; #else g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_UNSUPPORTED, "Setting client sigalgs is not supported with the OpenSSL version syslog-ng was compiled with"); return FALSE; #endif } gboolean tls_context_set_conf_cmds(TLSContext *self, GList *cmds, GError **error) { g_list_foreach(self->conf_cmds_list, (GFunc) g_free, NULL); self->conf_cmds_list = cmds; return TRUE; } void tls_context_set_ecdh_curve_list(TLSContext *self, const gchar *ecdh_curve_list) { g_free(self->ecdh_curve_list); self->ecdh_curve_list = g_strdup(ecdh_curve_list); } void tls_context_set_dhparam_file(TLSContext *self, const gchar *dhparam_file) { g_free(self->dhparam_file); self->dhparam_file = g_strdup(dhparam_file); } void tls_context_set_sni(TLSContext *self, const gchar *sni) { g_free(self->sni); self->sni = g_strdup(sni); } void tls_context_set_ocsp_stapling_verify(TLSContext *self, gboolean ocsp_stapling_verify) { self->ocsp_stapling_verify = ocsp_stapling_verify; } /* NOTE: location is a string description where this tls context was defined, e.g. the location in the config */ TLSContext * tls_context_new(TLSMode mode, const gchar *location) { TLSContext *self = g_new0(TLSContext, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->mode = mode; self->verify_mode = TVM_REQUIRED | TVM_TRUSTED; self->ssl_options = TSO_NOSSLv2; self->location = g_strdup(location ? : "n/a"); if (self->mode == TM_CLIENT) self->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); else { self->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); SSL_CTX_set_session_id_context(self->ssl_ctx, (const unsigned char *) "syslog", 6); } SSL_CTX_set_app_data(self->ssl_ctx, self); return self; } static void _tls_context_free(TLSContext *self) { g_free(self->location); SSL_CTX_free(self->ssl_ctx); g_list_foreach(self->conf_cmds_list, (GFunc) g_free, NULL); g_list_foreach(self->trusted_fingerprint_list, (GFunc) g_free, NULL); g_list_foreach(self->trusted_dn_list, (GFunc) g_free, NULL); g_free(self->key_file); g_free(self->pkcs12_file); g_free(self->cert_file); g_free(self->dhparam_file); g_free(self->ca_dir); g_free(self->crl_dir); g_free(self->ca_file); g_free(self->cipher_suite); g_free(self->tls13_cipher_suite); g_free(self->sigalgs); g_free(self->client_sigalgs); g_free(self->ecdh_curve_list); g_free(self->sni); g_free(self->keylog_file_path); if(self->keylog_file) fclose(self->keylog_file); g_free(self); } TLSContext * tls_context_ref(TLSContext *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) g_atomic_counter_inc(&self->ref_cnt); return self; } void tls_context_unref(TLSContext *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) _tls_context_free(self); } const gchar * tls_context_get_key_file(TLSContext *self) { return self->key_file; } GQuark tls_context_error_quark(void) { return g_quark_from_static_string("tls-context-error-quark"); } syslog-ng-syslog-ng-4.4.0/lib/transport/tls-context.h000066400000000000000000000114071450431004300226150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TLSCONTEXT_H_INCLUDED #define TLSCONTEXT_H_INCLUDED #include "transport/tls-verifier.h" #include "transport/tls-session.h" #include "messages.h" typedef enum { TM_CLIENT, TM_SERVER, TM_MAX } TLSMode; typedef enum { TVM_NONE, TVM_TRUSTED=0x0001, TVM_UNTRUSTED=0x0002, TVM_OPTIONAL=0x0010, TVM_REQUIRED=0x0020, } TLSVerifyMode; typedef enum { TSO_NONE, TSO_NOSSLv2=0x0001, TSO_NOSSLv3=0x0002, TSO_NOTLSv1=0x0004, TSO_NOTLSv11=0x0008, TSO_NOTLSv12=0x0010, TSO_NOTLSv13=0x0020, TSO_IGNORE_UNEXPECTED_EOF=0x0040, TSO_IGNORE_HOSTNAME_MISMATCH=0x0080, } TLSSslOptions; typedef enum { TLS_CONTEXT_SETUP_OK, TLS_CONTEXT_SETUP_ERROR, TLS_CONTEXT_SETUP_BAD_PASSWORD } TLSContextSetupResult; struct _TLSContext { GAtomicCounter ref_cnt; TLSMode mode; gint verify_mode; gchar *key_file; struct { gchar *keylog_file_path; FILE *keylog_file; GMutex keylog_file_lock; }; gchar *cert_file; gchar *dhparam_file; gchar *pkcs12_file; gchar *ca_dir; gchar *crl_dir; gchar *ca_file; gchar *cipher_suite; gchar *tls13_cipher_suite; gchar *sigalgs; gchar *client_sigalgs; gchar *ecdh_curve_list; gchar *sni; gboolean ocsp_stapling_verify; SSL_CTX *ssl_ctx; GList *conf_cmds_list; GList *trusted_fingerprint_list; GList *trusted_dn_list; gint ssl_options; gchar *location; }; #define TLSCONTEXT_ERROR tls_context_error_quark() GQuark tls_context_error_quark(void); enum TLSContextError { TLSCONTEXT_UNSUPPORTED, TLSCONTEXT_INTERNAL_ERROR, }; #define TMI_ALLOW_COMPRESS 0x1 gboolean tls_context_set_verify_mode_by_name(TLSContext *self, const gchar *mode_str); gboolean tls_context_set_ssl_options_by_name(TLSContext *self, GList *options); gint tls_context_get_verify_mode(const TLSContext *self); void tls_context_set_verify_mode(TLSContext *self, gint verify_mode); gboolean tls_context_ignore_hostname_mismatch(TLSContext *self); void tls_context_set_key_file(TLSContext *self, const gchar *key_file); void tls_context_set_cert_file(TLSContext *self, const gchar *cert_file); gboolean tls_context_set_keylog_file(TLSContext *self, gchar *keylog_file_path, GError **error); void tls_context_set_pkcs12_file(TLSContext *self, const gchar *pkcs12_file); void tls_context_set_ca_dir(TLSContext *self, const gchar *ca_dir); void tls_context_set_crl_dir(TLSContext *self, const gchar *crl_dir); void tls_context_set_ca_file(TLSContext *self, const gchar *ca_file); void tls_context_set_cipher_suite(TLSContext *self, const gchar *cipher_suite); gboolean tls_context_set_tls13_cipher_suite(TLSContext *self, const gchar *tls13_cipher_suite, GError **error); gboolean tls_context_set_sigalgs(TLSContext *self, const gchar *sigalgs, GError **error); gboolean tls_context_set_client_sigalgs(TLSContext *self, const gchar *sigalgs, GError **error); gboolean tls_context_set_conf_cmds(TLSContext *self, GList *cmds, GError **error); void tls_context_set_ecdh_curve_list(TLSContext *self, const gchar *ecdh_curve_list); void tls_context_set_dhparam_file(TLSContext *self, const gchar *dhparam_file); void tls_context_set_sni(TLSContext *self, const gchar *sni); void tls_context_set_ocsp_stapling_verify(TLSContext *self, gboolean ocsp_stapling_verify); const gchar *tls_context_get_key_file(TLSContext *self); EVTTAG *tls_context_format_tls_error_tag(TLSContext *self); EVTTAG *tls_context_format_location_tag(TLSContext *self); gboolean tls_context_verify_peer(TLSContext *self, X509 *peer_cert, const gchar *peer_name); TLSContextSetupResult tls_context_setup_context(TLSContext *self); TLSSession *tls_context_setup_session(TLSContext *self); TLSContext *tls_context_new(TLSMode mode, const gchar *config_location); TLSContext *tls_context_ref(TLSContext *self); void tls_context_unref(TLSContext *self); void tls_x509_format_dn(X509_NAME *name, GString *dn); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/tls-session.c000066400000000000000000000415421450431004300226120ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport/tls-session.h" #include "transport/tls-context.h" #include "str-utils.h" #include #include #include #include #include #include #include /* TLSSession */ void tls_session_configure_allow_compress(TLSSession *tls_session, gboolean allow_compress) { if (allow_compress) { SSL_clear_options(tls_session->ssl, SSL_OP_NO_COMPRESSION); } else { SSL_set_options(tls_session->ssl, SSL_OP_NO_COMPRESSION); } } static gboolean tls_get_x509_digest(X509 *x, GString *hash_string) { gint j; unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; g_assert(hash_string); if (!X509_digest(x, EVP_sha1(), md, &n)) return FALSE; g_string_append(hash_string, "SHA1:"); for (j = 0; j < (int) n; j++) g_string_append_printf(hash_string, "%02X%c", md[j], (j + 1 == (int) n) ?'\0' : ':'); return TRUE; } static X509 * tls_session_find_issuer(TLSSession *self, X509 *cert) { STACK_OF(X509) *intermediate_certs = SSL_get_peer_cert_chain(self->ssl); for (int i = 0; intermediate_certs && i < sk_X509_num(intermediate_certs); ++i) { X509 *issuer = sk_X509_value(intermediate_certs, i); if (X509_check_issued(issuer, cert) == X509_V_OK) { return X509_dup(issuer); } } X509_STORE *store = SSL_CTX_get_cert_store(self->ctx->ssl_ctx); if (!store) return NULL; X509_STORE_CTX *store_ctx = X509_STORE_CTX_new(); if (!store_ctx) return NULL; if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) != 1) { X509_STORE_CTX_free(store_ctx); return NULL; } X509 *issuer = NULL; if (X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert) != 1) { X509_STORE_CTX_free(store_ctx); return NULL; } X509_STORE_CTX_free(store_ctx); return issuer; } int tls_session_verify_fingerprint(X509_STORE_CTX *ctx) { SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); TLSSession *self = SSL_get_app_data(ssl); GList *current_fingerprint = self->ctx->trusted_fingerprint_list; GString *hash; gboolean match = FALSE; X509 *cert = X509_STORE_CTX_get_current_cert(ctx); if (!current_fingerprint) { return TRUE; } if (!cert) return match; hash = g_string_sized_new(EVP_MAX_MD_SIZE * 3); if (tls_get_x509_digest(cert, hash)) { do { if (strcmp((const gchar *)(current_fingerprint->data), hash->str) == 0) { match = TRUE; break; } } while ((current_fingerprint = g_list_next(current_fingerprint)) != NULL); } g_string_free(hash, TRUE); return match; } void tls_x509_format_dn(X509_NAME *name, GString *dn) { BIO *bio; gchar *buf; long len; bio = BIO_new(BIO_s_mem()); X509_NAME_print_ex(bio, name, 0, ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV); len = BIO_get_mem_data(bio, &buf); g_string_assign_len(dn, buf, len); BIO_free(bio); } int tls_session_verify_dn(X509_STORE_CTX *ctx) { SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); TLSSession *self = SSL_get_app_data(ssl); gboolean match = FALSE; GList *current_dn = self->ctx->trusted_dn_list; X509 *cert = X509_STORE_CTX_get_current_cert(ctx); GString *dn; if (!current_dn || !cert) return TRUE; dn = g_string_sized_new(128); tls_x509_format_dn(X509_get_subject_name(cert), dn); do { if (g_pattern_match_simple((const gchar *) current_dn->data, dn->str)) { match = TRUE; break; } } while ((current_dn = g_list_next(current_dn)) != NULL); return match; } int tls_session_verify(TLSSession *self, int ok, X509_STORE_CTX *ctx) { /* untrusted means that we have to accept the certificate even if it is untrusted */ if (self->ctx->verify_mode & TVM_UNTRUSTED) return 1; int ctx_error_depth = X509_STORE_CTX_get_error_depth(ctx); /* accept certificate if its fingerprint matches, again regardless whether x509 certificate validation was successful */ if (ok && ctx_error_depth == 0 && !tls_session_verify_fingerprint(ctx)) { msg_notice("Certificate valid, but fingerprint constraints were not met, rejecting", tls_context_format_location_tag(self->ctx)); return 0; } X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx); if (ok && ctx_error_depth != 0 && (X509_get_extension_flags(current_cert) & EXFLAG_CA) == 0) { msg_notice("Invalid certificate found in chain, basicConstraints.ca is unset in non-leaf certificate", tls_context_format_location_tag(self->ctx)); X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_CA); return 0; } /* reject certificate if it is valid, but its DN is not trusted */ if (ok && ctx_error_depth == 0 && !tls_session_verify_dn(ctx)) { msg_notice("Certificate valid, but DN constraints were not met, rejecting", tls_context_format_location_tag(self->ctx)); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_UNTRUSTED); return 0; } /* if the crl_dir is set in the configuration file but the directory is empty ignore this error */ if (!ok && X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL) { msg_notice("CRL directory is set but no CRLs found", tls_context_format_location_tag(self->ctx)); return 1; } if (!ok && X509_STORE_CTX_get_error(ctx) == X509_V_ERR_INVALID_PURPOSE) { msg_warning("Certificate valid, but purpose is invalid", tls_context_format_location_tag(self->ctx)); return 1; } return ok; } static void _log_certificate_validation_progress(int ok, X509_STORE_CTX *ctx) { X509 *xs; GString *subject_name, *issuer_name; xs = X509_STORE_CTX_get_current_cert(ctx); subject_name = g_string_sized_new(128); issuer_name = g_string_sized_new(128); tls_x509_format_dn(X509_get_subject_name(xs), subject_name); tls_x509_format_dn(X509_get_issuer_name(xs), issuer_name); if (ok) { msg_debug("Certificate validation progress", evt_tag_str("subject", subject_name->str), evt_tag_str("issuer", issuer_name->str)); } else { gint errnum, errdepth; errnum = X509_STORE_CTX_get_error(ctx); errdepth = X509_STORE_CTX_get_error_depth(ctx); msg_error("Certificate validation failed", evt_tag_str("subject", subject_name->str), evt_tag_str("issuer", issuer_name->str), evt_tag_str("error", X509_verify_cert_error_string(errnum)), evt_tag_int("depth", errdepth)); } g_string_free(subject_name, TRUE); g_string_free(issuer_name, TRUE); } int tls_session_verify_callback(int ok, X509_STORE_CTX *ctx) { SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); TLSSession *self = SSL_get_app_data(ssl); /* NOTE: Sometimes libssl calls this function with no current_cert. This happens when some global error is happen. At this situation we do not need to call any other check and callback */ if (X509_STORE_CTX_get_current_cert(ctx) == NULL) { int ctx_error = X509_STORE_CTX_get_error(ctx); switch (ctx_error) { case X509_V_ERR_NO_EXPLICIT_POLICY: /* NOTE: Because we set the CHECK_POLICY_FLAG if the certificate contains ExplicitPolicy constraint we would get this error. But this error is because we do not set the policy what we want to check for. */ ok = 1; break; default: msg_notice("Error occurred during certificate validation", evt_tag_int("error", X509_STORE_CTX_get_error(ctx)), tls_context_format_location_tag(self->ctx)); break; } } else { ok = tls_session_verify(self, ok, ctx); _log_certificate_validation_progress(ok, ctx); if (self->verifier && self->verifier->verify_func) return self->verifier->verify_func(ok, ctx, self->verifier->verify_data); } return ok; } static inline gboolean _ocsp_client_retrieve_response(SSL *ssl, OCSP_RESPONSE **response, OCSP_BASICRESP **basic_response, GError **error) { const unsigned char *ocsp_response_der; long ocsp_response_der_length = SSL_get_tlsext_status_ocsp_resp(ssl, &ocsp_response_der); if (!ocsp_response_der || ocsp_response_der_length <= 0) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "no OCSP response was received from the server"); return FALSE; } OCSP_RESPONSE *ocsp_response = d2i_OCSP_RESPONSE(NULL, &ocsp_response_der, ocsp_response_der_length); if (!ocsp_response) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "OCSP response received from server can not be parsed"); return FALSE; } if (OCSP_response_status(ocsp_response) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "OCSP response is unsuccessful"); OCSP_RESPONSE_free(ocsp_response); return FALSE; } OCSP_BASICRESP *ocsp_basic_resp = OCSP_response_get1_basic(ocsp_response); if (!ocsp_basic_resp) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "can not extract OCSP basic response"); OCSP_RESPONSE_free(ocsp_response); return FALSE; } *response = ocsp_response; *basic_response = ocsp_basic_resp; return TRUE; } static inline OCSP_CERTID * _get_ocsp_certid(TLSSession *self, X509 *cert, GError **error) { X509 *issuer = tls_session_find_issuer(self, cert); if (!issuer) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "failed to find certificate issuer"); return FALSE; } OCSP_CERTID *cert_id = OCSP_cert_to_id(NULL, cert, issuer); if (!cert_id) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "failed to retrieve certificate ID"); X509_free(issuer); return FALSE; } X509_free(issuer); return cert_id; } static gboolean tls_session_ocsp_client_check_cert_validity(TLSSession *self, OCSP_BASICRESP *ocsp_basic_resp, X509 *cert, GError **error) { OCSP_CERTID *cert_id = _get_ocsp_certid(self, cert, error); if (!cert_id) return FALSE; int status, reason; ASN1_GENERALIZEDTIME *rev_time = NULL; ASN1_GENERALIZEDTIME *this_upd = NULL; ASN1_GENERALIZEDTIME *next_upd = NULL; if (OCSP_resp_find_status(ocsp_basic_resp, cert_id, &status, &reason, &rev_time, &this_upd, &next_upd) != 1) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "failed to retrieve OCSP response status"); OCSP_CERTID_free(cert_id); return FALSE; } OCSP_CERTID_free(cert_id); switch (status) { case V_OCSP_CERTSTATUS_GOOD: break; case V_OCSP_CERTSTATUS_REVOKED: g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "certificate is revoked (reason: %s (%d))", OCSP_crl_reason_str(reason), reason); return FALSE; default: g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "certificate status is unknown"); return FALSE; } if (OCSP_check_validity(this_upd, next_upd, 300L, -1L) != 1) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "OCSP response is outside its time validity period"); return FALSE; } return TRUE; } static gboolean tls_session_ocsp_client_verify(TLSSession *self, OCSP_BASICRESP *ocsp_basic_resp, GError **error) { SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(self->ssl); X509_STORE *trusted_cert_store = SSL_CTX_get_cert_store(ssl_ctx); STACK_OF(X509) *untrusted_intermediate_certs = SSL_get_peer_cert_chain(self->ssl); if (OCSP_basic_verify(ocsp_basic_resp, untrusted_intermediate_certs, trusted_cert_store, 0) != 1) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "failed to verify OCSP response signature"); return FALSE; } X509 *cert = SSL_get_peer_certificate(self->ssl); if (!cert) { g_set_error(error, TLSCONTEXT_ERROR, TLSCONTEXT_INTERNAL_ERROR, "no certificate was presented by server"); return FALSE; } if (!tls_session_ocsp_client_check_cert_validity(self, ocsp_basic_resp, cert, error)) { X509_free(cert); return FALSE; } X509_free(cert); /* TODO: The server MAY send multiple OCSP responses, one for each cert in the chain, * those have to be validated by tls_session_ocsp_client_check_cert_validity(), _if_ they exist. */ return TRUE; } int tls_session_ocsp_client_verify_callback(SSL *ssl, void *user_data) { TLSSession *self = SSL_get_app_data(ssl); OCSP_RESPONSE *ocsp_response = NULL; OCSP_BASICRESP *ocsp_basic_resp = NULL; GError *error = NULL; if (!_ocsp_client_retrieve_response(ssl, &ocsp_response, &ocsp_basic_resp, &error)) goto err; if (!tls_session_ocsp_client_verify(self, ocsp_basic_resp, &error)) goto err; OCSP_BASICRESP_free(ocsp_basic_resp); OCSP_RESPONSE_free(ocsp_response); msg_debug("OCSP stapling verification succeeded", tls_context_format_location_tag(self->ctx)); return 1; err: msg_error("OCSP stapling verification failed", evt_tag_str("error", error->message), tls_context_format_location_tag(self->ctx)); g_clear_error(&error); OCSP_BASICRESP_free(ocsp_basic_resp); OCSP_RESPONSE_free(ocsp_response); return 0; } void tls_session_set_trusted_fingerprints(TLSContext *self, GList *fingerprints) { g_assert(fingerprints); g_list_foreach(self->trusted_fingerprint_list, (GFunc) g_free, NULL); self->trusted_fingerprint_list = fingerprints; } void tls_session_set_trusted_dn(TLSContext *self, GList *dn) { g_assert(dn); g_list_foreach(self->trusted_dn_list, (GFunc) g_free, NULL); self->trusted_dn_list = dn; } void tls_session_set_verifier(TLSSession *self, TLSVerifier *verifier) { self->verifier = verifier ? tls_verifier_ref(verifier) : NULL; } void tls_session_info_callback(const SSL *ssl, int where, int ret) { TLSSession *self = (TLSSession *)SSL_get_app_data(ssl); if( !self->peer_info.found && where == (SSL_ST_ACCEPT|SSL_CB_LOOP) ) { X509 *cert = SSL_get_peer_certificate(ssl); if(cert) { self->peer_info.found = 1; /* mark this found so we don't keep checking on every callback */ X509_NAME *name = X509_get_subject_name(cert); X509_NAME_get_text_by_NID( name, NID_commonName, self->peer_info.cn, X509_MAX_CN_LEN ); X509_NAME_get_text_by_NID( name, NID_organizationName, self->peer_info.o, X509_MAX_O_LEN ); X509_NAME_get_text_by_NID( name, NID_organizationalUnitName, self->peer_info.ou, X509_MAX_OU_LEN ); X509_free(cert); } } } static gboolean _set_sni_in_client_mode(TLSSession *self) { if (!self->ctx->sni) return TRUE; if (self->ctx->mode != TM_CLIENT) return TRUE; if (SSL_set_tlsext_host_name(self->ssl, self->ctx->sni)) return TRUE; msg_error("Failed to set SNI", evt_tag_str("sni", self->ctx->sni), tls_context_format_location_tag(self->ctx)); return FALSE; } TLSSession * tls_session_new(SSL *ssl, TLSContext *ctx) { TLSSession *self = g_new0(TLSSession, 1); self->ssl = ssl; self->ctx = tls_context_ref(ctx); /* to set verify callback */ tls_session_set_verifier(self, NULL); SSL_set_info_callback(ssl, tls_session_info_callback); if (!_set_sni_in_client_mode(self)) { tls_context_unref(self->ctx); g_free(self); return NULL; } return self; } void tls_session_free(TLSSession *self) { tls_context_unref(self->ctx); if (self->verifier) tls_verifier_unref(self->verifier); SSL_free(self->ssl); g_free(self); } syslog-ng-syslog-ng-4.4.0/lib/transport/tls-session.h000066400000000000000000000037401450431004300226150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TRANSPORT_TLS_SESSION_H_INCLUDED #define TRANSPORT_TLS_SESSION_H_INCLUDED #include "tls-verifier.h" #define X509_MAX_CN_LEN 64 #define X509_MAX_O_LEN 64 #define X509_MAX_OU_LEN 32 typedef struct _TLSContext TLSContext; typedef struct _TLSSession { SSL *ssl; TLSContext *ctx; TLSVerifier *verifier; struct { int found; gchar o[X509_MAX_O_LEN]; gchar ou[X509_MAX_OU_LEN]; gchar cn[X509_MAX_CN_LEN]; } peer_info; } TLSSession; void tls_session_configure_allow_compress(TLSSession *tls_session, gboolean allow_compress); void tls_session_set_trusted_fingerprints(TLSContext *self, GList *fingerprints); void tls_session_set_trusted_dn(TLSContext *self, GList *dns); void tls_session_set_verifier(TLSSession *self, TLSVerifier *verifier); int tls_session_verify_callback(int ok, X509_STORE_CTX *ctx); int tls_session_ocsp_client_verify_callback(SSL *ssl, void *user_data); TLSSession *tls_session_new(SSL *ssl, TLSContext *ctx); void tls_session_free(TLSSession *self); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/tls-verifier.c000066400000000000000000000136531450431004300227440ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "tls-verifier.h" #include "messages.h" #include "compat/openssl_support.h" #include /* TLSVerifier */ TLSVerifier * tls_verifier_new(TLSSessionVerifyFunc verify_func, gpointer verify_data, GDestroyNotify verify_data_destroy) { TLSVerifier *self = g_new0(TLSVerifier, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->verify_func = verify_func; self->verify_data = verify_data; self->verify_data_destroy = verify_data_destroy; return self; } TLSVerifier * tls_verifier_ref(TLSVerifier *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) g_atomic_counter_inc(&self->ref_cnt); return self; } static void _tls_verifier_free(TLSVerifier *self) { g_assert(self); if (self) { if (self->verify_data && self->verify_data_destroy) self->verify_data_destroy(self->verify_data); g_free(self); } } void tls_verifier_unref(TLSVerifier *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) _tls_verifier_free(self); } /* helper functions */ static gboolean tls_wildcard_match(const gchar *host_name, const gchar *pattern) { gchar **pattern_parts, **hostname_parts; gboolean success = FALSE; gchar *lower_pattern = NULL; gchar *lower_hostname = NULL; gint i; pattern_parts = g_strsplit(pattern, ".", 0); hostname_parts = g_strsplit(host_name, ".", 0); for (i = 0; pattern_parts[i]; i++) { if (!hostname_parts[i]) { /* number of dot separated entries is not the same in the hostname and the pattern spec */ goto exit; } lower_pattern = g_ascii_strdown(pattern_parts[i], -1); lower_hostname = g_ascii_strdown(hostname_parts[i], -1); if (!g_pattern_match_simple(lower_pattern, lower_hostname)) goto exit; } success = TRUE; exit: g_free(lower_pattern); g_free(lower_hostname); g_strfreev(pattern_parts); g_strfreev(hostname_parts); return success; } gboolean tls_verify_certificate_name(X509 *cert, const gchar *host_name) { gchar pattern_buf[256]; gint ext_ndx; gboolean found = FALSE, result = FALSE; ext_ndx = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); if (ext_ndx >= 0) { /* ok, there's a subjectAltName extension, check that */ X509_EXTENSION *ext; STACK_OF(GENERAL_NAME) *alt_names; GENERAL_NAME *gen_name; ext = X509_get_ext(cert, ext_ndx); alt_names = X509V3_EXT_d2i(ext); if (alt_names) { gint num, i; num = sk_GENERAL_NAME_num(alt_names); for (i = 0; !result && i < num; i++) { gen_name = sk_GENERAL_NAME_value(alt_names, i); if (gen_name->type == GEN_DNS) { const guchar *dnsname = ASN1_STRING_get0_data(gen_name->d.dNSName); guint dnsname_len = ASN1_STRING_length(gen_name->d.dNSName); if (dnsname_len > sizeof(pattern_buf) - 1) { found = TRUE; result = FALSE; break; } memcpy(pattern_buf, dnsname, dnsname_len); pattern_buf[dnsname_len] = 0; /* we have found a DNS name as alternative subject name */ found = TRUE; result = tls_wildcard_match(host_name, pattern_buf); } else if (gen_name->type == GEN_IPADD) { gchar dotted_ip[64] = {0}; int addr_family = AF_INET; if (gen_name->d.iPAddress->length == 16) addr_family = AF_INET6; if (inet_ntop(addr_family, gen_name->d.iPAddress->data, dotted_ip, sizeof(dotted_ip))) { g_strlcpy(pattern_buf, dotted_ip, sizeof(pattern_buf)); found = TRUE; result = strcasecmp(host_name, pattern_buf) == 0; } } } sk_GENERAL_NAME_free(alt_names); } } if (!found) { /* hmm. there was no subjectAltName (this is deprecated, but still * widely used), look up the Subject, most specific CN */ X509_NAME *name; name = X509_get_subject_name(cert); if (X509_NAME_get_text_by_NID(name, NID_commonName, pattern_buf, sizeof(pattern_buf)) != -1) { result = tls_wildcard_match(host_name, pattern_buf); } } if (!result) { msg_error("Certificate subject does not match configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf)); } else { msg_verbose("Certificate subject matches configured hostname", evt_tag_str("hostname", host_name), evt_tag_str("certificate", pattern_buf)); } return result; } syslog-ng-syslog-ng-4.4.0/lib/transport/tls-verifier.h000066400000000000000000000033201450431004300227370ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TRANSPORT_TLS_VERIFIER_H_INCLUDED #define TRANSPORT_TLS_VERIFIER_H_INCLUDED #include "syslog-ng.h" #include "atomic.h" #include typedef gint (*TLSSessionVerifyFunc)(gint ok, X509_STORE_CTX *ctx, gpointer user_data); typedef struct _TLSVerifier { GAtomicCounter ref_cnt; TLSSessionVerifyFunc verify_func; gpointer verify_data; GDestroyNotify verify_data_destroy; } TLSVerifier; TLSVerifier *tls_verifier_new(TLSSessionVerifyFunc verify_func, gpointer verify_data, GDestroyNotify verify_data_destroy); TLSVerifier *tls_verifier_ref(TLSVerifier *self); void tls_verifier_unref(TLSVerifier *self); gboolean tls_verify_certificate_name(X509 *cert, const gchar *hostname); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-aux-data.c000066400000000000000000000047441450431004300240700ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport-aux-data.h" #include "messages.h" #include void log_transport_aux_data_add_nv_pair(LogTransportAuxData *self, const gchar *name, const gchar *value) { if (!self) return; gsize name_len = strlen(name); gsize value_len = strlen(value); if (self->end_ptr + name_len + 1 + value_len + 1 + 1 < sizeof(self->data)) { /* copy NUL too */ memcpy(&self->data[self->end_ptr], name, name_len + 1); self->end_ptr += name_len + 1; memcpy(&self->data[self->end_ptr], value, value_len + 1); self->end_ptr += value_len + 1; /* append final NULL that indicates the end of name-value pairs */ self->data[self->end_ptr] = 0; } else { static gboolean warned = FALSE; if (!warned) { msg_notice("Transport aux data overflow, some fields may not be associated with the message, please increase aux buffer size", evt_tag_int("aux_size", sizeof(self->data))); warned = TRUE; } } } void log_transport_aux_data_foreach(LogTransportAuxData *self, void (*func)(const gchar *, const gchar *, gsize, gpointer), gpointer user_data) { const gchar *p; if (!self) return; p = self->data; while (*p) { const gchar *name = p; gsize name_len = strlen(p); const gchar *value = name + name_len + 1; gsize value_len = strlen(value); func(name, value, value_len, user_data); p = value + value_len + 1; } } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-aux-data.h000066400000000000000000000062421450431004300240700ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TRANSPORT_TRANSPORT_AUX_DATA_H_INCLUDED #define TRANSPORT_TRANSPORT_AUX_DATA_H_INCLUDED #include "gsockaddr.h" #include typedef struct _LogTransportAuxData { GSockAddr *peer_addr; GSockAddr *local_addr; struct timespec timestamp; gint proto; gchar data[1536]; gsize end_ptr; } LogTransportAuxData; static inline void log_transport_aux_data_init(LogTransportAuxData *self) { if (self) { self->peer_addr = NULL; self->local_addr = NULL; self->end_ptr = 0; self->data[0] = 0; self->timestamp.tv_sec = 0; self->timestamp.tv_nsec = 0; } } static inline void log_transport_aux_data_destroy(LogTransportAuxData *self) { if (self) { g_sockaddr_unref(self->peer_addr); g_sockaddr_unref(self->local_addr); } } static inline void log_transport_aux_data_reinit(LogTransportAuxData *self) { log_transport_aux_data_destroy(self); log_transport_aux_data_init(self); } static inline void log_transport_aux_data_copy(LogTransportAuxData *dst, LogTransportAuxData *src) { gsize data_to_copy = sizeof(*src) - sizeof(src->data) + src->end_ptr; if (dst) { memcpy(dst, src, data_to_copy); g_sockaddr_ref(dst->peer_addr); g_sockaddr_ref(dst->local_addr); } } static inline void log_transport_aux_data_set_peer_addr_ref(LogTransportAuxData *self, GSockAddr *peer_addr) { if (self) { if (self->peer_addr) g_sockaddr_unref(self->peer_addr); self->peer_addr = peer_addr; } } static inline void log_transport_aux_data_set_local_addr_ref(LogTransportAuxData *self, GSockAddr *local_addr) { if (self) { if (self->local_addr) g_sockaddr_unref(self->local_addr); self->local_addr = local_addr; } } static inline void log_transport_aux_data_set_timestamp(LogTransportAuxData *self, const struct timespec *timestamp) { if (self) self->timestamp = *timestamp; } void log_transport_aux_data_add_nv_pair(LogTransportAuxData *self, const gchar *name, const gchar *value); void log_transport_aux_data_foreach(LogTransportAuxData *self, void (*func)(const gchar *, const gchar *, gsize, gpointer), gpointer user_data); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-id.c000066400000000000000000000071531450431004300244220ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport/transport-factory-id.h" #include "mainloop.h" struct _TransportFactoryId { gchar *transport_name; gint uniq_id; }; typedef struct _Sequence Sequence; struct _Sequence { gint ctr; } sequence; static void sequence_inc(Sequence *seq) { seq->ctr++; } static gint sequence_get(Sequence *seq) { return seq->ctr; } static void sequence_reset(Sequence *seq, gint init_value) { seq->ctr = init_value; } static GList *transport_factory_ids; GMutex transport_factory_ids_mutex; void transport_factory_id_global_init(void) { sequence_reset(&sequence, 1); g_mutex_init(&transport_factory_ids_mutex); } static inline void _free(gpointer s) { transport_factory_id_free((TransportFactoryId *)s); } void transport_factory_id_global_deinit(void) { g_list_free_full(transport_factory_ids, _free); transport_factory_ids = NULL; g_mutex_clear(&transport_factory_ids_mutex); } void _transport_factory_id_register(TransportFactoryId *id) { transport_factory_ids = g_list_append(transport_factory_ids, id); } static gpointer _clone(gconstpointer s) { TransportFactoryId *id = (TransportFactoryId *)s; TransportFactoryId *cloned = g_new0(TransportFactoryId, 1); cloned->transport_name = g_strdup(id->transport_name); cloned->uniq_id = id->uniq_id; return cloned; } TransportFactoryId * _transport_factory_id_clone(const TransportFactoryId *id) { return (TransportFactoryId *)_clone((gconstpointer) id); } static gpointer _copy_func(gconstpointer src, gpointer data) { return _clone(src); } GList * _transport_factory_id_clone_registered_ids(void) { return g_list_copy_deep(transport_factory_ids, _copy_func, NULL); } void transport_factory_id_free(TransportFactoryId *id) { g_free(id->transport_name); g_free(id); } guint transport_factory_id_hash(gconstpointer key) { TransportFactoryId *id = (TransportFactoryId *)key; return g_direct_hash(GINT_TO_POINTER(id->uniq_id)); } gboolean transport_factory_id_equal(const TransportFactoryId *id1, const TransportFactoryId *id2) { return (id1->uniq_id == id2->uniq_id) ? TRUE : FALSE; } const gchar * transport_factory_id_get_transport_name(const TransportFactoryId *id) { return id->transport_name; } void _transport_factory_id_lock(void) { g_mutex_lock(&transport_factory_ids_mutex); } void _transport_factory_id_unlock(void) { g_mutex_unlock(&transport_factory_ids_mutex); } TransportFactoryId * _transport_factory_id_new(const gchar *transport_name) { TransportFactoryId *id = g_new0(TransportFactoryId, 1); sequence_inc(&sequence); id->transport_name = g_strdup(transport_name); id->uniq_id = sequence_get(&sequence); return id; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-id.h000066400000000000000000000045001450431004300244200ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_FACTORY_ID_INCLUDED #define TRANSPORT_FACTORY_ID_INCLUDED #include "syslog-ng.h" typedef struct _TransportFactoryId TransportFactoryId; /* * public API * */ void transport_factory_id_global_init(void); void transport_factory_id_global_deinit(void); const gchar *transport_factory_id_get_transport_name(const TransportFactoryId *); void transport_factory_id_free(TransportFactoryId *); guint transport_factory_id_hash(gconstpointer); gboolean transport_factory_id_equal(const TransportFactoryId *, const TransportFactoryId *); /** * private API (for internal usage and test) */ TransportFactoryId *_transport_factory_id_new(const gchar *transport_name); void _transport_factory_id_register(TransportFactoryId *); GList *_transport_factory_id_clone_registered_ids(void); TransportFactoryId *_transport_factory_id_clone(const TransportFactoryId *); void _transport_factory_id_lock(void); void _transport_factory_id_unlock(void); #define DEFINE_TRANSPORT_FACTORY_ID_FUN(transport_name, func_name) \ const TransportFactoryId* func_name(void) \ {\ static TransportFactoryId *id;\ _transport_factory_id_lock(); \ if (!id)\ {\ id = _transport_factory_id_new(transport_name);\ _transport_factory_id_register(id);\ }\ _transport_factory_id_unlock(); \ return id;\ } #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-registry.c000066400000000000000000000052071450431004300256740ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport/transport-factory-registry.h" struct _TransportFactoryRegistry { /* * hash_table * */ GHashTable *registry; }; static void _transport_factory_destroy_notify(gpointer s) { TransportFactory *self = (TransportFactory *)s; transport_factory_free(self); } TransportFactoryRegistry *transport_factory_registry_new(void) { TransportFactoryRegistry *instance = g_new0(TransportFactoryRegistry, 1); instance->registry = g_hash_table_new_full((GHashFunc)transport_factory_id_hash, (GEqualFunc)transport_factory_id_equal, NULL, _transport_factory_destroy_notify); return instance; } void transport_factory_registry_free(TransportFactoryRegistry *self) { g_hash_table_unref(self->registry); g_free(self); } void transport_factory_registry_add(TransportFactoryRegistry *self, TransportFactory *factory) { const TransportFactoryId *id = transport_factory_get_id(factory); const TransportFactory *old = transport_factory_registry_lookup(self, id); if (old) { g_assert(old == factory); } g_hash_table_insert(self->registry, (TransportFactoryId *)id, factory); } TransportFactory * transport_factory_registry_lookup(TransportFactoryRegistry *self, const TransportFactoryId *id) { return g_hash_table_lookup(self->registry, id); } TransportFactory * transport_factory_registry_remove(TransportFactoryRegistry *self, const TransportFactoryId *id) { TransportFactory *factory = g_hash_table_lookup(self->registry, id); g_hash_table_steal(self->registry, id); return factory; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-registry.h000066400000000000000000000033421450431004300256770ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_FACTORY_REGISTRY_H_INCLUDED #define TRANSPORT_FACTORY_REGISTRY_H_INCLUDED #include "syslog-ng.h" #include "transport/transport-factory.h" #include "transport/transport-factory-id.h" typedef struct _TransportFactoryRegistry TransportFactoryRegistry; TransportFactoryRegistry *transport_factory_registry_new(void); void transport_factory_registry_free(TransportFactoryRegistry *self); void transport_factory_registry_add(TransportFactoryRegistry *self, TransportFactory *factory); TransportFactory *transport_factory_registry_lookup(TransportFactoryRegistry *self, const TransportFactoryId *id); TransportFactory *transport_factory_registry_remove(TransportFactoryRegistry *self, const TransportFactoryId *id); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-socket.c000066400000000000000000000035311450431004300253120ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport/transport-factory-socket.h" #include "transport/transport-socket.h" #include "transport/transport-udp-socket.h" DEFINE_TRANSPORT_FACTORY_ID_FUN("socket", transport_factory_socket_id); static LogTransport * _construct_transport_dgram(const TransportFactory *s, gint fd) { return log_transport_udp_socket_new(fd); } static LogTransport * _construct_transport_stream(const TransportFactory *s, gint fd) { return log_transport_stream_socket_new(fd); } TransportFactory * transport_factory_socket_new(int sock_type) { TransportFactorySocket *self = g_new0(TransportFactorySocket, 1); if (sock_type == SOCK_DGRAM) self->super.construct_transport = _construct_transport_dgram; else self->super.construct_transport = _construct_transport_stream; self->super.id = transport_factory_socket_id(); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-socket.h000066400000000000000000000026561450431004300253260ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_FACTORY_SOCKET_H_INCLUDED #define TRANSPORT_FACTORY_SOCKET_H_INCLUDED #include "transport/transport-factory.h" #include "transport/transport-socket.h" typedef struct _TransportFactorySocket TransportFactorySocket; struct _TransportFactorySocket { TransportFactory super; }; TransportFactory *transport_factory_socket_new(gint sock_type); const TransportFactoryId *transport_factory_socket_id(void); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-tls.c000066400000000000000000000054451450431004300246320ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport/tls-context.h" #include "transport/transport-factory-tls.h" #include "transport/transport-tls.h" DEFINE_TRANSPORT_FACTORY_ID_FUN("tls", transport_factory_tls_id); static LogTransport * _construct_transport(const TransportFactory *s, gint fd) { TransportFactoryTLS *self = (TransportFactoryTLS *)s; TLSSession *tls_session = tls_context_setup_session(self->tls_context); if (!tls_session) return NULL; tls_session_configure_allow_compress(tls_session, self->allow_compress); tls_session_set_verifier(tls_session, self->tls_verifier); return log_transport_tls_new(tls_session, fd); } void transport_factory_tls_enable_compression(TransportFactory *s) { TransportFactoryTLS *self = (TransportFactoryTLS *)s; self->allow_compress = TRUE; } void transport_factory_tls_disable_compression(TransportFactory *s) { TransportFactoryTLS *self = (TransportFactoryTLS *)s; self->allow_compress = FALSE; } static void _free(TransportFactory *s) { TransportFactoryTLS *self = (TransportFactoryTLS *)s; tls_context_unref(self->tls_context); if (self->tls_verifier) tls_verifier_unref(self->tls_verifier); } TransportFactory * transport_factory_tls_new(TLSContext *ctx, TLSVerifier *tls_verifier, guint32 flags) { TransportFactoryTLS *instance = g_new0(TransportFactoryTLS, 1); instance->tls_context = tls_context_ref(ctx); instance->tls_verifier = tls_verifier ? tls_verifier_ref(tls_verifier) : NULL; instance->super.id = transport_factory_tls_id(); instance->super.construct_transport = _construct_transport; instance->super.free_fn = _free; if (flags & TMI_ALLOW_COMPRESS) transport_factory_tls_enable_compression((TransportFactory *)instance); else transport_factory_tls_disable_compression((TransportFactory *)instance); return &instance->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory-tls.h000066400000000000000000000032321450431004300246270ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_FACTORY_TLS_H_INCLUDED #define TRANSPORT_FACTORY_TLS_H_INCLUDED #include "transport/transport-factory.h" #include "transport/tls-context.h" typedef struct _TransportFactoryTLS TransportFactoryTLS; struct _TransportFactoryTLS { TransportFactory super; TLSContext *tls_context; TLSVerifier *tls_verifier; gboolean allow_compress; }; TransportFactory *transport_factory_tls_new(TLSContext *ctx, TLSVerifier *tls_verifier, guint32 flags); void transport_factory_tls_enable_compression(TransportFactory *); void transport_factory_tls_disable_compression(TransportFactory *); const TransportFactoryId *transport_factory_tls_id(void); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-factory.h000066400000000000000000000044751450431004300240410ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_FACTORY_H_INCLUDED #define TRANSPORT_FACTORY_H_INCLUDED #include "transport/logtransport.h" #include "transport/transport-factory-id.h" /* TransportFactory is an interface for representing * concrete TransportFactory instances * Each TransportFactory has * - a reference to a unique id * - a construct method for creating new LogTransport instances * - a destroy method for releasing resources that are needed for construct() */ typedef struct _TransportFactory TransportFactory; struct _TransportFactory { const TransportFactoryId *id; LogTransport *(*construct_transport)(const TransportFactory *self, gint fd); void (*free_fn)(TransportFactory *self); }; static inline LogTransport *transport_factory_construct_transport(const TransportFactory *self, gint fd) { g_assert(self->construct_transport); LogTransport *transport = self->construct_transport(self, fd); transport->name = transport_factory_id_get_transport_name(self->id); return transport; } static inline void transport_factory_free(TransportFactory *self) { if (self->free_fn) self->free_fn(self); g_free(self); } static inline const TransportFactoryId *transport_factory_get_id(const TransportFactory *self) { /* each concrete TransportFactory has to have an id */ g_assert(self->id); return self->id; } #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-file.c000066400000000000000000000050171450431004300232750ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport-file.h" #include #include #include gssize log_transport_file_read_method(LogTransport *self, gpointer buf, gsize buflen, LogTransportAuxData *aux) { gint rc; do { rc = read(self->fd, buf, buflen); } while (rc == -1 && errno == EINTR); return rc; } gssize log_transport_file_read_and_ignore_eof_method(LogTransport *self, gpointer buf, gsize buflen, LogTransportAuxData *aux) { gint rc; rc = log_transport_file_read_method(self, buf, buflen, aux); if (rc == 0) { rc = -1; errno = EAGAIN; } return rc; } gssize log_transport_file_write_method(LogTransport *self, const gpointer buf, gsize buflen) { gint rc; do { rc = write(self->fd, buf, buflen); } while (rc == -1 && errno == EINTR); return rc; } gssize log_transport_file_writev_method(LogTransport *self, struct iovec *iov, gint iov_count) { gint rc; do { rc = writev(self->fd, iov, iov_count); } while (rc == -1 && errno == EINTR); return rc; } void log_transport_file_init_instance(LogTransportFile *self, gint fd) { log_transport_init_instance(&self->super, fd); self->super.read = log_transport_file_read_method; self->super.write = log_transport_file_write_method; self->super.writev = log_transport_file_writev_method; self->super.free_fn = log_transport_free_method; } LogTransport * log_transport_file_new(gint fd) { LogTransportFile *self = g_new0(LogTransportFile, 1); log_transport_file_init_instance(self, fd); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-file.h000066400000000000000000000034211450431004300232770ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_TRANSPORT_FILE_H_INCLUDED #define TRANSPORT_TRANSPORT_FILE_H_INCLUDED 1 #include "transport/logtransport.h" /* log transport that simply sends messages to an fd */ typedef struct _LogTransportFile LogTransportFile; struct _LogTransportFile { LogTransport super; }; gssize log_transport_file_read_method(LogTransport *self, gpointer buf, gsize buflen, LogTransportAuxData *aux); gssize log_transport_file_read_and_ignore_eof_method(LogTransport *self, gpointer buf, gsize buflen, LogTransportAuxData *aux); gssize log_transport_file_write_method(LogTransport *self, const gpointer buf, gsize buflen); void log_transport_file_init_instance(LogTransportFile *self, gint fd); LogTransport *log_transport_file_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-pipe.c000066400000000000000000000050741450431004300233160ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport/transport-pipe.h" #include "transport/transport-file.h" #include #include gssize log_transport_pipe_write_method(LogTransport *s, const gpointer buf, gsize buflen) { LogTransportFile *self = (LogTransportFile *) s; gint rc; do { /* NOTE: this loop is needed because of the funny semantics that * pipe() uses. A pipe has a buffer (sized PIPE_BUF), which * determines how much data it can buffer. If the data to be * written would overflow the buffer, it may reject it with * rc == -1 and errno set to EAGAIN. * * The issue is worse as AIX may indicate in poll() that the * pipe is writable, and then the pipe may flat out reject our * write() operation, resulting in a busy loop. * * The work around is to try to write the data in * ever-decreasing size, and only accept EAGAIN if a single byte * write is refused as well. * * Most UNIX platforms behaves better than that, but the AIX * implementation is still conforming, for now we only enable it * on AIX. */ do { rc = write(self->super.fd, buf, buflen); } #ifdef __aix__ while ((buflen >>= 1) && rc < 0 && errno == EAGAIN); #else while (0); #endif } while (rc == -1 && errno == EINTR); return rc; } LogTransport * log_transport_pipe_new(gint fd) { LogTransportFile *self = g_new0(LogTransportFile, 1); log_transport_file_init_instance(self, fd); self->super.write = log_transport_pipe_write_method; return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-pipe.h000066400000000000000000000023651450431004300233230ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_TRANSPORT_PIPE_H_INCLUDED #define TRANSPORT_TRANSPORT_PIPE_H_INCLUDED 1 #include "logtransport.h" gssize log_transport_pipe_write_method(LogTransport *s, const gpointer buf, gsize buflen); LogTransport *log_transport_pipe_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-socket.c000066400000000000000000000166131450431004300236520ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport-socket.h" #include #include #include static gint _determine_address_family(gint fd) { struct sockaddr_storage sas; socklen_t len = sizeof(sas); if (getsockname(fd, (struct sockaddr *) &sas, &len) < 0) return 0; return sas.ss_family; } static gint _determine_proto_value_based_on_so_protocol(gint fd) { #if defined(SO_PROTOCOL) gint ipproto; socklen_t ipproto_len = sizeof(ipproto); /* supported by Linux and FreeBSD */ if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &ipproto, &ipproto_len) >= 0) return ipproto; #endif return 0; } static gint _determine_proto_value_based_on_so_domain_and_type(gint fd, gint address_family) { gint type; socklen_t len = sizeof(type); if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) return 0; switch (address_family) { case AF_INET: case AF_INET6: if (type == SOCK_DGRAM) return IPPROTO_UDP; else if (type == SOCK_STREAM) return IPPROTO_TCP; break; case AF_UNIX: break; default: g_assert_not_reached(); } return 0; } static gint _determine_proto(gint fd, gint address_family) { gint result = _determine_proto_value_based_on_so_protocol(fd); if (!result) result = _determine_proto_value_based_on_so_domain_and_type(fd, address_family); return result; } gboolean _extract_timestamp_from_cmsg(struct cmsghdr *cmsg, struct timespec *timestamp) { #ifdef SCM_TIMESTAMPNS if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) { memcpy(timestamp, CMSG_DATA(cmsg), sizeof(struct timespec)); return TRUE; } #endif return FALSE; } void log_transport_socket_parse_cmsg_method(LogTransportSocket *s, struct cmsghdr *cmsg, LogTransportAuxData *aux) { struct timespec timestamp; if (_extract_timestamp_from_cmsg(cmsg, ×tamp)) { log_transport_aux_data_set_timestamp(aux, ×tamp); return; } } static void _setup_fd(LogTransportSocket *self, gint fd) { #ifdef SO_TIMESTAMPNS gint on = 1; setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on)); #endif } #if defined(SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR) static void _parse_cmsg_to_aux(LogTransportSocket *self, struct msghdr *msg, LogTransportAuxData *aux) { struct cmsghdr *cmsg; if (!self->parse_cmsg || !aux) return; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { self->parse_cmsg(self, cmsg, aux); } } #else #define _parse_cmsg_to_aux(s, m, a) #endif static void _extract_from_msghdr_method(LogTransportSocket *self, struct msghdr *msg, LogTransportAuxData *aux) { if (msg->msg_namelen && aux) log_transport_aux_data_set_peer_addr_ref(aux, g_sockaddr_new((struct sockaddr *) msg->msg_name, msg->msg_namelen)); if (aux) aux->proto = self->proto; _parse_cmsg_to_aux(self, msg, aux); } static gssize log_transport_socket_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { LogTransportSocket *self = (LogTransportSocket *) s; gint rc; struct msghdr msg; struct iovec iov[1]; struct sockaddr_storage ss; #if defined(SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR) gchar ctlbuf[64]; msg.msg_control = ctlbuf; msg.msg_controllen = sizeof(ctlbuf); #endif msg.msg_name = (struct sockaddr *) &ss; msg.msg_namelen = sizeof(ss); msg.msg_iovlen = 1; msg.msg_iov = iov; iov[0].iov_base = buf; iov[0].iov_len = buflen; do { rc = recvmsg(self->super.fd, &msg, 0); } while (rc == -1 && errno == EINTR); if (rc > 0) _extract_from_msghdr_method(self, &msg, aux); return rc; } static gssize log_transport_socket_write_method(LogTransport *s, const gpointer buf, gsize buflen) { LogTransportSocket *self = (LogTransportSocket *) s; gint rc; do { rc = send(self->super.fd, buf, buflen, 0); } while (rc == -1 && errno == EINTR); return rc; } static void log_transport_socket_init_instance(LogTransportSocket *self, gint fd) { log_transport_init_instance(&self->super, fd); self->super.read = log_transport_socket_read_method; self->super.write = log_transport_socket_write_method; self->address_family = _determine_address_family(fd); self->proto = _determine_proto(fd, self->address_family); self->parse_cmsg = log_transport_socket_parse_cmsg_method; _setup_fd(self, fd); } static gssize log_transport_dgram_socket_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { gssize rc = log_transport_socket_read_method(s, buf, buflen, aux); if (rc == 0) { /* DGRAM sockets should never return EOF, they just need to be read again */ rc = -1; errno = EAGAIN; } return rc; } static gssize log_transport_dgram_socket_write_method(LogTransport *s, const gpointer buf, gsize buflen) { gint rc; rc = log_transport_socket_write_method(s, buf, buflen); /* NOTE: FreeBSD returns ENOBUFS on send() failure instead of indicating * this conditions via poll(). The return of ENOBUFS actually is a send * error and is calculated in IP statistics, so the best is to handle it as * a success. The only alternative would be to return EAGAIN, which could * cause syslog-ng to spin as long as buffer space is unavailable. Since * I'm not sure how much time that would take and I think spinning the CPU * is not a good idea in general, I just drop the packet in this case. * UDP is lossy anyway */ if (rc < 0 && errno == ENOBUFS) return buflen; return rc; } void log_transport_dgram_socket_init_instance(LogTransportSocket *self, gint fd) { log_transport_socket_init_instance(self, fd); self->super.read = log_transport_dgram_socket_read_method; self->super.write = log_transport_dgram_socket_write_method; } LogTransport * log_transport_dgram_socket_new(gint fd) { LogTransportSocket *self = g_new0(LogTransportSocket, 1); log_transport_dgram_socket_init_instance(self, fd); return &self->super; } void log_transport_stream_socket_free_method(LogTransport *s) { if (s->fd != -1) shutdown(s->fd, SHUT_RDWR); log_transport_free_method(s); } void log_transport_stream_socket_init_instance(LogTransportSocket *self, gint fd) { log_transport_socket_init_instance(self, fd); self->super.free_fn = log_transport_stream_socket_free_method; } LogTransport * log_transport_stream_socket_new(gint fd) { LogTransportSocket *self = g_new0(LogTransportSocket, 1); log_transport_stream_socket_init_instance(self, fd); return &self->super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-socket.h000066400000000000000000000034531450431004300236550ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_TRANSPORT_SOCKET_H_INCLUDED #define TRANSPORT_TRANSPORT_SOCKET_H_INCLUDED 1 #include "logtransport.h" typedef struct _LogTransportSocket LogTransportSocket; struct _LogTransportSocket { LogTransport super; gint address_family; gint proto; void (*parse_cmsg)(LogTransportSocket *self, struct cmsghdr *cmsg, LogTransportAuxData *aux); }; void log_transport_socket_parse_cmsg_method(LogTransportSocket *s, struct cmsghdr *cmsg, LogTransportAuxData *aux); void log_transport_dgram_socket_init_instance(LogTransportSocket *self, gint fd); LogTransport *log_transport_dgram_socket_new(gint fd); void log_transport_stream_socket_init_instance(LogTransportSocket *self, gint fd); void log_transport_stream_socket_free_method(LogTransport *s); LogTransport *log_transport_stream_socket_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-tls.c000066400000000000000000000166161450431004300231670ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "transport/transport-tls.h" #include "transport/transport-socket.h" #include "messages.h" #include #include #include typedef struct _LogTransportTLS { LogTransportSocket super; TLSSession *tls_session; gboolean sending_shutdown; } LogTransportTLS; static inline gboolean _is_shutdown_sent(gint shutdown_rc) { return shutdown_rc >= 0; } static inline void _handle_shutdown_error(LogTransportTLS *self, gint ssl_error) { switch (ssl_error) { case SSL_ERROR_WANT_READ: self->super.super.cond = G_IO_IN; errno = EAGAIN; break; case SSL_ERROR_WANT_WRITE: self->super.super.cond = G_IO_OUT; errno = EAGAIN; break; case SSL_ERROR_SYSCALL: /* errno is set accordingly */ self->sending_shutdown = FALSE; break; default: msg_error("SSL error while shutting down stream", tls_context_format_tls_error_tag(self->tls_session->ctx), tls_context_format_location_tag(self->tls_session->ctx)); ERR_clear_error(); errno = ECONNRESET; self->sending_shutdown = FALSE; break; } } static gint log_transport_tls_send_shutdown(LogTransportTLS *self) { self->sending_shutdown = TRUE; gint shutdown_rc = SSL_shutdown(self->tls_session->ssl); if (_is_shutdown_sent(shutdown_rc)) { self->sending_shutdown = FALSE; return shutdown_rc; } gint ssl_error = SSL_get_error(self->tls_session->ssl, shutdown_rc); _handle_shutdown_error(self, ssl_error); return shutdown_rc; } static gssize log_transport_tls_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { LogTransportTLS *self = (LogTransportTLS *) s; gint ssl_error; gint rc; if (G_UNLIKELY(self->sending_shutdown)) return (log_transport_tls_send_shutdown(self) >= 0) ? 0 : -1; /* assume that we need to poll our input for reading unless * SSL_ERROR_WANT_WRITE is specified by libssl */ self->super.super.cond = G_IO_IN; /* if we have found the peer has a certificate */ if( self->tls_session->peer_info.found ) { log_transport_aux_data_add_nv_pair(aux, ".tls.x509_cn", self->tls_session->peer_info.cn ); log_transport_aux_data_add_nv_pair(aux, ".tls.x509_o", self->tls_session->peer_info.o ); log_transport_aux_data_add_nv_pair(aux, ".tls.x509_ou", self->tls_session->peer_info.ou ); } do { rc = SSL_read(self->tls_session->ssl, buf, buflen); if (rc <= 0) { ssl_error = SSL_get_error(self->tls_session->ssl, rc); switch (ssl_error) { case SSL_ERROR_WANT_READ: rc = -1; errno = EAGAIN; break; case SSL_ERROR_WANT_WRITE: /* although we are reading this fd, libssl wants to write. This * happens during renegotiation for example */ self->super.super.cond = G_IO_OUT; rc = -1; errno = EAGAIN; break; case SSL_ERROR_ZERO_RETURN: rc = (log_transport_tls_send_shutdown(self) >= 0) ? 0 : -1; break; case SSL_ERROR_SYSCALL: // https://github.com/openssl/openssl/pull/11400 // There is a known bug in OpenSSL where it reports SSL_ERROR_SYSCALL without setting // the proper errno value. The mentioned PR were reverted because lot of legacy code // were broken by the fix. OpenSSL 3.0.0 will contain it. rc = (errno == 0) ? 0 : -1; break; default: goto tls_error; } } } while (rc == -1 && errno == EINTR); if (rc > 0) self->super.super.cond = 0; return rc; tls_error: msg_error("SSL error while reading stream", tls_context_format_tls_error_tag(self->tls_session->ctx), tls_context_format_location_tag(self->tls_session->ctx)); ERR_clear_error(); errno = ECONNRESET; return -1; } static gssize log_transport_tls_write_method(LogTransport *s, const gpointer buf, gsize buflen) { LogTransportTLS *self = (LogTransportTLS *) s; gint ssl_error; gint rc; /* assume that we need to poll our output for writing unless * SSL_ERROR_WANT_READ is specified by libssl */ self->super.super.cond = G_IO_OUT; rc = SSL_write(self->tls_session->ssl, buf, buflen); if (rc < 0) { ssl_error = SSL_get_error(self->tls_session->ssl, rc); switch (ssl_error) { case SSL_ERROR_WANT_READ: /* although we are writing this fd, libssl wants to read. This * happens during renegotiation for example */ self->super.super.cond = G_IO_IN; errno = EAGAIN; break; case SSL_ERROR_WANT_WRITE: errno = EAGAIN; break; case SSL_ERROR_SYSCALL: /* errno is set accordingly */ // https://github.com/openssl/openssl/pull/11400 // There is a known bug in OpenSSL where it reports SSL_ERROR_SYSCALL without setting // the proper errno value. The mentioned PR were reverted because lot of legacy code // were broken by the fix. OpenSSL 3.0.0 will contain it. if (errno == 0) { rc = -1; errno = ECONNRESET; } break; default: goto tls_error; } } else { self->super.super.cond = 0; } return rc; tls_error: msg_error("SSL error while writing stream", tls_context_format_tls_error_tag(self->tls_session->ctx), tls_context_format_location_tag(self->tls_session->ctx)); ERR_clear_error(); errno = EPIPE; return -1; } static void log_transport_tls_free_method(LogTransport *s); LogTransport * log_transport_tls_new(TLSSession *tls_session, gint fd) { LogTransportTLS *self = g_new0(LogTransportTLS, 1); log_transport_stream_socket_init_instance(&self->super, fd); self->super.super.cond = 0; self->super.super.read = log_transport_tls_read_method; self->super.super.write = log_transport_tls_write_method; self->super.super.free_fn = log_transport_tls_free_method; self->tls_session = tls_session; SSL_set_fd(self->tls_session->ssl, fd); return &self->super.super; } static void log_transport_tls_free_method(LogTransport *s) { LogTransportTLS *self = (LogTransportTLS *) s; tls_session_free(self->tls_session); log_transport_stream_socket_free_method(s); } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-tls.h000066400000000000000000000023021450431004300231570ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef TLSTRANSPORT_H_INCLUDED #define TLSTRANSPORT_H_INCLUDED #include "transport/logtransport.h" #include "transport/tls-context.h" LogTransport *log_transport_tls_new(TLSSession *tls_session, gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/transport/transport-udp-socket.c000066400000000000000000000117701450431004300244370ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-udp-socket.h" #include "transport/transport-socket.h" #include "gsocket.h" #include "scratch-buffers.h" #include "str-format.h" #include #include #include #include #include #include typedef struct _LogTransportUDP LogTransportUDP; struct _LogTransportUDP { LogTransportSocket super; GSockAddr *bind_addr; }; #if defined(__FreeBSD__) || defined(__OpenBSD__) GSockAddr * _extract_dest_ip4_addr_from_cmsg(struct cmsghdr *cmsg, GSockAddr *bind_addr) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { struct sockaddr_in sin = *(struct sockaddr_in *) &bind_addr->sa; struct in_addr *sin_addr = (struct in_addr *) CMSG_DATA(cmsg); sin.sin_addr = *sin_addr; return g_sockaddr_new((struct sockaddr *) &sin, sizeof(sin)); } return NULL; } #else GSockAddr * _extract_dest_ip4_addr_from_cmsg(struct cmsghdr *cmsg, GSockAddr *bind_addr) { #ifdef IP_PKTINFO if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { struct sockaddr_in sin; struct in_pktinfo inpkt; memcpy(&inpkt, CMSG_DATA(cmsg), sizeof(inpkt)); /* we need to copy the port number from the bind address as it is not * part of IP_PKTINFO */ sin = *(struct sockaddr_in *) &bind_addr->sa; sin.sin_addr = inpkt.ipi_addr; return g_sockaddr_new((struct sockaddr *) &sin, sizeof(sin)); } #endif return NULL; } #endif #if SYSLOG_NG_ENABLE_IPV6 GSockAddr * _extract_dest_ip6_addr_from_cmsg(struct cmsghdr *cmsg, GSockAddr *bind_addr) { #ifdef IPV6_PKTINFO if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { struct sockaddr_in6 sin6; struct in6_pktinfo in6pkt; memcpy(&in6pkt, CMSG_DATA(cmsg), sizeof(in6pkt)); /* we need to copy the port number (and scope id) from the bind * address as it is not part of IPV6_PKTINFO */ sin6 = *(struct sockaddr_in6 *) &bind_addr->sa; sin6.sin6_addr = in6pkt.ipi6_addr; return g_sockaddr_new((struct sockaddr *) &sin6, sizeof(sin6)); } #endif return NULL; } #endif GSockAddr * _extract_dest_addr_from_cmsg(struct cmsghdr *cmsg, GSockAddr *bind_addr) { if (bind_addr->sa.sa_family == AF_INET) return _extract_dest_ip4_addr_from_cmsg(cmsg, bind_addr); #if SYSLOG_NG_ENABLE_IPV6 else if (bind_addr->sa.sa_family == AF_INET6) return _extract_dest_ip6_addr_from_cmsg(cmsg, bind_addr); #endif else g_assert_not_reached(); } static void log_transport_udp_parse_cmsg(LogTransportSocket *s, struct cmsghdr *cmsg, LogTransportAuxData *aux) { LogTransportUDP *self = (LogTransportUDP *) s; log_transport_socket_parse_cmsg_method(s, cmsg, aux); GSockAddr *dest_addr = _extract_dest_addr_from_cmsg(cmsg, self->bind_addr); if (dest_addr) { log_transport_aux_data_set_local_addr_ref(aux, dest_addr); return; } } static void _setup_fd(LogTransportUDP *self, gint fd) { gint on = 1; self->bind_addr = g_socket_get_local_name(fd); if (self->super.address_family == AF_INET) { #if defined(__FreeBSD__) || defined(__OpenBSD__) setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); #elif defined(IP_PKTINFO) setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); #endif } #if SYSLOG_NG_ENABLE_IPV6 && defined(IPV6_RECVPKTINFO) else if (self->bind_addr->sa.sa_family == AF_INET6) setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); #endif else g_assert_not_reached(); } static void log_transport_udp_socket_free(LogTransport *s) { LogTransportUDP *self = (LogTransportUDP *)s; g_sockaddr_unref(self->bind_addr); log_transport_free_method(s); } LogTransport * log_transport_udp_socket_new(gint fd) { LogTransportUDP *self = g_new0(LogTransportUDP, 1); log_transport_dgram_socket_init_instance(&self->super, fd); self->super.super.free_fn = log_transport_udp_socket_free; self->super.parse_cmsg = log_transport_udp_parse_cmsg; _setup_fd(self, fd); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/lib/transport/transport-udp-socket.h000066400000000000000000000022401450431004300244340ustar00rootroot00000000000000/* * Copyright (c) 2002-2019 Balabit * Copyright (c) 1998-2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_UDP_SOCKET_H_INCLUDED #define TRANSPORT_UDP_SOCKET_H_INCLUDED #include "transport/logtransport.h" LogTransport *log_transport_udp_socket_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/lib/userdb.c000066400000000000000000000037641450431004300175630ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "userdb.h" #include #include #include #include #include gboolean resolve_user(const char *user, gint *uid) { struct passwd *pw; gchar *endptr; *uid = 0; if (!(*user)) return FALSE; *uid = strtol(user, &endptr, 0); if (*endptr) { pw = getpwnam(user); if (!pw) return FALSE; *uid = pw->pw_uid; } return TRUE; } gboolean resolve_group(const char *group, gint *gid) { struct group *gr; gchar *endptr; *gid = 0; if (!(*group)) return FALSE; *gid = strtol(group, &endptr, 0); if (*endptr) { gr = getgrnam(group); if (!gr) return FALSE; *gid = gr->gr_gid; } return TRUE; } gboolean resolve_user_group(char *arg, gint *uid, gint *gid) { char *user, *group; *uid = 0; user = strtok(arg, ":."); group = strtok(NULL, ""); if (user && !resolve_user(user, uid)) return FALSE; if (group && !resolve_group(group, gid)) return FALSE; return TRUE; } syslog-ng-syslog-ng-4.4.0/lib/userdb.h000066400000000000000000000025031450431004300175560ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef USERDB_H_INCLUDED #define USERDB_H_INCLUDED 1 #include "syslog-ng.h" /* deliberately using gint here as the extremal values may not fit into uid_t/gid_t */ gboolean resolve_user(const char *user, gint *uid); gboolean resolve_group(const char *group, gint *gid); gboolean resolve_user_group(char *arg, gint *uid, gint *gid); #endif syslog-ng-syslog-ng-4.4.0/lib/utf8utils.c000066400000000000000000000220671450431004300202430ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "utf8utils.h" #include "str-utils.h" static inline gboolean _is_character_unsafe(gunichar uchar, const gchar *unsafe_chars) { /* These G_LIKELY/UNLIKELY clauses assume that most characters are in the * ASCII range and that unsafe characters are not specified. Since this function * is called for each and every character generated by format-json/format-welf * it does make a difference. */ if (G_UNLIKELY(uchar >= 256)) return FALSE; if (G_LIKELY(!unsafe_chars)) return FALSE; return _strchr_optimized_for_single_char_haystack(unsafe_chars, (gchar) uchar) != NULL; } /** * This function escapes an unsanitized input (e.g. that can contain binary * characters, and produces an escaped format that can be deescaped in need, * which is guaranteed to be utf8 clean. The major difference between * "binary" and "text" form is that the receiver is able to cope with \xXX * sequences that can incorporate invalid utf8 sequences when decoded. With * "text" format, we never embed anything that would become not valid utf8 * when decoded. * * Here are the rules that the routine follows: * - well-known control characters are escaped (0x0a as \n and so on) * - other control characters as per control_format * - backslash is escaped as \\ * - any additional characters (only ASCII is supported) as \ * - invalid utf8 sequences are converted as per invalid_format * - utf8 characters are reproduced as is */ static gsize _append_escaped_utf8_character(GString *escaped_output, const gchar **raw, gssize raw_len, const gchar *unsafe_chars, const gchar *control_format, const gchar *invalid_format) { const gchar *char_ptr = *raw; gunichar uchar = g_utf8_get_char_validated(char_ptr, raw_len); if (G_UNLIKELY(uchar == (gunichar) -1 || uchar == (gunichar) -2)) { g_string_append_printf(escaped_output, invalid_format, *(guint8 *) char_ptr); (*raw)++; return 1; } else if (G_UNLIKELY(uchar < 32 || uchar == '\\')) { switch (uchar) { case '\b': g_string_append(escaped_output, "\\b"); break; case '\f': g_string_append(escaped_output, "\\f"); break; case '\n': g_string_append(escaped_output, "\\n"); break; case '\r': g_string_append(escaped_output, "\\r"); break; case '\t': g_string_append(escaped_output, "\\t"); break; case '\\': g_string_append(escaped_output, "\\\\"); break; default: g_string_append_printf(escaped_output, control_format, uchar); break; } } else if (G_UNLIKELY(_is_character_unsafe(uchar, unsafe_chars))) g_string_append_printf(escaped_output, "\\%c", (gchar) uchar); else g_string_append_unichar_optimized(escaped_output, uchar); *raw = g_utf8_next_char(char_ptr); return *raw - char_ptr; } static void _append_unsafe_utf8_as_escaped_with_specific_length(GString *escaped_output, const gchar *raw, gsize raw_len, const gchar *unsafe_chars, const gchar *control_format, const gchar *invalid_format) { const gchar *raw_end = raw + raw_len; while (raw < raw_end) _append_escaped_utf8_character(escaped_output, &raw, raw_end - raw, unsafe_chars, control_format, invalid_format); } static void _append_unsafe_utf8_as_escaped_nul_terminated(GString *escaped_output, const gchar *raw, const gchar *unsafe_chars, const gchar *control_format, const gchar *invalid_format) { _append_unsafe_utf8_as_escaped_with_specific_length(escaped_output, raw, strlen(raw), unsafe_chars, control_format, invalid_format); } /** * @see _append_escaped_utf8_character() */ void append_unsafe_utf8_as_escaped(GString *escaped_output, const gchar *raw, gssize raw_len, const gchar *unsafe_chars, const gchar *control_format, const gchar *invalid_format) { if (raw_len < 0) _append_unsafe_utf8_as_escaped_nul_terminated(escaped_output, raw, unsafe_chars, control_format, invalid_format); else _append_unsafe_utf8_as_escaped_with_specific_length(escaped_output, raw, raw_len, unsafe_chars, control_format, invalid_format); } /** * This function escapes an unsanitized input (e.g. that can contain binary * characters, and produces an escaped format that can be deescaped in need, * which is guaranteed to be utf8 clean. The major difference between * "binary" and "text" form is that the receiver is able to cope with \xXX * sequences that can incorporate invalid utf8 sequences when decoded. With * "text" format, we never embed anything that would become not valid utf8 * when decoded. * * Here are the rules that the routine follows: * - well-known control characters are escaped (0x0a as \n and so on) * - other control characters as per control_format (\xXX) * - backslash is escaped as \\ * - any additional characters (only ASCII is supported) as \ * - invalid utf8 sequences are converted as per invalid_format (\xXX) * - utf8 characters are reproduced as is * * This is basically meant to be used when sending data to * 8 bit clean receivers, e.g. syslog-ng or WELF. * @see append_unsafe_utf8_as_escaped() */ void append_unsafe_utf8_as_escaped_binary(GString *escaped_string, const gchar *str, gssize str_len, const gchar *unsafe_chars) { append_unsafe_utf8_as_escaped(escaped_string, str, str_len, unsafe_chars, "\\x%02x", "\\x%02x"); } gchar * convert_unsafe_utf8_to_escaped_binary(const gchar *str, gssize str_len, const gchar *unsafe_chars) { if (str_len < 0) str_len = strlen(str); GString *escaped_string = g_string_sized_new(str_len); append_unsafe_utf8_as_escaped_binary(escaped_string, str, str_len, unsafe_chars); return g_string_free(escaped_string, FALSE); } /** * This function escapes an unsanitized input (e.g. that can contain binary * characters, and produces an escaped format that can be deescaped in need, * which is guaranteed to be utf8 clean. The major difference between * "binary" and "text" form is that the receiver is able to cope with \xXX * sequences that can incorporate invalid utf8 sequences when decoded. With * "text" format, we never embed anything that would become not valid utf8 * when decoded. * * Here are the rules that the routine follows: * - well-known control characters are escaped (0x0a as \n and so on) * - other control characters as per control_format (\xXX) * - backslash is escaped as \\ * - any additional characters (only ASCII is supported) as \ * - invalid utf8 sequences are converted as per invalid_format (\\xXX) * - utf8 characters are reproduced as is * * This is basically meant to be used when sending data to * utf8 only receivers, e.g. JSON. * @see append_unsafe_utf8_as_escaped() */ void append_unsafe_utf8_as_escaped_text(GString *escaped_string, const gchar *str, gssize str_len, const gchar *unsafe_chars) { append_unsafe_utf8_as_escaped(escaped_string, str, str_len, unsafe_chars, "\\x%02x", "\\\\x%02x"); } gchar * convert_unsafe_utf8_to_escaped_text(const gchar *str, gssize str_len, const gchar *unsafe_chars) { if (str_len < 0) str_len = strlen(str); GString *escaped_string = g_string_sized_new(str_len); append_unsafe_utf8_as_escaped_text(escaped_string, str, str_len, unsafe_chars); return g_string_free(escaped_string, FALSE); } syslog-ng-syslog-ng-4.4.0/lib/utf8utils.h000066400000000000000000000037321450431004300202460ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef UTF8UTILS_H_INCLUDED #define UTF8UTILS_H_INCLUDED #include "syslog-ng.h" void append_unsafe_utf8_as_escaped_binary(GString *escaped_string, const gchar *str, gssize str_len, const gchar *unsafe_chars); gchar *convert_unsafe_utf8_to_escaped_binary(const gchar *str, gssize str_len, const gchar *unsafe_chars); void append_unsafe_utf8_as_escaped_text(GString *escaped_string, const gchar *str, gssize str_len, const gchar *unsafe_chars); gchar *convert_unsafe_utf8_to_escaped_text(const gchar *str, gssize str_len, const gchar *unsafe_chars); void append_unsafe_utf8_as_escaped(GString *escaped_output, const gchar *raw, gssize raw_len, const gchar *unsafe_chars, const gchar *control_format, const gchar *invalid_format); #endif syslog-ng-syslog-ng-4.4.0/lib/uuid.c000066400000000000000000000036441450431004300172420ustar00rootroot00000000000000/* * Copyright (c) 2010-2012 Balabit * Copyright (c) 2010-2012 Balázs Scheidler * Copyright (c) 2012 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "uuid.h" #include #include void uuid_gen_random(gchar *buf, gsize buflen) { union { struct { guint32 time_low; guint16 time_mid; guint16 time_hi_and_version; guint8 clk_seq_hi_res; guint8 clk_seq_low; guint8 node[6]; guint16 node_low; guint32 node_hi; }; guchar __rnd[16]; } uuid; RAND_bytes(uuid.__rnd, sizeof(uuid)); uuid.clk_seq_hi_res = (uuid.clk_seq_hi_res & ~0xC0) | 0x80; uuid.time_hi_and_version = htons((uuid.time_hi_and_version & ~0xF000) | 0x4000); g_snprintf(buf, buflen, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, uuid.clk_seq_hi_res, uuid.clk_seq_low, uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3], uuid.node[4], uuid.node[5]); } syslog-ng-syslog-ng-4.4.0/lib/uuid.h000066400000000000000000000022461450431004300172440ustar00rootroot00000000000000/* * Copyright (c) 2010-2012 Balabit * Copyright (c) 2010-2012 Balázs Scheidler * Copyright (c) 2012 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef UUID_H_INCLUDED #define UUID_H_INCLUDED 1 #include "syslog-ng.h" void uuid_gen_random(gchar *buf, gsize buflen); #endif syslog-ng-syslog-ng-4.4.0/lib/value-pairs/000077500000000000000000000000001450431004300203515ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/value-pairs/CMakeLists.txt000066400000000000000000000005531450431004300231140ustar00rootroot00000000000000set(VALUE_PAIRS_HEADERS value-pairs/value-pairs.h value-pairs/transforms.h value-pairs/cmdline.h value-pairs/internals.h value-pairs/evttag.h PARENT_SCOPE) set(VALUE_PAIRS_SOURCES value-pairs/value-pairs.c value-pairs/transforms.c value-pairs/cmdline.c value-pairs/evttag.c PARENT_SCOPE) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/lib/value-pairs/Makefile.am000066400000000000000000000010071450431004300224030ustar00rootroot00000000000000value_pairsincludedir = ${pkgincludedir}/value-pairs EXTRA_DIST += lib/value-pairs/CMakeLists.txt \ lib/value-pairs/tests/CMakeLists.txt value_pairsinclude_HEADERS = \ lib/value-pairs/value-pairs.h \ lib/value-pairs/transforms.h \ lib/value-pairs/cmdline.h \ lib/value-pairs/internals.h \ lib/value-pairs/evttag.h value_pairs_sources = \ lib/value-pairs/value-pairs.c \ lib/value-pairs/transforms.c \ lib/value-pairs/cmdline.c \ lib/value-pairs/evttag.c include lib/value-pairs/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/lib/value-pairs/cmdline.c000066400000000000000000000377111450431004300221410ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "value-pairs/cmdline.h" #include "value-pairs/internals.h" #include #include #include /******************************************************************************* * Command line parser *******************************************************************************/ static void vp_cmdline_parse_rekey_finish (gpointer data) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; if (vpts) value_pairs_add_transforms (vp, args[2]); args[2] = NULL; g_free(args[3]); args[3] = NULL; } static void vp_cmdline_start_key(gpointer data, const gchar *key) { gpointer *args = (gpointer *) data; vp_cmdline_parse_rekey_finish (data); args[3] = g_strdup(key); } static ValuePairsTransformSet * vp_cmdline_rekey_verify (gchar *key, ValuePairsTransformSet *vpts, gpointer data) { gpointer *args = (gpointer *)data; if (!vpts) { if (!key) return NULL; vpts = value_pairs_transform_set_new (key); vp_cmdline_parse_rekey_finish (data); args[2] = vpts; return vpts; } return vpts; } /* parse a value-pair specification from a command-line like environment */ static gboolean vp_cmdline_parse_scope(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; gchar **scopes; gint i; vp_cmdline_parse_rekey_finish (data); scopes = g_strsplit (value, ",", -1); for (i = 0; scopes[i] != NULL; i++) { if (!value_pairs_add_scope (vp, scopes[i])) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing value-pairs: unknown scope %s", scopes[i]); g_strfreev (scopes); return FALSE; } } g_strfreev (scopes); return TRUE; } static gboolean vp_cmdline_parse_exclude(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; gchar **excludes; gint i; vp_cmdline_parse_rekey_finish (data); excludes = g_strsplit(value, ",", -1); for (i = 0; excludes[i] != NULL; i++) value_pairs_add_glob_pattern(vp, excludes[i], FALSE); g_strfreev(excludes); return TRUE; } static gboolean vp_cmdline_parse_key(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; gchar **keys; gint i; vp_cmdline_start_key(data, value); keys = g_strsplit(value, ",", -1); for (i = 0; keys[i] != NULL; i++) value_pairs_add_glob_pattern(vp, keys[i], TRUE); g_strfreev(keys); return TRUE; } static gboolean vp_cmdline_parse_rekey(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vp_cmdline_start_key(data, value); return TRUE; } static gboolean vp_cmdline_parse_pair (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; GlobalConfig *cfg = (GlobalConfig *) args[0]; gchar **kv; gboolean res = FALSE; LogTemplate *template; vp_cmdline_parse_rekey_finish (data); if (strchr(value, '=') == NULL) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing value-pairs: expected an equal sign in key=value pair"); return FALSE; } kv = g_strsplit(value, "=", 2); template = log_template_new(cfg, NULL); if (!log_template_compile_with_type_hint(template, kv[1], error)) goto error; value_pairs_add_pair(vp, kv[0], template); res = TRUE; error: log_template_unref(template); g_strfreev(kv); return res; } static gboolean vp_cmdline_parse_pair_or_key (const gchar *option_name, const gchar *value, gpointer data, GError **error) { if (strchr(value, '=') == NULL) return vp_cmdline_parse_key(option_name, value, data, error); else return vp_cmdline_parse_pair(option_name, value, data, error); } static gboolean vp_cmdline_parse_subkeys(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; if (!value[0]) { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --subkeys requires a non-empty argument"); return FALSE; } GString *prefix = g_string_new(value); g_string_append_c(prefix, '*'); value_pairs_add_glob_pattern(vp, prefix->str, TRUE); vp_cmdline_start_key(data, prefix->str); vpts = vp_cmdline_rekey_verify(prefix->str, vpts, data); if (!vpts) { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --subkeys failed to create key"); g_string_free(prefix, TRUE); return FALSE; } value_pairs_transform_set_add_func (vpts, value_pairs_new_transform_replace_prefix(value, "")); g_string_free(prefix, TRUE); return TRUE; } static gboolean vp_cmdline_parse_rekey_replace_prefix (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; gchar **kv; vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --replace-prefix used without --key or --rekey"); return FALSE; } if (!g_strstr_len (value, strlen (value), "=")) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing value-pairs: rekey replace-prefix construct should be in the format string=replacement"); return FALSE; } kv = g_strsplit(value, "=", 2); value_pairs_transform_set_add_func (vpts, value_pairs_new_transform_replace_prefix (kv[0], kv[1])); g_free (kv[0]); g_free (kv[1]); g_free (kv); return TRUE; } static gboolean vp_cmdline_parse_rekey_add_prefix (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --add-prefix used without --key or --rekey"); return FALSE; } value_pairs_transform_set_add_func (vpts, value_pairs_new_transform_add_prefix (value)); return TRUE; } static gboolean vp_cmdline_parse_rekey_upper (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --upper used without --key or --rekey"); return FALSE; } value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_upper ()); return TRUE; } static gboolean vp_cmdline_parse_rekey_lower (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --lower used without --key or --rekey"); return FALSE; } value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_lower ()); return TRUE; } static gboolean vp_cmdline_parse_rekey_shift (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; gchar *end = NULL; gint number_to_shift = strtol(value, &end, 0); if (number_to_shift <= 0 || *end != 0) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs, argument to --shift is not numeric or not a positive number"); return FALSE; } vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --shift used without --key or --rekey"); return FALSE; } value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_shift (number_to_shift)); return TRUE; } static gboolean vp_cmdline_parse_rekey_shift_levels (const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) args[2]; gchar *key = (gchar *) args[3]; gchar *end = NULL; gint number_to_shift = strtol(value, &end, 0); if (number_to_shift <= 0 || *end != 0) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs, argument to --shift-levels is not numeric or not a positive number"); return FALSE; } vpts = vp_cmdline_rekey_verify (key, vpts, data); if (!vpts) { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Error parsing value-pairs: --shift-levels used without --key or --rekey"); return FALSE; } value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_shift_levels (number_to_shift)); return TRUE; } static gboolean vp_cmdline_parse_cast(const gchar *option_name, const gchar *value, gpointer data, GError **error) { gpointer *args = (gpointer *) data; ValuePairs *vp = (ValuePairs *) args[1]; if (strcmp(option_name, "--no-cast") == 0) value_pairs_set_cast_to_strings(vp, FALSE); else if (strcmp(option_name, "--cast") == 0) value_pairs_set_cast_to_strings(vp, TRUE); else if (strcmp(option_name, "--auto-cast") == 0) value_pairs_set_auto_cast(vp); else return FALSE; return TRUE; } static void _value_pairs_add_optional_options(ValuePairs *vp, GOptionGroup *og, const ValuePairsOptionalOptions *optional_options) { GOptionEntry include_bytes_option[] = { { "include-bytes", 0, 0, G_OPTION_ARG_NONE, &vp->include_bytes, NULL, NULL }, { NULL }, }; if (optional_options->enable_include_bytes) g_option_group_add_entries(og, include_bytes_option); } static gboolean value_pairs_parse_command_line(ValuePairs *vp, gint *argc, gchar ***argv, const ValuePairsOptionalOptions *optional_options, GOptionGroup *custom_options, GError **error) { GOptionContext *ctx; GOptionEntry vp_options[] = { { "scope", 's', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_scope, NULL, NULL }, { "exclude", 'x', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_exclude, NULL, NULL }, { "key", 'k', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_key, NULL, NULL }, { "rekey", 'r', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey, NULL, NULL }, { "pair", 'p', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair, NULL, NULL }, { "upper", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_upper, NULL, NULL }, { "lower", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_lower, NULL, NULL }, { "shift", 'S', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_shift, NULL, NULL }, { "shift-levels", 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_shift_levels, NULL, NULL }, { "add-prefix", 'A', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_add_prefix, NULL, NULL }, { "replace-prefix", 'R', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_replace_prefix, NULL, NULL }, { "replace", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_rekey_replace_prefix, NULL, NULL }, { "subkeys", 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_subkeys, NULL, NULL }, { "omit-empty-values", 0, 0, G_OPTION_ARG_NONE, &vp->omit_empty_values, NULL, NULL }, { "cast", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_cast, NULL, NULL }, { "no-cast", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_cast, NULL, NULL }, { "auto-cast", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_cast, NULL, NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair_or_key, NULL, NULL }, { NULL } }; gpointer user_data_args[4]; gboolean success; user_data_args[0] = vp->cfg; user_data_args[1] = vp; user_data_args[2] = NULL; user_data_args[3] = NULL; ctx = g_option_context_new("value-pairs"); GOptionGroup *og = g_option_group_new("value-pairs", "", "", user_data_args, NULL); g_option_group_add_entries(og, vp_options); if (optional_options) _value_pairs_add_optional_options(vp, og, optional_options); /* only the main group gets to process G_OPTION_REMAINING options, so * vp_options is the main one */ g_option_context_set_main_group(ctx, og); if (custom_options) g_option_context_add_group(ctx, custom_options); success = g_option_context_parse(ctx, argc, argv, error); vp_cmdline_parse_rekey_finish(user_data_args); g_option_context_free(ctx); return success; } ValuePairs * value_pairs_new_from_cmdline(GlobalConfig *cfg, gint *argc, gchar ***argv, const ValuePairsOptionalOptions *optional_options, GOptionGroup *custom_options, GError **error) { ValuePairs *vp; vp = value_pairs_new(cfg); if (!value_pairs_parse_command_line(vp, argc, argv, optional_options, custom_options, error)) { value_pairs_unref(vp); return NULL; } return vp; } syslog-ng-syslog-ng-4.4.0/lib/value-pairs/cmdline.h000066400000000000000000000031041450431004300221330ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VALUE_PAIRS_CMDLINE_H_INCLUDED #define VALUE_PAIRS_CMDLINE_H_INCLUDED 1 #include "value-pairs/value-pairs.h" typedef struct ValuePairsOptionalOptions_ { gboolean enable_include_bytes; } ValuePairsOptionalOptions; ValuePairs *value_pairs_new_from_cmdline(GlobalConfig *cfg, gint *argc, gchar ***argv, const ValuePairsOptionalOptions *optional_options, GOptionGroup *custom_options, GError **error); #endif syslog-ng-syslog-ng-4.4.0/lib/value-pairs/evttag.c000066400000000000000000000033451450431004300220140ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "value-pairs/evttag.h" static gboolean _append_pair_to_debug_string(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { GString *text = (GString *) user_data; g_string_append_printf(text, "%s=%s ", name, value); return FALSE; } EVTTAG * evt_tag_value_pairs(const char *key, ValuePairs *vp, LogMessage *msg, LogTemplateEvalOptions *options) { GString *debug_text = g_string_new(""); EVTTAG *result; value_pairs_foreach(vp, _append_pair_to_debug_string, msg, options, debug_text); result = evt_tag_str(key, debug_text->str); g_string_free(debug_text, TRUE); return result; } syslog-ng-syslog-ng-4.4.0/lib/value-pairs/evttag.h000066400000000000000000000023641450431004300220210ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VALUE_PAIRS_EVTTAG_H_INCLUDED #define VALUE_PAIRS_EVTTAG_H_INCLUDED 1 #include "value-pairs.h" #include "messages.h" EVTTAG *evt_tag_value_pairs(const char *key, ValuePairs *vp, LogMessage *msg, LogTemplateEvalOptions *options); #endif syslog-ng-syslog-ng-4.4.0/lib/value-pairs/internals.h000066400000000000000000000031761450431004300225300ustar00rootroot00000000000000/* * Copyright (c) 2011-2014 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VALUE_PAIRS_INTERNALS_H_INCLUDED #define VALUE_PAIRS_INTERNALS_H_INCLUDED 1 #include "syslog-ng.h" #include "atomic.h" struct _ValuePairs { GAtomicCounter ref_cnt; GlobalConfig *cfg; GPtrArray *builtins; GPtrArray *patterns; GPtrArray *vpairs; GPtrArray *transforms; gboolean omit_empty_values; gboolean include_bytes; /* guint32 as CfgFlagHandler only supports 32 bit integers */ guint32 scopes; /* for compatibility with 3.x versions, apply automatic conversion to * strings to avoid leaking type information to callers */ gboolean cast_to_strings; gboolean explicit_cast_to_strings; }; #endif syslog-ng-syslog-ng-4.4.0/lib/value-pairs/tests/000077500000000000000000000000001450431004300215135ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/lib/value-pairs/tests/CMakeLists.txt000066400000000000000000000002041450431004300242470ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_value_pairs DEPENDS syslogformat) add_unit_test(CRITERION LIBTEST TARGET test_value_pairs_walk) syslog-ng-syslog-ng-4.4.0/lib/value-pairs/tests/Makefile.am000066400000000000000000000010031450431004300235410ustar00rootroot00000000000000lib_value_pairs_tests_TESTS = \ lib/value-pairs/tests/test_value_pairs \ lib/value-pairs/tests/test_value_pairs_walk check_PROGRAMS += \ ${lib_value_pairs_tests_TESTS} lib_value_pairs_tests_test_value_pairs_LDADD = $(TEST_LDADD) lib_value_pairs_tests_test_value_pairs_CFLAGS = $(TEST_CFLAGS) lib_value_pairs_tests_test_value_pairs_LDFLAGS = $(PREOPEN_SYSLOGFORMAT) lib_value_pairs_tests_test_value_pairs_walk_LDADD = $(TEST_LDADD) lib_value_pairs_tests_test_value_pairs_walk_CFLAGS = $(TEST_CFLAGS) syslog-ng-syslog-ng-4.4.0/lib/value-pairs/tests/test_value_pairs.c000066400000000000000000000505221450431004300252340ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "value-pairs/value-pairs.h" #include "logmsg/logmsg.h" #include "apphook.h" #include "cfg.h" #include "plugin.h" #include "msg-format.h" #include gboolean success = TRUE; gboolean vp_keys_foreach(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { gpointer *args = (gpointer *) user_data; GList **keys = (GList **) args[0]; gboolean *test_key_found = (gboolean *) args[1]; if (strcmp(name, "test.key") != 0) *keys = g_list_insert_sorted(*keys, g_strdup(name), (GCompareFunc) strcmp); else *test_key_found = TRUE; return FALSE; } void cat_keys_foreach(const gchar *name, gpointer user_data) { GString *res = (GString *) user_data; if (res->len > 0) g_string_append_c(res, ','); g_string_append(res, name); } MsgFormatOptions parse_options; LogTemplateOptions template_options; LogMessage * create_message(void) { LogMessage *msg; const gchar *text = "<134>1 2009-10-16T11:51:56+02:00 exchange.macartney.esbjerg MSExchange_ADAccess 20208 _MSGID_ [origin ip=\"exchange.macartney.esbjerg\"][meta sequenceId=\"191732\" sysUpTime=\"68807696\"][EventData@18372.4 Data=\"MSEXCHANGEOWAAPPPOOL.CONFIG\\\" -W \\\"\\\" -M 1 -AP \\\"MSEXCHANGEOWAAPPPOOL5244fileserver.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 mail.macartney.esbjerg CDG 1 7 7 1 0 1 1 7 1 maindc.macartney.esbjerg CD- 1 6 6 0 0 1 1 6 1 \"][Keywords@18372.4 Keyword=\"Classic\"] ApplicationMSExchangeADAccess: message"; const gchar *unset_nvpair = "unset_value"; msg = msg_format_parse(&parse_options, (const guchar *) text, strlen(text)); log_msg_set_tag_by_name(msg, "almafa"); log_msg_set_value_by_name(msg, unset_nvpair, "value that has been unset", -1); log_msg_unset_value_by_name(msg, unset_nvpair); return msg; } static LogTemplate * create_template(const gchar *type_hint_string, const gchar *template_string) { LogTemplate *template; template = log_template_new(configuration, NULL); cr_assert(log_template_compile(template, template_string, NULL)); log_template_set_type_hint(template, type_hint_string, NULL); return template; } static void assert_keys_match_expected(const gchar *scope, GList *vp_keys_list, const gchar *expected) { gchar **expected_list = g_strsplit(expected, ",", -1); GList *l = vp_keys_list; gint i = 0; for (i = 0; l && expected_list[i]; l = l->next, i++) { cr_assert_str_eq((const gchar *) l->data, expected_list[i], "Expected element at index %d mismatch %s <> %s, scope=%s", i, (const gchar *) l->data, expected_list[i], scope); } cr_assert(l == NULL && expected_list[i] == NULL); g_strfreev(expected_list); } void testcase(const gchar *scope, const gchar *exclude, const gchar *expected) { ValuePairs *vp; GList *vp_keys_list = NULL; LogMessage *msg = create_message(); gpointer args[2]; gboolean test_key_found = FALSE; LogTemplate *template; vp = value_pairs_new(configuration); value_pairs_add_scope(vp, scope); if (exclude) value_pairs_add_glob_pattern(vp, exclude, FALSE); template = create_template("string", "$MESSAGE"); value_pairs_add_pair(vp, "test.key", template); log_template_unref(template); args[0] = &vp_keys_list; args[1] = &test_key_found; LogTemplateEvalOptions options = {&template_options, LTZ_LOCAL, 11, NULL, LM_VT_STRING}; value_pairs_foreach(vp, vp_keys_foreach, msg, &options, args); cr_expect(test_key_found, "test.key is not found in the result set"); assert_keys_match_expected(scope, vp_keys_list, expected); g_list_foreach(vp_keys_list, (GFunc) g_free, NULL); g_list_free(vp_keys_list); log_msg_unref(msg); value_pairs_unref(vp); } void transformers_testcase(const gchar *scope, const gchar *transformed_keys, const gchar *expected, GPtrArray *transformers) { ValuePairs *vp; GList *vp_keys_list = NULL; LogMessage *msg = create_message(); gpointer args[2]; gboolean test_key_found = FALSE; vp = value_pairs_new(configuration); value_pairs_add_scope(vp, scope); if (transformers) { gint i; ValuePairsTransformSet *vpts = value_pairs_transform_set_new(transformed_keys ? : "*"); for (i = 0; i < transformers->len; i++) value_pairs_transform_set_add_func(vpts, g_ptr_array_index(transformers, i)); value_pairs_add_transforms(vp, vpts); } args[0] = &vp_keys_list; args[1] = &test_key_found; LogTemplateEvalOptions options = {&template_options, LTZ_LOCAL, 11, NULL, LM_VT_STRING}; value_pairs_foreach(vp, vp_keys_foreach, msg, &options, args); assert_keys_match_expected(scope, vp_keys_list, expected); g_list_foreach(vp_keys_list, (GFunc) g_free, NULL); g_list_free(vp_keys_list); log_msg_unref(msg); value_pairs_unref(vp); } struct value_pairs_params { gchar *scope; gchar *exclude; gchar *expected; GPtrArray *transformers; }; ParameterizedTestParameters(value_pairs, test) { static const struct value_pairs_params params[] = { { "rfc3164", NULL, "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM", NULL }, {"rfc3164", NULL, "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM", NULL }, {"core", NULL, "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM", NULL }, {"base", NULL, "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM", NULL }, {"rfc5424", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip,DATE,FACILITY,HOST,MESSAGE,MSGID,PID,PRIORITY,PROGRAM", NULL }, {"syslog-proto", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip,DATE,FACILITY,HOST,MESSAGE,MSGID,PID,PRIORITY,PROGRAM", NULL }, {"selected-macros", NULL, "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM,SEQNUM,SOURCEIP,TAGS", NULL }, {"nv-pairs", NULL, "HOST,MESSAGE,MSGID,PID,PROGRAM", NULL }, {"dot-nv-pairs", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip", NULL }, {"sdata", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip", NULL }, {"all-nv-pairs", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip,HOST,MESSAGE,MSGID,PID,PROGRAM", NULL }, {"everything", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip,AMPM,BSDTAG,C_AMPM,C_DATE,C_DAY,C_FULLDATE,C_HOUR,C_HOUR12,C_ISODATE,C_ISOWEEK,C_MIN,C_MONTH,C_MONTH_ABBREV,C_MONTH_NAME,C_MONTH_WEEK,C_MSEC,C_SEC,C_STAMP,C_TZ,C_TZOFFSET,C_UNIXTIME,C_USEC,C_WEEK,C_WEEKDAY,C_WEEK_DAY,C_WEEK_DAY_ABBREV,C_WEEK_DAY_NAME,C_YEAR,C_YEAR_DAY,DATE,DAY,DESTIP,DESTPORT,FACILITY,FACILITY_NUM,FULLDATE,HOST,HOSTID,HOUR,HOUR12,ISODATE,ISOWEEK,LEVEL,LEVEL_NUM,LOGHOST,MESSAGE,MIN,MONTH,MONTH_ABBREV,MONTH_NAME,MONTH_WEEK,MSEC,MSG,MSGHDR,MSGID,PID,PRI,PRIORITY,PROGRAM,PROTO,P_AMPM,P_DATE,P_DAY,P_FULLDATE,P_HOUR,P_HOUR12,P_ISODATE,P_ISOWEEK,P_MIN,P_MONTH,P_MONTH_ABBREV,P_MONTH_NAME,P_MONTH_WEEK,P_MSEC,P_SEC,P_STAMP,P_TZ,P_TZOFFSET,P_UNIXTIME,P_USEC,P_WEEK,P_WEEKDAY,P_WEEK_DAY,P_WEEK_DAY_ABBREV,P_WEEK_DAY_NAME,P_YEAR,P_YEAR_DAY,RAWMSG_SIZE,R_AMPM,R_DATE,R_DAY,R_FULLDATE,R_HOUR,R_HOUR12,R_ISODATE,R_ISOWEEK,R_MIN,R_MONTH,R_MONTH_ABBREV,R_MONTH_NAME,R_MONTH_WEEK,R_MSEC,R_SEC,R_STAMP,R_TZ,R_TZOFFSET,R_UNIXTIME,R_USEC,R_WEEK,R_WEEKDAY,R_WEEK_DAY,R_WEEK_DAY_ABBREV,R_WEEK_DAY_NAME,R_YEAR,R_YEAR_DAY,SDATA,SEC,SEQNUM,SEVERITY,SEVERITY_NUM,SOURCEIP,STAMP,SYSUPTIME,S_AMPM,S_DATE,S_DAY,S_FULLDATE,S_HOUR,S_HOUR12,S_ISODATE,S_ISOWEEK,S_MIN,S_MONTH,S_MONTH_ABBREV,S_MONTH_NAME,S_MONTH_WEEK,S_MSEC,S_SEC,S_STAMP,S_TZ,S_TZOFFSET,S_UNIXTIME,S_USEC,S_WEEK,S_WEEKDAY,S_WEEK_DAY,S_WEEK_DAY_ABBREV,S_WEEK_DAY_NAME,S_YEAR,S_YEAR_DAY,TAG,TAGS,TZ,TZOFFSET,UNIXTIME,USEC,WEEK,WEEKDAY,WEEK_DAY,WEEK_DAY_ABBREV,WEEK_DAY_NAME,YEAR,YEAR_DAY", NULL }, {"nv-pairs", ".SDATA.*", "HOST,MESSAGE,MSGID,PID,PROGRAM", NULL }, /* tests that the exclude patterns do not affect explicitly added * keys. The testcase function adds a "test.key" and then checks if * it is indeed present. Even if it would be excluded it still has * to be in the result set. */ {"rfc3164", "test.*", "DATE,FACILITY,HOST,MESSAGE,PID,PRIORITY,PROGRAM", NULL }, /* tests that excluding works even when the key would be in the * default set. */ {"nv-pairs", "MESSAGE", "HOST,MSGID,PID,PROGRAM", NULL } }; return cr_make_param_array(struct value_pairs_params, params, sizeof (params) / sizeof(params[0])); } ParameterizedTest(struct value_pairs_params *param, value_pairs, test) { testcase(param->scope, param->exclude, param->expected); } Test(value_pairs, test_transformers) { /* test the value-pair transformators */ GPtrArray *transformers = g_ptr_array_new(); g_ptr_array_add(transformers, value_pairs_new_transform_add_prefix("__")); g_ptr_array_add(transformers, value_pairs_new_transform_shift(2)); g_ptr_array_add(transformers, value_pairs_new_transform_replace_prefix("C_", "CC_")); transformers_testcase("everything", NULL, ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword," ".SDATA.meta.sequenceId,.SDATA.meta.sysUpTime,.SDATA.origin.ip," "AMPM,BSDTAG,CC_AMPM,CC_DATE,CC_DAY,CC_FULLDATE,CC_HOUR,CC_HOUR12," "CC_ISODATE,CC_ISOWEEK,CC_MIN,CC_MONTH,CC_MONTH_ABBREV,CC_MONTH_NAME," "CC_MONTH_WEEK,CC_MSEC,CC_SEC,CC_STAMP,CC_TZ,CC_TZOFFSET," "CC_UNIXTIME,CC_USEC,CC_WEEK,CC_WEEKDAY,CC_WEEK_DAY," "CC_WEEK_DAY_ABBREV,CC_WEEK_DAY_NAME,CC_YEAR,CC_YEAR_DAY," "DATE,DAY,DESTIP,DESTPORT,FACILITY,FACILITY_NUM,FULLDATE,HOST,HOSTID,HOUR," "HOUR12,ISODATE,ISOWEEK,LEVEL,LEVEL_NUM,LOGHOST,MESSAGE,MIN,MONTH," "MONTH_ABBREV,MONTH_NAME,MONTH_WEEK,MSEC,MSG,MSGHDR,MSGID," "PID,PRI,PRIORITY,PROGRAM,PROTO,P_AMPM,P_DATE,P_DAY,P_FULLDATE," "P_HOUR,P_HOUR12,P_ISODATE,P_ISOWEEK,P_MIN,P_MONTH,P_MONTH_ABBREV," "P_MONTH_NAME,P_MONTH_WEEK,P_MSEC,P_SEC,P_STAMP,P_TZ,P_TZOFFSET," "P_UNIXTIME,P_USEC,P_WEEK,P_WEEKDAY,P_WEEK_DAY,P_WEEK_DAY_ABBREV," "P_WEEK_DAY_NAME,P_YEAR,P_YEAR_DAY,RAWMSG_SIZE,R_AMPM,R_DATE,R_DAY,R_FULLDATE," "R_HOUR,R_HOUR12,R_ISODATE,R_ISOWEEK,R_MIN,R_MONTH,R_MONTH_ABBREV,R_MONTH_NAME," "R_MONTH_WEEK,R_MSEC,R_SEC,R_STAMP,R_TZ,R_TZOFFSET,R_UNIXTIME,R_USEC," "R_WEEK,R_WEEKDAY,R_WEEK_DAY,R_WEEK_DAY_ABBREV,R_WEEK_DAY_NAME,R_YEAR," "R_YEAR_DAY,SDATA,SEC,SEQNUM,SEVERITY,SEVERITY_NUM,SOURCEIP,STAMP,SYSUPTIME,S_AMPM,S_DATE," "S_DAY,S_FULLDATE,S_HOUR,S_HOUR12,S_ISODATE,S_ISOWEEK,S_MIN,S_MONTH,S_MONTH_ABBREV," "S_MONTH_NAME,S_MONTH_WEEK,S_MSEC,S_SEC,S_STAMP,S_TZ,S_TZOFFSET,S_UNIXTIME," "S_USEC,S_WEEK,S_WEEKDAY,S_WEEK_DAY,S_WEEK_DAY_ABBREV,S_WEEK_DAY_NAME," "S_YEAR,S_YEAR_DAY,TAG,TAGS,TZ,TZOFFSET,UNIXTIME,USEC,WEEK,WEEKDAY," "WEEK_DAY,WEEK_DAY_ABBREV,WEEK_DAY_NAME,YEAR,YEAR_DAY", transformers); g_ptr_array_free(transformers, TRUE); } Test(value_pairs, test_transformer_shift_levels) { /* test the value-pair transformators */ GPtrArray *transformers = g_ptr_array_new(); /* remove . from before .SDATA prefix */ g_ptr_array_add(transformers, value_pairs_new_transform_shift_levels(1)); /* add a new prefix, would become .foo.bar.baz.SDATA */ g_ptr_array_add(transformers, value_pairs_new_transform_add_prefix(".foo.bar.baz.")); /* remove just added prefix, should start with SDATA without leading dot */ g_ptr_array_add(transformers, value_pairs_new_transform_shift_levels(4)); transformers_testcase("sdata", ".SDATA.meta.*", ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.origin.ip,SDATA.meta.sequenceId,SDATA.meta.sysUpTime", transformers); g_ptr_array_free(transformers, TRUE); } Test(value_pairs, test_transformer_lower) { /* test the value-pair transformators */ GPtrArray *transformers = g_ptr_array_new(); g_ptr_array_add(transformers, value_pairs_new_transform_lower()); transformers_testcase("sdata", ".SDATA.meta.sequenceId", ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.meta.sysUpTime,.SDATA.origin.ip,.sdata.meta.sequenceid", transformers); g_ptr_array_free(transformers, TRUE); } Test(value_pairs, test_transformer_upper) { /* test the value-pair transformators */ GPtrArray *transformers = g_ptr_array_new(); g_ptr_array_add(transformers, value_pairs_new_transform_upper()); transformers_testcase("sdata", ".SDATA.meta.sequenceId", ".SDATA.EventData@18372.4.Data,.SDATA.Keywords@18372.4.Keyword,.SDATA.META.SEQUENCEID,.SDATA.meta.sysUpTime,.SDATA.origin.ip", transformers); g_ptr_array_free(transformers, TRUE); } static ValuePairs * _create_value_pairs_for_include_bytes_tc(void) { ValuePairs *vp = value_pairs_new(configuration); value_pairs_add_scope(vp, "nv-pairs"); LogTemplate *template; template = create_template(NULL, "$bytes"); value_pairs_add_pair(vp, "custom_bytes", template); log_template_unref(template); template = create_template(NULL, "$protobuf"); value_pairs_add_pair(vp, "custom_protobuf", template); log_template_unref(template); template = create_template("bytes", "$bytes"); value_pairs_add_pair(vp, "custom_explicit_bytes", template); log_template_unref(template); template = create_template("protobuf", "$protobuf"); value_pairs_add_pair(vp, "custom_explicit_protobuf", template); log_template_unref(template); return vp; } static gboolean asserts_for_no_include_bytes_v4(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { if (strcmp(name, "custom_bytes") == 0) { cr_assert_eq(type, LM_VT_NULL); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_protobuf") == 0) { cr_assert_eq(type, LM_VT_NULL); cr_assert_eq(value_len, 0); } else { cr_assert(FALSE, "%s not expected", name); } return FALSE; } static gboolean asserts_for_include_bytes_v4(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { if (strcmp(name, "bytes") == 0) { cr_assert_eq(type, LM_VT_BYTES); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\0\1\2\3", 4), 0); } else if (strcmp(name, "protobuf") == 0) { cr_assert_eq(type, LM_VT_PROTOBUF); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\4\5\6\7", 4), 0); } else if (strcmp(name, "custom_bytes") == 0) { cr_assert_eq(type, LM_VT_NULL); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_protobuf") == 0) { cr_assert_eq(type, LM_VT_NULL); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_explicit_bytes") == 0) { cr_assert_eq(type, LM_VT_BYTES); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\0\1\2\3", 4), 0); } else if (strcmp(name, "custom_explicit_protobuf") == 0) { cr_assert_eq(type, LM_VT_PROTOBUF); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\4\5\6\7", 4), 0); } else { cr_assert(FALSE, "%s not expected", name); } return FALSE; } Test(value_pairs, test_include_bytes_v4) { cfg_set_version_without_validation(configuration, VERSION_VALUE_4_0); ValuePairs *vp = _create_value_pairs_for_include_bytes_tc(); LogMessage *msg = log_msg_new_empty(); log_msg_set_value_by_name_with_type(msg, "bytes", "\0\1\2\3", 4, LM_VT_BYTES); log_msg_set_value_by_name_with_type(msg, "protobuf", "\4\5\6\7", 4, LM_VT_PROTOBUF); LogTemplateEvalOptions options = {&template_options, LTZ_LOCAL, 11, NULL, LM_VT_STRING}; value_pairs_foreach(vp, asserts_for_no_include_bytes_v4, msg, &options, NULL); value_pairs_set_include_bytes(vp, TRUE); value_pairs_foreach(vp, asserts_for_include_bytes_v4, msg, &options, NULL); log_msg_unref(msg); value_pairs_unref(vp); } static gboolean asserts_for_no_include_bytes_v3(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { if (strcmp(name, "custom_bytes") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_protobuf") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 0); } else { cr_assert(FALSE, "%s not expected", name); } return FALSE; } static gboolean asserts_for_include_bytes_v3(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { if (strcmp(name, "bytes") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\0\1\2\3", 4), 0); } else if (strcmp(name, "protobuf") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\4\5\6\7", 4), 0); } else if (strcmp(name, "custom_bytes") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_protobuf") == 0) { cr_assert_eq(type, LM_VT_STRING); cr_assert_eq(value_len, 0); } else if (strcmp(name, "custom_explicit_bytes") == 0) { cr_assert_eq(type, LM_VT_BYTES); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\0\1\2\3", 4), 0); } else if (strcmp(name, "custom_explicit_protobuf") == 0) { cr_assert_eq(type, LM_VT_PROTOBUF); cr_assert_eq(value_len, 4); cr_assert_eq(memcmp(value, "\4\5\6\7", 4), 0); } else { cr_assert(FALSE, "%s not expected", name); } return FALSE; } Test(value_pairs, test_include_bytes_v3) { cfg_set_version_without_validation(configuration, VERSION_VALUE_3_38); ValuePairs *vp = _create_value_pairs_for_include_bytes_tc(); LogMessage *msg = log_msg_new_empty(); log_msg_set_value_by_name_with_type(msg, "bytes", "\0\1\2\3", 4, LM_VT_BYTES); log_msg_set_value_by_name_with_type(msg, "protobuf", "\4\5\6\7", 4, LM_VT_PROTOBUF); LogTemplateEvalOptions options = {&template_options, LTZ_LOCAL, 11, NULL, LM_VT_STRING}; value_pairs_foreach(vp, asserts_for_no_include_bytes_v3, msg, &options, NULL); value_pairs_set_include_bytes(vp, TRUE); value_pairs_foreach(vp, asserts_for_include_bytes_v3, msg, &options, NULL); log_msg_unref(msg); value_pairs_unref(vp); } void setup(void) { app_startup(); setenv("TZ", "MET-1METDST", TRUE); tzset(); configuration = cfg_new_snippet(); cfg_load_module(configuration, "syslogformat"); msg_format_options_defaults(&parse_options); msg_format_options_init(&parse_options, configuration); parse_options.flags |= LP_SYSLOG_PROTOCOL; } void teardown(void) { cfg_free(configuration); app_shutdown(); } TestSuite(value_pairs, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/value-pairs/tests/test_value_pairs_walk.c000066400000000000000000000104761450431004300262560ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "value-pairs/value-pairs.h" #include "apphook.h" #include "plugin.h" #include "cfg.h" #include "logmsg/logmsg.h" LogTemplateOptions template_options; GlobalConfig *cfg; int root_data = 1; int root_test_data = 2; static gboolean test_vp_obj_start(const gchar *name, const gchar *prefix, gpointer *prefix_data, const gchar *prev, gpointer *prev_data, gpointer user_data) { static int times_called = 0; switch(times_called) { case 0: cr_expect_null(prefix, "First vp_obj_start but prefix is not NULL!"); break; case 1: cr_expect_str_eq(prefix, "root", "Second vp_obj_start but prefix is not 'root'!"); *prefix_data = &root_data; break; case 2: cr_expect_str_eq(prefix, "root.test", "Third vp_obj_start but prefix is not 'root.test'!"); cr_expect_str_eq(prev, "root", "Wrong previous prefix"); cr_expect_eq(*((gint *)(*prev_data)), root_data, "Wrong previous data"); *prefix_data = &root_test_data; break; default: cr_expect_fail("vp_obj_start called more times than number of path elements!"); } times_called++; return FALSE; } static gboolean test_vp_obj_stop(const gchar *name, const gchar *prefix, gpointer *prefix_data, const gchar *prev, gpointer *prev_data, gpointer user_data) { static int times_called = 0; switch(times_called) { case 0: cr_expect_str_eq(prefix, "root.test", "First vp_obj_stop but prefix is not 'root.test'!"); cr_expect_str_eq(prev, "root", "Wrong previous prefix"); cr_expect_eq(*((gint *)(*prev_data)), root_data, "Wrong previous data"); break; case 1: cr_expect_str_eq(prefix, "root", "Second vp_obj_stop but prefix is not 'root'!"); break; case 2: cr_expect_null(prefix, "Third vp_obj_stop but prefix is not NULL!"); break; default: cr_expect_fail("vp_obj_stop called more times than number of path elements!"); } times_called++; return FALSE; } static gboolean test_vp_value(const gchar *name, const gchar *prefix, LogMessageValueType type, const gchar *value, gsize value_len, gpointer *prefix_data, gpointer user_data) { cr_expect_str_eq(prefix, "root.test", "Wrong prefix"); cr_expect_str_eq(value, "value", "Wrong value"); cr_expect_eq(*((gint *)(*prefix_data)), root_test_data, "Wrong prefix data"); return FALSE; } Test(value_pairs_walker, prefix_dat) { ValuePairs *vp; LogMessage *msg; const char *value = "value"; log_template_options_init(&template_options, cfg); vp = value_pairs_new(cfg); value_pairs_add_glob_pattern(vp, "root.*", TRUE); msg = log_msg_new_empty(); log_msg_set_value_by_name(msg, "PROGRAM", "test", -1); log_msg_set_value_by_name(msg, "root.test.alma", value, strlen(value)); log_msg_set_value_by_name(msg, "root.test.korte", value, strlen(value)); LogTemplateEvalOptions options = {&template_options, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; value_pairs_walk(vp, test_vp_obj_start, test_vp_value, test_vp_obj_stop, msg, &options, 0, NULL); value_pairs_unref(vp); log_msg_unref(msg); }; void setup(void) { app_startup(); cfg = cfg_new_snippet(); } void teardown(void) { app_shutdown(); } TestSuite(value_pairs_walker, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/lib/value-pairs/transforms.c000066400000000000000000000152511450431004300227170ustar00rootroot00000000000000/* * Copyright (c) 2011-2013 Balabit * Copyright (c) 2011-2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transforms.h" #include "template/templates.h" #include "cfg-parser.h" #include "str-utils.h" #include "scratch-buffers.h" #include typedef void (*VPTransFunc)(ValuePairsTransform *t, GString *name); typedef void (*VPTransDestroyFunc)(ValuePairsTransform *t); struct _ValuePairsTransformSet { GPatternSpec *pattern; GList *transforms; }; struct _ValuePairsTransform { VPTransFunc transform; VPTransDestroyFunc destroy; }; typedef struct { ValuePairsTransform super; gint amount; } VPTransShift; typedef struct { ValuePairsTransform super; gchar *prefix; } VPTransAddPrefix; typedef struct { ValuePairsTransform super; gchar *old_prefix; gchar *new_prefix; gint new_prefix_len; gint old_prefix_len; } VPTransReplacePrefix; static void vp_trans_init(ValuePairsTransform *t, VPTransFunc trans, VPTransDestroyFunc dest) { if (!t) return; t->transform = trans; t->destroy = dest; } void value_pairs_transform_free(ValuePairsTransform *t) { if (t->destroy) t->destroy(t); g_free(t); } static inline void value_pairs_transform_apply(ValuePairsTransform *t, GString *key) { t->transform(t, key); } /* add_prefix() */ static void vp_trans_add_prefix(ValuePairsTransform *t, GString *key) { VPTransAddPrefix *self = (VPTransAddPrefix *)t; g_string_prepend(key, self->prefix); } static void vp_trans_add_prefix_destroy(ValuePairsTransform *t) { VPTransAddPrefix *self = (VPTransAddPrefix *)t; g_free(self->prefix); } ValuePairsTransform * value_pairs_new_transform_add_prefix (const gchar *prefix) { VPTransAddPrefix *vpt; vpt = g_new(VPTransAddPrefix, 1); vp_trans_init((ValuePairsTransform *)vpt, vp_trans_add_prefix, vp_trans_add_prefix_destroy); vpt->prefix = g_strdup(prefix); return (ValuePairsTransform *)vpt; } /* upper() */ static void vp_trans_upper(ValuePairsTransform *self, GString *key) { g_string_ascii_up(key); } ValuePairsTransform * value_pairs_new_transform_upper (void) { ValuePairsTransform *vpt = g_new0(ValuePairsTransform, 1); vp_trans_init(vpt, vp_trans_upper, NULL); return vpt; } /* lower() */ static void vp_trans_lower(ValuePairsTransform *self, GString *key) { g_string_ascii_down(key); } ValuePairsTransform * value_pairs_new_transform_lower (void) { ValuePairsTransform *vpt = g_new0(ValuePairsTransform, 1); vp_trans_init(vpt, vp_trans_lower, NULL); return vpt; } /* shift() */ static void vp_trans_shift(ValuePairsTransform *t, GString *key) { VPTransShift *self = (VPTransShift *)t; g_string_erase(key, 0, self->amount); } ValuePairsTransform * value_pairs_new_transform_shift (gint amount) { VPTransShift *vpt; vpt = g_new(VPTransShift, 1); vp_trans_init((ValuePairsTransform *)vpt, vp_trans_shift, NULL); vpt->amount = amount; return (ValuePairsTransform *)vpt; } /* shift-levels() */ static void vp_trans_shift_levels(ValuePairsTransform *t, GString *key) { VPTransShift *self = (VPTransShift *)t; const gchar *dot; gint levels_left = self->amount - 1; dot = strchr(key->str, '.'); while (dot && levels_left > 0) { dot = strchr(dot + 1, '.'); levels_left--; } if (dot) g_string_erase(key, 0, dot + 1 - key->str); } ValuePairsTransform * value_pairs_new_transform_shift_levels(gint amount) { VPTransShift *vpt; vpt = g_new(VPTransShift, 1); vp_trans_init((ValuePairsTransform *)vpt, vp_trans_shift_levels, NULL); vpt->amount = amount; return (ValuePairsTransform *)vpt; } /* replace-prefix() */ static void vp_trans_replace_prefix(ValuePairsTransform *t, GString *key) { VPTransReplacePrefix *self = (VPTransReplacePrefix *)t; if (strncmp(self->old_prefix, key->str, self->old_prefix_len) != 0) return; g_string_erase(key, 0, self->old_prefix_len); g_string_prepend_len(key, self->new_prefix, self->new_prefix_len); } static void vp_trans_replace_prefix_destroy(ValuePairsTransform *t) { VPTransReplacePrefix *self = (VPTransReplacePrefix *)t; g_free(self->old_prefix); g_free(self->new_prefix); } ValuePairsTransform * value_pairs_new_transform_replace_prefix(const gchar *prefix, const gchar *new_prefix) { VPTransReplacePrefix *vpt; vpt = g_new(VPTransReplacePrefix, 1); vp_trans_init((ValuePairsTransform *)vpt, vp_trans_replace_prefix, vp_trans_replace_prefix_destroy); vpt->old_prefix = g_strdup(prefix); vpt->old_prefix_len = strlen(prefix); vpt->new_prefix = g_strdup(new_prefix); vpt->new_prefix_len = strlen(vpt->new_prefix); return (ValuePairsTransform *)vpt; } /* * ValuePairsTransformSet */ ValuePairsTransformSet * value_pairs_transform_set_new(const gchar *glob) { ValuePairsTransformSet *vpts; vpts = g_new(ValuePairsTransformSet, 1); vpts->transforms = NULL; vpts->pattern = g_pattern_spec_new(glob); return vpts; } void value_pairs_transform_set_add_func(ValuePairsTransformSet *vpts, ValuePairsTransform *vpt) { vpts->transforms = g_list_append(vpts->transforms, vpt); } void value_pairs_transform_set_free(ValuePairsTransformSet *vpts) { GList *l; l = vpts->transforms; while (l) { value_pairs_transform_free((ValuePairsTransform *)l->data); l = g_list_delete_link(l, l); } g_pattern_spec_free(vpts->pattern); g_free(vpts); } void value_pairs_transform_set_apply(ValuePairsTransformSet *vpts, GString *key) { if (g_pattern_match_string(vpts->pattern, key->str)) { GList *l; l = vpts->transforms; while (l) { value_pairs_transform_apply((ValuePairsTransform *)l->data, key); l = l->next; } } } syslog-ng-syslog-ng-4.4.0/lib/value-pairs/transforms.h000066400000000000000000000040241450431004300227200ustar00rootroot00000000000000/* * Copyright (c) 2011-2013 Balabit * Copyright (c) 2011-2013 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VPTRANSFORM_INCLUDED #define VPTRANSFORM_INCLUDED 1 #include "syslog-ng.h" typedef struct _ValuePairsTransform ValuePairsTransform; typedef struct _ValuePairsTransformSet ValuePairsTransformSet; ValuePairsTransform *value_pairs_new_transform_add_prefix (const gchar *prefix); ValuePairsTransform *value_pairs_new_transform_lower (void); ValuePairsTransform *value_pairs_new_transform_upper (void); ValuePairsTransform *value_pairs_new_transform_shift (gint amount); ValuePairsTransform *value_pairs_new_transform_replace_prefix(const gchar *prefix, const gchar *new_prefix); ValuePairsTransform *value_pairs_new_transform_shift_levels(gint amount); void value_pairs_transform_free(ValuePairsTransform *t); ValuePairsTransformSet *value_pairs_transform_set_new(const gchar *glob); void value_pairs_transform_set_add_func(ValuePairsTransformSet *vpts, ValuePairsTransform *vpt); void value_pairs_transform_set_free(ValuePairsTransformSet *vpts); void value_pairs_transform_set_apply(ValuePairsTransformSet *vpts, GString *key); #endif syslog-ng-syslog-ng-4.4.0/lib/value-pairs/value-pairs.c000066400000000000000000000702651450431004300227570ustar00rootroot00000000000000/* * Copyright (c) 2011-2015 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "value-pairs/internals.h" #include "value-pairs/value-pairs.h" #include "logmsg/logmsg.h" #include "logmsg/type-hinting.h" #include "template/templates.h" #include "template/macros.h" #include "cfg-parser.h" #include "string-list.h" #include "scratch-buffers.h" #include "cfg.h" #include typedef struct { GPatternSpec *pattern; gboolean include; } VPPatternSpec; typedef struct { gchar *name; LogTemplate *template; } VPPairConf; typedef struct { /* we don't own any of the fields here, it is assumed that allocations are * managed by the caller */ GString *name; GString *value; LogMessageValueType type_hint; } VPResultValue; typedef struct { GTree *result_tree; /* array of VPResultValue instances */ GArray *values; } VPResults; typedef enum { VPS_NV_PAIRS = 0x01, VPS_DOT_NV_PAIRS = 0x02, VPS_RFC3164 = 0x04, VPS_RFC5424 = 0x08, VPS_ALL_MACROS = 0x10, VPS_SELECTED_MACROS = 0x20, VPS_SDATA = 0x40, VPS_EVERYTHING = 0x7f, } ValuePairScope; enum { VPT_MACRO, VPT_NVPAIR, }; typedef struct { const gchar *name; const gchar *alt_name; gint type; gint id; } ValuePairSpec; static ValuePairSpec rfc3164[] = { /* there's one macro named DATE that'll be expanded specially */ { "FACILITY" }, { "PRIORITY" }, { "HOST" }, { "PROGRAM" }, { "PID" }, { "MESSAGE" }, { "DATE" }, { 0 }, }; static ValuePairSpec rfc5424[] = { { "MSGID", }, { 0 }, }; static ValuePairSpec selected_macros[] = { { "TAGS" }, { "SOURCEIP" }, { "SEQNUM" }, { 0 }, }; static ValuePairSpec *all_macros; static CfgFlagHandler value_pair_scope[] = { { "nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS }, { "dot-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_DOT_NV_PAIRS}, { "all-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS | VPS_DOT_NV_PAIRS }, { "rfc3164", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 }, { "core", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 }, { "base", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 }, { "rfc5424", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 }, { "syslog-proto", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 }, { "all-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_ALL_MACROS }, { "selected-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_SELECTED_MACROS }, { "sdata", CFH_SET, offsetof(ValuePairs, scopes), VPS_SDATA }, { "everything", CFH_SET, offsetof(ValuePairs, scopes), VPS_EVERYTHING }, { NULL, 0, 0, 0}, }; static gboolean vp_pattern_spec_eval(VPPatternSpec *self, const gchar *input) { return g_pattern_match_string(self->pattern, input); } static void vp_pattern_spec_free(VPPatternSpec *self) { g_pattern_spec_free(self->pattern); g_free(self); } static VPPatternSpec * vp_pattern_spec_new(const gchar *pattern, gboolean include) { VPPatternSpec *self = g_new0(VPPatternSpec, 1); self->pattern = g_pattern_spec_new(pattern); self->include = include; return self; } static VPPairConf * vp_pair_conf_new(const gchar *key, LogTemplate *value) { VPPairConf *p = g_new(VPPairConf, 1); p->name = g_strdup(key); p->template = log_template_ref(value); return p; } static void vp_pair_conf_free(VPPairConf *vpc) { log_template_unref(vpc->template); g_free(vpc->name); g_free(vpc); } static void vp_result_value_init(VPResultValue *rv, GString *name, LogMessageValueType type_hint, GString *value) { rv->type_hint = type_hint; rv->name = name; rv->value = value; } static void vp_results_init(VPResults *results, GCompareFunc compare_func) { results->values = g_array_sized_new(FALSE, FALSE, sizeof(VPResultValue), 16); results->result_tree = g_tree_new_full((GCompareDataFunc) compare_func, NULL, NULL, NULL); } static void vp_results_deinit(VPResults *results) { g_tree_destroy(results->result_tree); g_array_free(results->values, TRUE); } static void vp_results_insert(VPResults *results, GString *name, LogMessageValueType type_hint, GString *value) { VPResultValue *rv; gint ndx = results->values->len; g_array_set_size(results->values, ndx + 1); rv = &g_array_index(results->values, VPResultValue, ndx); vp_result_value_init(rv, name, type_hint, value); /* GTree takes over ownership of name */ g_tree_insert(results->result_tree, name->str, GINT_TO_POINTER(ndx)); } static GString * vp_transform_apply (ValuePairs *vp, const gchar *key) { gint i; GString *result = scratch_buffers_alloc(); g_string_assign(result, key); if (vp->transforms->len == 0) return result; for (i = 0; i < vp->transforms->len; i++) { ValuePairsTransformSet *t = (ValuePairsTransformSet *) g_ptr_array_index(vp->transforms, i); value_pairs_transform_set_apply(t, result); } return result; } /* runs over the name-value pairs requested by the user (e.g. with value_pairs_add_pair) */ static void vp_pairs_foreach(gpointer data, gpointer user_data) { ValuePairs *vp = ((gpointer *)user_data)[0]; LogMessage *msg = ((gpointer *)user_data)[2]; LogTemplateEvalOptions *options = ((gpointer *)user_data)[3]; VPResults *results = ((gpointer *)user_data)[5]; GString *sb = scratch_buffers_alloc(); VPPairConf *vpc = (VPPairConf *)data; LogMessageValueType type; log_template_append_format_value_and_type((LogTemplate *)vpc->template, msg, options, sb, &type); if (vp->omit_empty_values && sb->len == 0) return; if (!vp->include_bytes && (type == LM_VT_BYTES || type == LM_VT_PROTOBUF)) return; if (vp->cast_to_strings && vpc->template->explicit_type_hint == LM_VT_NONE) type = LM_VT_STRING; vp_results_insert(results, vp_transform_apply(vp, vpc->name), type, sb); } /* runs over the LogMessage nv-pairs, and inserts them unless excluded */ static gboolean vp_msg_nvpairs_foreach(NVHandle handle, const gchar *name, const gchar *value, gssize value_len, LogMessageValueType type, gpointer user_data) { ValuePairs *vp = ((gpointer *)user_data)[0]; VPResults *results = ((gpointer *)user_data)[5]; guint j; gboolean inc; GString *sb; if (vp->omit_empty_values && value_len == 0) return FALSE; if ((type == LM_VT_BYTES || type == LM_VT_PROTOBUF) && !vp->include_bytes) return FALSE; inc = (name[0] == '.' && (vp->scopes & VPS_DOT_NV_PAIRS)) || (name[0] != '.' && (vp->scopes & VPS_NV_PAIRS)) || (log_msg_is_handle_sdata(handle) && (vp->scopes & (VPS_SDATA + VPS_RFC5424))); for (j = 0; j < vp->patterns->len; j++) { VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, j); if (vp_pattern_spec_eval(vps, name)) inc = vps->include; } if (!inc) return FALSE; sb = scratch_buffers_alloc(); g_string_append_len(sb, value, value_len); if (vp->cast_to_strings) type = LM_VT_STRING; vp_results_insert(results, vp_transform_apply(vp, name), type, sb); return FALSE; } static gboolean vp_find_in_set(ValuePairs *vp, const gchar *name, gboolean exclude) { guint j; gboolean included = exclude; for (j = 0; j < vp->patterns->len; j++) { VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, j); if (vp_pattern_spec_eval(vps, name)) included = vps->include; } return included; } static void vp_merge_other_set(ValuePairs *vp, ValuePairSpec *set, gboolean exclude) { gint i; for (i = 0; set[i].name; i++) { if (!vp_find_in_set(vp, set[i].name, exclude)) continue; g_ptr_array_add(vp->builtins, &set[i]); } } /* runs over the all macros and merges the selected ones by the pattern into the value-pair set */ static void vp_merge_macros(ValuePairs *vp) { vp_merge_other_set(vp, all_macros, FALSE); } /* runs over a set of ValuePairSpec structs and merges them into the value-pair set */ static void vp_merge_set(ValuePairs *vp, ValuePairSpec *set) { vp_merge_other_set(vp, set, TRUE); } static void vp_update_builtin_list_of_values(ValuePairs *vp) { g_ptr_array_set_size(vp->builtins, 0); if (vp->patterns->len > 0) vp_merge_macros(vp); if (vp->scopes & (VPS_RFC3164 + VPS_RFC5424 + VPS_SELECTED_MACROS)) vp_merge_set(vp, rfc3164); if (vp->scopes & VPS_RFC5424) vp_merge_set(vp, rfc5424); if (vp->scopes & VPS_SELECTED_MACROS) vp_merge_set(vp, selected_macros); if (vp->scopes & VPS_ALL_MACROS) vp_merge_set(vp, all_macros); } static void vp_merge_builtins(ValuePairs *vp, VPResults *results, LogMessage *msg, LogTemplateEvalOptions *options) { gint i; GString *sb; for (i = 0; i < vp->builtins->len; i++) { ValuePairSpec *spec = (ValuePairSpec *) g_ptr_array_index(vp->builtins, i); LogMessageValueType type; sb = scratch_buffers_alloc(); switch (spec->type) { case VPT_MACRO: log_macro_expand(spec->id, FALSE, options, msg, sb, &type); break; case VPT_NVPAIR: { const gchar *nv; gssize len; nv = log_msg_get_value_with_type(msg, (NVHandle) spec->id, &len, &type); g_string_append_len(sb, nv, len); break; } default: g_assert_not_reached(); } if (sb->len == 0) { continue; } if (vp->cast_to_strings) type = LM_VT_STRING; vp_results_insert(results, vp_transform_apply(vp, spec->name), type, sb); } } static gboolean vp_foreach_helper(const gchar *name, gpointer ndx_as_pointer, gpointer data) { VPResults *results = ((gpointer *)data)[0]; gint ndx = GPOINTER_TO_INT(ndx_as_pointer); VPResultValue *rv = &g_array_index(results->values, VPResultValue, ndx); VPForeachFunc func = ((gpointer *)data)[1]; gpointer user_data = ((gpointer *)data)[2]; gboolean *r = ((gpointer *)data)[3]; gboolean success = !func(name, rv->type_hint, rv->value->str, rv->value->len, user_data); *r &= success; if (!success) { msg_trace("value_pairs_foreach: callback indicates failure", evt_tag_str("name", name), evt_tag_mem("value", rv->value->str, rv->value->len), evt_tag_int("type", rv->type_hint)); } return !*r; } gboolean value_pairs_foreach_sorted (ValuePairs *vp, VPForeachFunc func, GCompareFunc compare_func, LogMessage *msg, LogTemplateEvalOptions *options, gpointer user_data) { gpointer args[] = { vp, func, msg, options, user_data, NULL}; gboolean result = TRUE; VPResults results; gpointer helper_args[] = { &results, func, user_data, &result }; ScratchBuffersMarker mark; scratch_buffers_mark(&mark); vp_results_init(&results, compare_func); args[5] = &results; /* * Build up the base set */ if (vp->scopes & (VPS_NV_PAIRS + VPS_DOT_NV_PAIRS + VPS_SDATA + VPS_RFC5424) || vp->patterns->len > 0) log_msg_values_foreach(msg, vp_msg_nvpairs_foreach, args); vp_merge_builtins(vp, &results, msg, options); /* Merge the explicit key-value pairs too */ g_ptr_array_foreach(vp->vpairs, (GFunc)vp_pairs_foreach, args); /* Aaand we run it through the callback! */ g_tree_foreach(results.result_tree, (GTraverseFunc)vp_foreach_helper, helper_args); vp_results_deinit(&results); scratch_buffers_reclaim_marked(mark); return result; } gboolean value_pairs_foreach(ValuePairs *vp, VPForeachFunc func, LogMessage *msg, LogTemplateEvalOptions *options, gpointer user_data) { return value_pairs_foreach_sorted(vp, func, (GCompareFunc) strcmp, msg, options, user_data); } /******************************************************************************* * vp_stack (represented by vp_stack_t) * * A not very generic stack implementation used by vp_walker. *******************************************************************************/ #define VP_STACK_INITIAL_SIZE 16 typedef struct { GPtrArray *elems; } vp_stack_t; static void vp_stack_init(vp_stack_t *stack) { stack->elems = g_ptr_array_sized_new(VP_STACK_INITIAL_SIZE); } static void vp_stack_destroy(vp_stack_t *stack) { g_ptr_array_free(stack->elems, TRUE); } static void vp_stack_push(vp_stack_t *stack, gpointer data) { g_ptr_array_add(stack->elems, data); } static gpointer vp_stack_peek(vp_stack_t *stack) { if (stack->elems->len == 0) return NULL; return g_ptr_array_index(stack->elems, stack->elems->len - 1); } static gpointer vp_stack_pop(vp_stack_t *stack) { gpointer data = NULL; data = vp_stack_peek(stack); if (data) g_ptr_array_remove_index(stack->elems, stack->elems->len - 1); return data; } static guint vp_stack_height(vp_stack_t *stack) { return stack->elems->len; } /******************************************************************************* * vp_walker (represented by vp_walk_state_t), * * The stuff that translates name-value pairs to a tree with SAX like * callbacks. (start/value/end) *******************************************************************************/ typedef struct { gchar *key; gchar *prefix; gint prefix_len; gpointer data; } vp_walk_stack_data_t; typedef struct { VPWalkCallbackFunc obj_start; VPWalkCallbackFunc obj_end; VPWalkValueCallbackFunc process_value; gpointer user_data; vp_stack_t stack; gchar key_delimiter; /* tokenizer state */ GPtrArray *tokens; } vp_walk_state_t; static vp_walk_stack_data_t * vp_walker_stack_push (vp_stack_t *stack, gchar *key, gchar *prefix) { vp_walk_stack_data_t *nt = g_new(vp_walk_stack_data_t, 1); nt->key = key; nt->prefix = prefix; nt->prefix_len = strlen(nt->prefix); nt->data = NULL; vp_stack_push(stack, nt); return nt; } static vp_walk_stack_data_t * vp_walker_stack_peek(vp_stack_t *stack) { return (vp_walk_stack_data_t *) vp_stack_peek(stack); } static vp_walk_stack_data_t * vp_walker_stack_pop(vp_stack_t *stack) { return (vp_walk_stack_data_t *) vp_stack_pop(stack); } static void vp_walker_free_stack_data(vp_walk_stack_data_t *t) { g_free(t->key); g_free(t->prefix); g_free(t); } static void vp_walker_stack_unwind_containers_until(vp_walk_state_t *state, const gchar *name) { vp_walk_stack_data_t *t; while ((t = vp_walker_stack_pop(&state->stack)) != NULL) { vp_walk_stack_data_t *p; if (name && strncmp(name, t->prefix, t->prefix_len) == 0) { /* This one matched, put it back, PUT IT BACK! */ vp_stack_push(&state->stack, t); break; } p = vp_walker_stack_peek(&state->stack); if (p) state->obj_end(t->key, t->prefix, &t->data, p->prefix, &p->data, state->user_data); else state->obj_end(t->key, t->prefix, &t->data, NULL, NULL, state->user_data); vp_walker_free_stack_data(t); } } static void vp_walker_stack_unwind_all_containers(vp_walk_state_t *state) { vp_walker_stack_unwind_containers_until(state, NULL); } static const gchar * vp_walker_skip_sdata_enterprise_id(const gchar *name) { /* parse .SDATA.foo@1234.56.678 format, starting with the '@' character. Assume that any numbers + dots form part of the "foo@1234.56.678" key, even if they contain dots */ do { /* skip @ or . */ ++name; name += strspn(name, "0123456789"); } while (*name == '.' && isdigit(*(name + 1))); return name; } static void _extract_token(vp_walk_state_t *state, const gchar *token_start, gsize token_len) { g_ptr_array_add(state->tokens, g_strndup(token_start, token_len)); } static void _start_new_token(vp_walk_state_t *state, const gchar **token_start, const gchar **token_end) { ++(*token_end); *token_start = *token_end; } static void _extract_and_find_next_token(vp_walk_state_t *state, const gchar **token_start_p, const gchar **token_end_p) { const gchar *token_start = *token_start_p; const gchar *token_end = *token_end_p; switch (*token_end) { case '@': token_end = vp_walker_skip_sdata_enterprise_id(token_end); break; case '.': if (token_start != token_end) { _extract_token(state, token_start, token_end - token_start); _start_new_token(state, &token_start, &token_end); break; } /* fall through, zero length token is not considered a separate token */ default: token_end++; token_end += strcspn(token_end, "@."); break; } *token_start_p = token_start; *token_end_p = token_end; } static void _extract_and_find_next_token_with_custom_delimiter(vp_walk_state_t *state, const gchar **token_start_p, const gchar **token_end_p) { const gchar *token_start = *token_start_p; const gchar *token_end = *token_end_p; if (*token_end == state->key_delimiter && token_start != token_end) { _extract_token(state, token_start, token_end - token_start); _start_new_token(state, &token_start, &token_end); } else { const gchar *sep = strchr(token_end + 1, state->key_delimiter); /* position to end of the string if sep is unset */ if (sep) token_end = sep; else token_end += strlen(token_end); } *token_start_p = token_start; *token_end_p = token_end; } static void _extract_tokens_with_default_delimiter(vp_walk_state_t *state, const gchar *name) { const gchar *token_start = name; const gchar *token_end = name; while (*token_end) _extract_and_find_next_token(state, &token_start, &token_end); /* extract last token at the end */ if (token_start != token_end) _extract_token(state, token_start, token_end - token_start); } static void _extract_tokens_with_custom_delimiter(vp_walk_state_t *state, const gchar *name) { const gchar *token_start = name; const gchar *token_end = name; while (*token_end) _extract_and_find_next_token_with_custom_delimiter(state, &token_start, &token_end); /* extract last token at the end */ if (token_start != token_end) _extract_token(state, token_start, token_end - token_start); } static GPtrArray * vp_walker_split_name_to_tokens(vp_walk_state_t *state, const gchar *name) { state->tokens = g_ptr_array_sized_new(VP_STACK_INITIAL_SIZE); if (state->key_delimiter == '.') _extract_tokens_with_default_delimiter(state, name); else _extract_tokens_with_custom_delimiter(state, name); if (state->tokens->len == 0) { g_ptr_array_free(state->tokens, TRUE); return NULL; } return state->tokens; } static gchar * vp_walker_name_combine_prefix(vp_walk_state_t *state, GPtrArray *tokens, gint until) { GString *s = scratch_buffers_alloc(); gchar *str; gint i; for (i = 0; i < until; i++) { g_string_append(s, g_ptr_array_index(tokens, i)); g_string_append_c(s, state->key_delimiter); } g_string_append(s, g_ptr_array_index(tokens, until)); str = g_strdup(s->str); return str; } static gchar * vp_walker_start_containers_for_name(vp_walk_state_t *state, const gchar *name) { GPtrArray *tokens; gchar *key = NULL; guint i, start; tokens = vp_walker_split_name_to_tokens(state, name); start = vp_stack_height(&state->stack); for (i = start; i < tokens->len - 1; i++) { vp_walk_stack_data_t *p, *nt; p = vp_walker_stack_peek(&state->stack); nt = vp_walker_stack_push(&state->stack, g_strdup(g_ptr_array_index(tokens, i)), vp_walker_name_combine_prefix(state, tokens, i)); if (p) state->obj_start(nt->key, nt->prefix, &nt->data, p->prefix, &p->data, state->user_data); else state->obj_start(nt->key, nt->prefix, &nt->data, NULL, NULL, state->user_data); } /* The last token is the key (well, second to last, last being NULL), so treat that normally. */ key = g_ptr_array_index(tokens, tokens->len - 1); g_ptr_array_index(tokens, tokens->len - 1) = NULL; g_ptr_array_foreach(tokens, (GFunc)g_free, NULL); g_ptr_array_free(tokens, TRUE); return key; } static gboolean value_pairs_walker(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { vp_walk_state_t *state = (vp_walk_state_t *)user_data; vp_walk_stack_data_t *data; gchar *key; gboolean result; vp_walker_stack_unwind_containers_until(state, name); key = vp_walker_start_containers_for_name(state, name); data = vp_walker_stack_peek(&state->stack); if (data != NULL) result = state->process_value(key, data->prefix, type, value, value_len, &data->data, state->user_data); else result = state->process_value(key, NULL, type, value, value_len, NULL, state->user_data); g_free(key); return result; } static gint vp_walk_cmp(const gchar *s1, const gchar *s2) { return strcmp(s2, s1); } /******************************************************************************* * Public API *******************************************************************************/ gboolean value_pairs_walk(ValuePairs *vp, VPWalkCallbackFunc obj_start_func, VPWalkValueCallbackFunc process_value_func, VPWalkCallbackFunc obj_end_func, LogMessage *msg, LogTemplateEvalOptions *options, gchar key_delimiter, gpointer user_data) { vp_walk_state_t state; gboolean result; state.user_data = user_data; state.obj_start = obj_start_func; state.obj_end = obj_end_func; state.process_value = process_value_func; state.key_delimiter = key_delimiter ? : '.'; vp_stack_init(&state.stack); state.obj_start(NULL, NULL, NULL, NULL, NULL, user_data); result = value_pairs_foreach_sorted(vp, value_pairs_walker, (GCompareFunc)vp_walk_cmp, msg, options, &state); vp_walker_stack_unwind_all_containers(&state); state.obj_end(NULL, NULL, NULL, NULL, NULL, user_data); vp_stack_destroy(&state.stack); return result; } gboolean value_pairs_add_scope(ValuePairs *vp, const gchar *scope) { gboolean result; if (strcmp(scope, "none") != 0) { result = cfg_process_flag(value_pair_scope, vp, scope); vp_update_builtin_list_of_values(vp); } else { result = TRUE; vp->scopes = 0; vp_update_builtin_list_of_values(vp); } return result; } void value_pairs_add_glob_pattern(ValuePairs *vp, const gchar *pattern, gboolean include) { g_ptr_array_add(vp->patterns, vp_pattern_spec_new(pattern, include)); vp_update_builtin_list_of_values(vp); } void value_pairs_add_glob_patterns(ValuePairs *vp, GList *patterns, gboolean include) { GList *l = patterns; while (l) { value_pairs_add_glob_pattern(vp, (gchar *)l->data, include); l = g_list_next (l); } string_list_free(patterns); vp_update_builtin_list_of_values(vp); } void value_pairs_add_pair(ValuePairs *vp, const gchar *key, LogTemplate *value) { g_ptr_array_add(vp->vpairs, vp_pair_conf_new(key, value)); vp_update_builtin_list_of_values(vp); } void value_pairs_add_transforms(ValuePairs *vp, ValuePairsTransformSet *vpts) { g_ptr_array_add(vp->transforms, vpts); vp_update_builtin_list_of_values(vp); } void value_pairs_set_cast_to_strings(ValuePairs *vp, gboolean enable) { vp->cast_to_strings = enable; vp->explicit_cast_to_strings = TRUE; } void value_pairs_set_auto_cast(ValuePairs *vp) { /* cast is based on @version, in 3.x mode we use strings, in 4.x we use * types but we won't get the warning */ vp->explicit_cast_to_strings = TRUE; } gboolean value_pairs_is_cast_to_strings_explicit(ValuePairs *vp) { return vp->explicit_cast_to_strings; } void value_pairs_set_include_bytes(ValuePairs *vp, gboolean enable) { vp->include_bytes = enable; } ValuePairs * value_pairs_new(GlobalConfig *cfg) { ValuePairs *vp; vp = g_new0(ValuePairs, 1); g_atomic_counter_set(&vp->ref_cnt, 1); vp->builtins = g_ptr_array_new(); vp->vpairs = g_ptr_array_new(); vp->patterns = g_ptr_array_new(); vp->transforms = g_ptr_array_new(); vp->cfg = cfg; if (cfg_is_config_version_older(cfg, VERSION_VALUE_4_0)) { /* we don't have an upgrade warning here, as it could only be a very * generic message, not helping our users too much. I've added this * kind of warning to affected modules instead, like $(format-json) * and mongo-db() */ vp->cast_to_strings = TRUE; } return vp; } ValuePairs * value_pairs_new_default(GlobalConfig *cfg) { ValuePairs *vp = value_pairs_new(cfg); value_pairs_add_scope(vp, "selected-macros"); value_pairs_add_scope(vp, "nv-pairs"); value_pairs_add_scope(vp, "sdata"); return vp; } static void value_pairs_free (ValuePairs *vp) { guint i; for (i = 0; i < vp->vpairs->len; i++) vp_pair_conf_free(g_ptr_array_index(vp->vpairs, i)); g_ptr_array_free(vp->vpairs, TRUE); for (i = 0; i < vp->patterns->len; i++) { VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, i); vp_pattern_spec_free(vps); } g_ptr_array_free(vp->patterns, TRUE); for (i = 0; i < vp->transforms->len; i++) { ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) g_ptr_array_index(vp->transforms, i); value_pairs_transform_set_free(vpts); } g_ptr_array_free(vp->transforms, TRUE); g_ptr_array_free(vp->builtins, TRUE); g_free(vp); } ValuePairs * value_pairs_ref(ValuePairs *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } void value_pairs_unref(ValuePairs *self) { if (self) { g_assert(g_atomic_counter_get(&self->ref_cnt) > 0); if (g_atomic_counter_dec_and_test(&self->ref_cnt)) value_pairs_free(self); } } static void value_pairs_init_set(ValuePairSpec *set) { gint i; for (i = 0; set[i].name; i++) { guint id; const gchar *name; name = set[i].alt_name ? set[i].alt_name : set[i].name; if ((id = log_macro_lookup(name, strlen(name)))) { set[i].type = VPT_MACRO; set[i].id = id; } else { set[i].type = VPT_NVPAIR; set[i].id = log_msg_get_value_handle(name); } } } void value_pairs_global_init(void) { gint i = 0; GArray *a; value_pairs_init_set(rfc3164); value_pairs_init_set(rfc5424); value_pairs_init_set(selected_macros); a = g_array_new(TRUE, TRUE, sizeof(ValuePairSpec)); for (i = 0; macros[i].name; i++) { ValuePairSpec pair; pair.name = macros[i].name; pair.type = VPT_MACRO; pair.id = macros[i].id; g_array_append_val(a, pair); } all_macros = (ValuePairSpec *) g_array_free(a, FALSE); } void value_pairs_global_deinit(void) { g_free(all_macros); } syslog-ng-syslog-ng-4.4.0/lib/value-pairs/value-pairs.h000066400000000000000000000073321450431004300227570ustar00rootroot00000000000000/* * Copyright (c) 2011-2014 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VALUE_PAIRS_H_INCLUDED #define VALUE_PAIRS_H_INCLUDED 1 #include "syslog-ng.h" #include "logmsg/nvtable.h" #include "logmsg/type-hinting.h" #include "value-pairs/transforms.h" #include "template/templates.h" #include "atomic.h" typedef struct _ValuePairs ValuePairs; typedef gboolean (*VPForeachFunc) (const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data); typedef gboolean (*VPWalkValueCallbackFunc) (const gchar *name, const gchar *prefix, LogMessageValueType type, const gchar *value, gsize value_len, gpointer *prefix_data, gpointer user_data); typedef gboolean (*VPWalkCallbackFunc)(const gchar *name, const gchar *prefix, gpointer *prefix_data, const gchar *prev, gpointer *prev_data, gpointer user_data); gboolean value_pairs_add_scope(ValuePairs *vp, const gchar *scope); void value_pairs_add_glob_pattern(ValuePairs *vp, const gchar *pattern, gboolean include); void value_pairs_add_glob_patterns(ValuePairs *vp, GList *patterns, gboolean include); void value_pairs_add_pair(ValuePairs *vp, const gchar *key, LogTemplate *value); void value_pairs_add_transforms(ValuePairs *vp, ValuePairsTransformSet *vpts); void value_pairs_set_cast_to_strings(ValuePairs *vp, gboolean enable); void value_pairs_set_auto_cast(ValuePairs *vp); gboolean value_pairs_is_cast_to_strings_explicit(ValuePairs *vp); void value_pairs_set_include_bytes(ValuePairs *vp, gboolean enable); gboolean value_pairs_foreach_sorted(ValuePairs *vp, VPForeachFunc func, GCompareFunc compare_func, LogMessage *msg, LogTemplateEvalOptions *options, gpointer user_data); gboolean value_pairs_foreach(ValuePairs *vp, VPForeachFunc func, LogMessage *msg, LogTemplateEvalOptions *options, gpointer user_data); gboolean value_pairs_walk(ValuePairs *vp, VPWalkCallbackFunc obj_start_func, VPWalkValueCallbackFunc process_value_func, VPWalkCallbackFunc obj_end_func, LogMessage *msg, LogTemplateEvalOptions *options, gchar key_delimiter, gpointer user_data); ValuePairs *value_pairs_new(GlobalConfig *cfg); ValuePairs *value_pairs_new_default(GlobalConfig *cfg); ValuePairs *value_pairs_ref(ValuePairs *self); void value_pairs_unref(ValuePairs *self); void value_pairs_global_init(void); void value_pairs_global_deinit(void); #endif syslog-ng-syslog-ng-4.4.0/lib/versioning.h000066400000000000000000000213041450431004300204550ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef __VERSIONING_H__ #define __VERSIONING_H__ /* The aim of this header file is to make it easy to track version * identification in code when porting code from the PE tree to the OSE tree * or vice versa. Error and warning messages should always use these macros * instead of inlining a concrete version number. Runtime checks should * always use the get_version_value() function to convert OSE version codes * to PE ones. * **************************************************************************** * The code _should_ always use OSE version numbering, otherwise it'd break * * and confuse the user when code gets ported between trees. * **************************************************************************** * * Versions in error messages * ========================== * * Whenever using an error message that needs to state a version number, it * should use one of the VERSION_X_Y macros, X_Y identifying the OSE version * number where the incompatible change was applied. * * Example: * * msg_warning("WARNING: foo got changed to bar in " VERSION_3_4"); * * Incompatible changes in non-OSE products * ======================================== * * If you introduce an incompatible change in a private tree (but don't do * that), you should explicitly define a macro that identifies your version, * e.g. if you have a product named foo, which is based on syslog-ng 3.3 * and you decide to change the interpretation of a config syntax in your * 1.0 release, you should create a macro: * * VERSION_FOO_1_0 "foo 1.0" * * This would be changed once the code gets integrated into syslog-ng, to * the "integrated-to" release. That way, users that always used OSE gets * the version number properly. * * Rebasing to a tree that already has your incompatible change * ============================================================ * * Assuming your change makes it to the OSE tree, the FOO specific version * references will be changed to OSE version macros, which could be a * problem for you when rebase your product, since your rebased product will * claim that the incompatible change happened _after_ it really happened. * The best solution is not to introduce incompatible changes or do that in * the OSE tree first. If you have to something like this, make sure that * you take care about these at rebase time. * * Version number barrier * ====================== * * For now there's an explicit barrier in version numbering between PE and * OSE, which is "4.0"; everything below "4.0" is an OSE version number, * everything ahead is a PE one. This will change once there's sufficient * gap between the two (e.g. PE 4.0 is long forgotten), in that case * OSE can also use version 4 and later. * * If there's another similar products built on syslog-ng (e.g. someone * other than BB creates such a product, the same scheme can be used by them * too). */ /* version references for major syslog-ng OSE versions. All error messages * should reference the syslog-ng version number through these macros, in order * to make it relatively simple to explain PE/OSE version numbers to users. */ #define PRODUCT_DOCUMENTATION "https://www.syslog-ng.com/technical-documents/list/syslog-ng-open-source-edition" #define PRODUCT_CONTACT "\n\tGitHub Project: https://github.com/syslog-ng/syslog-ng\n\tChat with the Developers: https://gitter.im/syslog-ng/syslog-ng\n\tMailing List: https://lists.balabit.hu/mailman/listinfo/syslog-ng" #define VERSION_3_0 "syslog-ng 3.0" #define VERSION_3_1 "syslog-ng 3.1" #define VERSION_3_2 "syslog-ng 3.2" #define VERSION_3_3 "syslog-ng 3.3" #define VERSION_3_4 "syslog-ng 3.4" #define VERSION_3_5 "syslog-ng 3.5" #define VERSION_3_6 "syslog-ng 3.6" #define VERSION_3_7 "syslog-ng 3.7" #define VERSION_3_8 "syslog-ng 3.8" #define VERSION_3_9 "syslog-ng 3.9" #define VERSION_3_10 "syslog-ng 3.10" #define VERSION_3_11 "syslog-ng 3.11" #define VERSION_3_12 "syslog-ng 3.12" #define VERSION_3_13 "syslog-ng 3.13" #define VERSION_3_14 "syslog-ng 3.14" #define VERSION_3_15 "syslog-ng 3.15" #define VERSION_3_16 "syslog-ng 3.16" #define VERSION_3_17 "syslog-ng 3.17" #define VERSION_3_18 "syslog-ng 3.18" #define VERSION_3_19 "syslog-ng 3.19" #define VERSION_3_20 "syslog-ng 3.20" #define VERSION_3_21 "syslog-ng 3.21" #define VERSION_3_22 "syslog-ng 3.22" #define VERSION_3_23 "syslog-ng 3.23" #define VERSION_3_24 "syslog-ng 3.24" #define VERSION_3_25 "syslog-ng 3.25" #define VERSION_3_26 "syslog-ng 3.26" #define VERSION_3_27 "syslog-ng 3.27" #define VERSION_3_28 "syslog-ng 3.28" #define VERSION_3_29 "syslog-ng 3.29" #define VERSION_3_30 "syslog-ng 3.30" #define VERSION_3_31 "syslog-ng 3.31" #define VERSION_3_32 "syslog-ng 3.32" #define VERSION_3_33 "syslog-ng 3.33" #define VERSION_3_34 "syslog-ng 3.34" #define VERSION_3_35 "syslog-ng 3.35" #define VERSION_3_36 "syslog-ng 3.36" #define VERSION_3_37 "syslog-ng 3.37" #define VERSION_3_38 "syslog-ng 3.38" #define VERSION_4_0 "syslog-ng 4.0" #define VERSION_4_1 "syslog-ng 4.1" #define VERSION_4_2 "syslog-ng 4.2" #define VERSION_4_3 "syslog-ng 4.3" #define VERSION_4_4 "syslog-ng 4.4" /* VERSION_VALUE_* references versions as integers to be compared against stuff like cfg->user_version */ /* VERSION_STR_* references versions as strings to be shown to the user */ #define VERSION_VALUE_3_0 0x0300 #define VERSION_VALUE_3_1 0x0301 #define VERSION_VALUE_3_2 0x0302 #define VERSION_VALUE_3_3 0x0303 #define VERSION_VALUE_3_4 0x0304 #define VERSION_VALUE_3_5 0x0305 #define VERSION_VALUE_3_6 0x0306 #define VERSION_VALUE_3_7 0x0307 #define VERSION_VALUE_3_8 0x0308 #define VERSION_VALUE_3_9 0x0309 #define VERSION_VALUE_3_10 0x030a #define VERSION_VALUE_3_11 0x030b #define VERSION_VALUE_3_12 0x030c #define VERSION_VALUE_3_13 0x030d #define VERSION_VALUE_3_14 0x030e #define VERSION_VALUE_3_15 0x030f #define VERSION_VALUE_3_16 0x0310 #define VERSION_VALUE_3_17 0x0311 #define VERSION_VALUE_3_18 0x0312 #define VERSION_VALUE_3_19 0x0313 #define VERSION_VALUE_3_20 0x0314 #define VERSION_VALUE_3_21 0x0315 #define VERSION_VALUE_3_22 0x0316 #define VERSION_VALUE_3_23 0x0317 #define VERSION_VALUE_3_24 0x0318 #define VERSION_VALUE_3_25 0x0319 #define VERSION_VALUE_3_26 0x031a #define VERSION_VALUE_3_27 0x031b #define VERSION_VALUE_3_28 0x031c #define VERSION_VALUE_3_29 0x031d #define VERSION_VALUE_3_30 0x031e #define VERSION_VALUE_3_31 0x031f #define VERSION_VALUE_3_32 0x0320 #define VERSION_VALUE_3_33 0x0321 #define VERSION_VALUE_3_34 0x0322 #define VERSION_VALUE_3_35 0x0323 #define VERSION_VALUE_3_36 0x0324 #define VERSION_VALUE_3_37 0x0325 #define VERSION_VALUE_3_38 0x0326 #define VERSION_VALUE_4_0 0x0400 #define VERSION_VALUE_4_1 0x0401 #define VERSION_VALUE_4_2 0x0402 #define VERSION_VALUE_4_3 0x0403 #define VERSION_VALUE_4_4 0x0404 /* config version code, in the same format as GlobalConfig->version */ #define VERSION_VALUE_CURRENT VERSION_VALUE_4_4 #define VERSION_STR_CURRENT "4.4" #define VERSION_PRODUCT_CURRENT VERSION_4_4 /* this value points to the last syslog-ng version where we changed the * meaning of any setting in the configuration file. Basically, it is the * highest value passed to any cfg_is_config_version_older() call. */ #define VERSION_VALUE_LAST_SEMANTIC_CHANGE VERSION_VALUE_4_2 #define VERSION_STR_LAST_SEMANTIC_CHANGE "4.2" #define version_convert_from_user(v) (v) /* version based feature flips */ #define VERSION_VALUE_NEXT_MAJOR VERSION_VALUE_4_0 /* we are already past 4.0 which introduced FEATURE_TYPING_MIN_VERSION, so * set min_version to an extremal value. We should remove this macro if all * derived works introduce typing support. Until that point we keep it * here, so the same codebase can execute with typing disabled. */ #define FEATURE_TYPING_MIN_VERSION 0 #define FEATURE_TYPING_VERSION "syslog-ng 4.0" #include "pe-versioning.h" #endif syslog-ng-syslog-ng-4.4.0/lib/window-size-counter.c000066400000000000000000000052651450431004300222310ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "window-size-counter.h" #define COUNTER_MASK (((gsize)1<<(8*sizeof(gsize)-1)) - 1) static const gsize COUNTER_MAX = COUNTER_MASK; static const gsize SUSPEND_MASK = G_MAXSIZE ^ COUNTER_MASK; static const gsize RESUME_MASK = G_MAXSIZE >> 1; static gboolean _is_suspended(gsize v) { return (v == 0) || ((v & SUSPEND_MASK) == SUSPEND_MASK); } gsize window_size_counter_get_max(void) { return COUNTER_MAX; } void window_size_counter_set(WindowSizeCounter *c, gsize value) { atomic_gssize_set(&c->counter, value & COUNTER_MASK); } gsize window_size_counter_get(WindowSizeCounter *c, gboolean *suspended) { gsize v = atomic_gssize_get_unsigned(&c->counter); if (suspended) *suspended = _is_suspended(v); return v & COUNTER_MASK; } gsize window_size_counter_add(WindowSizeCounter *c, gsize value, gboolean *suspended) { gsize v = (gsize)atomic_gssize_add(&c->counter, value); gsize old_value = v & COUNTER_MASK; g_assert (old_value + value <= COUNTER_MAX); if (suspended) *suspended = _is_suspended(v); return old_value; } gsize window_size_counter_sub(WindowSizeCounter *c, gsize value, gboolean *suspended) { gsize v = (gsize)atomic_gssize_add(&c->counter, -1 * value); gsize old_value = v & COUNTER_MASK; g_assert (old_value >= value); if (suspended) *suspended = _is_suspended(v); return old_value; } void window_size_counter_suspend(WindowSizeCounter *c) { atomic_gssize_or(&c->counter, SUSPEND_MASK); } void window_size_counter_resume(WindowSizeCounter *c) { atomic_gssize_and(&c->counter, RESUME_MASK); } gboolean window_size_counter_suspended(WindowSizeCounter *c) { gsize v = atomic_gssize_get_unsigned(&c->counter); return _is_suspended(v); } syslog-ng-syslog-ng-4.4.0/lib/window-size-counter.h000066400000000000000000000034111450431004300222250ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * Copyright (c) 2018 Laszlo Budai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef WINDOW_SIZE_COUNTER_H_INCLUDED #define WINDOW_SIZE_COUNTER_H_INCLUDED #include "syslog-ng.h" #include "atomic-gssize.h" typedef struct _WindowSizeCounter WindowSizeCounter; struct _WindowSizeCounter { atomic_gssize counter; }; void window_size_counter_set(WindowSizeCounter *c, gsize value); gsize window_size_counter_get(WindowSizeCounter *c, gboolean *suspended); gsize window_size_counter_add(WindowSizeCounter *c, gsize value, gboolean *suspended); gsize window_size_counter_sub(WindowSizeCounter *c, gsize value, gboolean *suspended); void window_size_counter_suspend(WindowSizeCounter *c); void window_size_counter_resume(WindowSizeCounter *c); gboolean window_size_counter_suspended(WindowSizeCounter *c); gsize window_size_counter_get_max(void); #endif syslog-ng-syslog-ng-4.4.0/libtest/000077500000000000000000000000001450431004300170215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/libtest/CMakeLists.txt000066400000000000000000000013311450431004300215570ustar00rootroot00000000000000set(LIBTEST_HEADERS config_parse_lib.h fake-time.h mock-transport.h mock-cfg-parser.h mock-logpipe.h msg_parse_lib.h persist_lib.h proto_lib.h queue_utils_lib.h stopwatch.h cr_template.h grab-logging.h ) set(LIBTEST_SOURCES config_parse_lib.c fake-time.c libtest.c mock-transport.c mock-cfg-parser.c mock-logpipe.c msg_parse_lib.c persist_lib.c proto_lib.c queue_utils_lib.c stopwatch.c cr_template.c grab-logging.c ) add_library(libtest STATIC ${LIBTEST_SOURCES}) target_link_libraries(libtest syslog-ng ${CRITERION_LIBRARIES}) target_include_directories(libtest INTERFACE ${PROJECT_SOURCE_DIR}) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/libtest/Makefile.am000066400000000000000000000026121450431004300210560ustar00rootroot00000000000000libtestdir = \ $(pkglibdir)/libtest libtestincludedir = \ $(pkgincludedir)/libtest EXTRA_DIST += libtest/CMakeLists.txt libtest_LIBRARIES = \ libtest/libsyslog-ng-test.a libtest_libsyslog_ng_test_a_SOURCES = \ libtest/config_parse_lib.c \ libtest/config_parse_lib.h \ libtest/cr_template.c \ libtest/grab-logging.c \ libtest/grab-logging.h \ libtest/libtest.c \ libtest/mock-cfg-parser.c \ libtest/mock-cfg-parser.h \ libtest/mock-logpipe.c \ libtest/mock-logpipe.h \ libtest/mock-transport.c \ libtest/mock-transport.h \ libtest/fake-time.c \ libtest/fake-time.h \ libtest/msg_parse_lib.c \ libtest/msg_parse_lib.h \ libtest/persist_lib.c \ libtest/persist_lib.h \ libtest/proto_lib.c \ libtest/proto_lib.h \ libtest/queue_utils_lib.c \ libtest/queue_utils_lib.h \ libtest/stopwatch.c \ libtest/stopwatch.h libtest_libsyslog_ng_test_a_CFLAGS = $(AM_CFLAGS) $(CRITERION_CFLAGS) libtestinclude_HEADERS = \ libtest/config_parse_lib.h \ libtest/cr_template.h \ libtest/fake-time.h \ libtest/grab-logging.h \ libtest/mock-cfg-parser.h \ libtest/mock-transport.h \ libtest/msg_parse_lib.h \ libtest/persist_lib.h \ libtest/proto_lib.h \ libtest/queue_utils_lib.h \ libtest/stopwatch.h pkgconfig_DATA += \ libtest/syslog-ng-test.pc LIBTEST_LIBS = $(top_builddir)/libtest/libsyslog-ng-test.a include libtest/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/libtest/config_parse_lib.c000066400000000000000000000075211450431004300224570ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Juhász * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "config_parse_lib.h" #include "cfg.h" #include "cfg-parser.h" #include "plugin.h" static gchar ** split_plugin_name_and_config(const gchar *config_to_parse) { gchar **delimited = NULL; if (!config_to_parse || strlen(config_to_parse) == 0) return NULL; delimited = g_strsplit(config_to_parse, "(", 2); if (!delimited) return NULL; if (g_strv_length(delimited) == 2) { gchar *tmp = delimited[1]; delimited[1] = g_strdup_printf("(%s", tmp); g_free(tmp); return delimited; } g_strfreev(delimited); return NULL; } static gpointer parse_plugin_config(const gchar *config_to_parse, gint context, gpointer arg) { gpointer result = NULL; CfgLexer *old_lexer = configuration->lexer; CfgLexer *lexer = NULL; CFG_LTYPE *yylloc = NULL; Plugin *plugin = NULL; gchar **delimited; delimited = split_plugin_name_and_config(config_to_parse); if (!delimited) { fprintf(stderr, "Error parsing expression\n"); return NULL; } lexer = cfg_lexer_new_buffer(configuration, delimited[1], strlen(delimited[1])); if (!lexer) { fprintf(stderr, "Error parsing expression\n"); goto finish; } yylloc = g_new0(CFG_LTYPE, 1); yylloc->first_column = 1; yylloc->first_line = 1; yylloc->last_column = 1; yylloc->last_line = 1; plugin = cfg_find_plugin(configuration, context, delimited[0]); if (!plugin) { fprintf(stderr, "Error parsing expression\n"); goto finish; } configuration->lexer = lexer; cfg_set_global_paths(configuration); cfg_lexer_push_context(lexer, main_parser.context, main_parser.keywords, main_parser.name); result = cfg_parse_plugin(configuration, plugin, yylloc, arg); cfg_lexer_pop_context(lexer); if (!result) { fprintf(stderr, "Error parsing expression\n"); goto finish; } finish: configuration->lexer = old_lexer; if (lexer) cfg_lexer_free(lexer); g_free(yylloc); g_strfreev(delimited); return result; } static gboolean parse_general_config(const gchar *config_to_parse, gint context, gpointer arg) { gpointer result = NULL; CfgLexer *lexer = cfg_lexer_new_buffer(configuration, config_to_parse, strlen(config_to_parse)); if (!cfg_run_parser(configuration, lexer, &main_parser, &result, arg)) { fprintf(stderr, "Error parsing expression\n"); return FALSE; } return TRUE; } gboolean parse_config(const gchar *config_to_parse, gint context, gpointer arg, gpointer *result) { if (!config_to_parse || strlen(config_to_parse) == 0) return FALSE; if (result) { *result = parse_plugin_config(config_to_parse, context, arg); if (*result) return TRUE; } if (main_parser.context != context) return FALSE; return parse_general_config(config_to_parse, context, arg); } syslog-ng-syslog-ng-4.4.0/libtest/config_parse_lib.h000066400000000000000000000024401450431004300224570ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Juhász * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONFIG_PARSE_LIB_H_INCLUDED #define CONFIG_PARSE_LIB_H_INCLUDED 1 #include "syslog-ng.h" #include "plugin-types.h" gboolean parse_config(const gchar *config_to_parse, gint context, gpointer arg, gpointer *result); #endif syslog-ng-syslog-ng-4.4.0/libtest/cr_template.c000066400000000000000000000276641450431004300215030ustar00rootroot00000000000000/* * Copyright (c) 2012-2018 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cr_template.h" #include "stopwatch.h" #include "msg_parse_lib.h" #include "timeutils/misc.h" #include "logmsg/logmsg.h" #include "gsockaddr.h" #include "cfg.h" #include #include static MsgFormatOptions parse_options; void init_template_tests(void) { init_parse_options_and_load_syslogformat(&parse_options); } void deinit_template_tests(void) { deinit_syslogformat_module(); } LogMessage * message_from_list(va_list ap) { char *key, *value; LogMessage *msg = create_empty_message(); if (!msg) return NULL; key = va_arg(ap, char *); while (key) { value = va_arg(ap, char *); if (!value) return msg; log_msg_set_value_by_name(msg, key, value, -1); key = va_arg(ap, char *); } return msg; } LogMessage * create_empty_message(void) { LogMessage *msg; const gchar *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép"; msg = msg_format_parse(&parse_options, (const guchar *) msg_str, strlen(msg_str)); log_msg_set_saddr_ref(msg, g_sockaddr_inet_new("10.11.12.13", 1010)); log_msg_set_daddr_ref(msg, g_sockaddr_inet_new("127.0.0.5", 6514)); log_msg_set_match(msg, 0, "whole-match", -1); log_msg_set_match(msg, 1, "first-match", -1); log_msg_set_tag_by_name(msg, "alma"); log_msg_set_tag_by_name(msg, "korte"); log_msg_clear_tag_by_name(msg, "narancs"); log_msg_set_tag_by_name(msg, "citrom"); log_msg_set_tag_by_name(msg, "tag,containing,comma"); msg->rcptid = 555; msg->host_id = 0xcafebabe; msg->proto = 33; /* fix some externally or automatically defined values */ log_msg_set_value(msg, LM_V_HOST_FROM, "kismacska", -1); msg->timestamps[LM_TS_RECVD].ut_sec = 1139684315; msg->timestamps[LM_TS_RECVD].ut_usec = 639000; msg->timestamps[LM_TS_RECVD].ut_gmtoff = get_local_timezone_ofs(1139684315); return msg; } LogMessage * create_sample_message(void) { LogMessage *msg = create_empty_message(); log_msg_set_value_by_name(msg, "APP.VALUE", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE2", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE3", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE4", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE5", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE6", "value", -1); log_msg_set_value_by_name(msg, "APP.VALUE7", "value", -1); log_msg_set_value_by_name(msg, "APP.STRIP1", " value", -1); log_msg_set_value_by_name(msg, "APP.STRIP2", "value ", -1); log_msg_set_value_by_name(msg, "APP.STRIP3", " value ", -1); log_msg_set_value_by_name(msg, "APP.STRIP4", "value", -1); log_msg_set_value_by_name(msg, "APP.STRIP5", "", -1); log_msg_set_value_by_name(msg, "APP.QVALUE", "\"value\"", -1); log_msg_set_value_by_name(msg, ".unix.uid", "1000", -1); log_msg_set_value_by_name(msg, ".unix.gid", "1000", -1); log_msg_set_value_by_name(msg, ".unix.cmd", "command", -1); log_msg_set_value_by_name(msg, ".json.foo", "bar", -1); log_msg_set_value_by_name(msg, ".json.sub.value1", "subvalue1", -1); log_msg_set_value_by_name(msg, ".json.sub.value2", "subvalue2", -1); log_msg_set_value_by_name(msg, "escaping", "binary stuff follows \"\xad árvíztűrőtükörfúrógép", -1); log_msg_set_value_by_name(msg, "escaping2", "\xc3", -1); log_msg_set_value_by_name(msg, "null", "binary\0stuff", 12); log_msg_set_value_by_name(msg, "comma_value", "value,with,a,comma", -1); log_msg_set_value_by_name(msg, "empty_value", "", -1); log_msg_set_value_by_name(msg, "template_name", "dummy", -1); log_msg_set_value_by_name_with_type(msg, "number1", "123", -1, LM_VT_INTEGER); log_msg_set_value_by_name_with_type(msg, "number2", "456", -1, LM_VT_INTEGER); log_msg_set_value_by_name_with_type(msg, "bytes", "\0\1\2\3", 4, LM_VT_BYTES); log_msg_set_value_by_name_with_type(msg, "protobuf", "\4\5\6\7", 4, LM_VT_PROTOBUF); return msg; } LogTemplate * compile_template_with_escaping(const gchar *template, gboolean escaping) { LogTemplate *templ = log_template_new(configuration, NULL); gboolean success; GError *error = NULL; log_template_set_escape(templ, escaping); success = log_template_compile(templ, template, &error); cr_assert(success, "template expected to compile cleanly," " but it didn't, template=%s, error=%s", template, error ? error->message : "(none)"); g_clear_error(&error); return templ; } LogTemplate * compile_template(const gchar *template) { return compile_template_with_escaping(template, FALSE); } LogTemplate * compile_escaped_template(const gchar *template) { return compile_template_with_escaping(template, TRUE); } void assert_template_format_with_escaping_and_context_msgs(const gchar *template, gboolean escaping, const gchar *expected, gssize expected_len, LogMessageValueType expected_type, LogMessage **msgs, gint num_messages) { LogTemplate *templ = compile_template_with_escaping(template, escaping); const gchar *prefix = "somevoodooprefix/"; LogMessageValueType type; gint prefix_len = strlen(prefix); if (!templ) return; GString *res = g_string_new(prefix); const gchar *context_id = "test-context-id"; LogTemplateEvalOptions options = {NULL, LTZ_LOCAL, 999, context_id, LM_VT_STRING}; log_template_append_format_value_and_type_with_context(templ, msgs, num_messages, &options, res, &type); cr_assert(strncmp(res->str, prefix, prefix_len) == 0, "the prefix was overwritten by the template, template=%s, res=%s, expected_prefix=%s", template, res->str, prefix); expected_len = (expected_len >= 0 ? expected_len : strlen(expected)); cr_assert_eq(res->len - prefix_len, expected_len, "context template test failed, expected length mismatch, template=%s, actual=%.*s, expected=%.*s", template, (gint) res->len - prefix_len, res->str + prefix_len, (gint) expected_len, expected); cr_assert_arr_eq(res->str + prefix_len, expected, expected_len, "context template test failed, template=%s, actual=%.*s, expected=%.*s", template, (gint) res->len - prefix_len, res->str + prefix_len, (gint) expected_len, expected); if (expected_type != LM_VT_NONE) cr_assert_eq(type, expected_type, "expected type does not match template=%s, type=%d, expected_type=%d (value was %.*s)", template, type, expected_type, (gint) expected_len, expected); log_template_unref(templ); g_string_free(res, TRUE); } void assert_template_format_with_context_msgs(const gchar *template, const gchar *expected, LogMessage **msgs, gint num_messages) { assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, -1, LM_VT_NONE, msgs, num_messages); } void assert_template_format_with_escaping_msg(const gchar *template, gboolean escaping, const gchar *expected, LogMessage *msg) { assert_template_format_with_escaping_and_context_msgs(template, escaping, expected, -1, LM_VT_NONE, &msg, 1); } void assert_template_format_with_escaping(const gchar *template, gboolean escaping, const gchar *expected) { LogMessage *msg = create_sample_message(); assert_template_format_with_escaping_msg(template, escaping, expected, msg); log_msg_unref(msg); } void assert_template_format_msg(const gchar *template, const gchar *expected, LogMessage *msg) { assert_template_format_with_escaping_msg(template, FALSE, expected, msg); } void assert_template_format(const gchar *template, const gchar *expected) { assert_template_format_with_escaping(template, FALSE, expected); } void assert_template_format_value_and_type(const gchar *template, const gchar *expected, LogMessageValueType expected_type) { LogMessage *msg = create_sample_message(); assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, -1, expected_type, &msg, 1); log_msg_unref(msg); } void assert_template_format_value_and_type_msg(const gchar *template, const gchar *expected, LogMessageValueType expected_type, LogMessage *msg) { assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, -1, expected_type, &msg, 1); } void assert_template_format_value_and_type_with_escaping(const gchar *template, gboolean escaping, const gchar *expected, LogMessageValueType expected_type) { LogMessage *msg = create_sample_message(); assert_template_format_with_escaping_and_context_msgs(template, escaping, expected, -1, expected_type, &msg, 1); log_msg_unref(msg); } void assert_template_format_with_context(const gchar *template, const gchar *expected) { LogMessage *msg; LogMessage *context[2]; msg = create_sample_message(); context[0] = context[1] = msg; assert_template_format_with_context_msgs(template, expected, context, 2); log_msg_unref(msg); } void assert_template_format_with_len(const gchar *template, const gchar *expected, gssize expected_len) { LogMessage *msg = create_sample_message(); assert_template_format_with_escaping_and_context_msgs(template, FALSE, expected, expected_len, LM_VT_NONE, &msg, 1); log_msg_unref(msg); } void assert_template_failure(const gchar *template, const gchar *expected_error) { LogTemplate *templ = log_template_new(configuration, NULL); GError *error = NULL; cr_assert_not(log_template_compile(templ, template, &error), "compilation failure expected to template," " but success was returned, template=%s, expected_error=%s\n", template, expected_error); cr_assert(strstr(error ? error->message : "", expected_error) != NULL, "FAIL: compilation error doesn't match, error=%s, expected_error=%s\n", error->message, expected_error); g_clear_error(&error); log_template_unref(templ); } #define BENCHMARK_COUNT 100000 void perftest_template(gchar *template) { LogTemplate *templ; LogMessage *msg; GString *res = g_string_sized_new(1024); gint i; GError *error = NULL; templ = log_template_new(configuration, NULL); if (!log_template_compile(templ, template, &error)) { cr_assert(FALSE, "template expected to compile cleanly," " but it didn't, template=%s, error=%s", template, error ? error->message : "(none)"); return; } msg = create_sample_message(); start_stopwatch(); for (i = 0; i < BENCHMARK_COUNT; i++) { log_template_format(templ, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, res); } stop_stopwatch_and_display_result(BENCHMARK_COUNT, " %-90.*s", (int) strlen(template) - 1, template); log_template_unref(templ); g_string_free(res, TRUE); log_msg_unref(msg); } syslog-ng-syslog-ng-4.4.0/libtest/cr_template.h000066400000000000000000000067221450431004300215000ustar00rootroot00000000000000/* * Copyright (c) 2012-2018 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIBTEST_CR_TEMPLATE_H_INCLUDED #define LIBTEST_CR_TEMPLATE_H_INCLUDED 1 #include "syslog-ng.h" #include "template/templates.h" #include "msg-format.h" #include void assert_template_format(const gchar *template, const gchar *expected); void assert_template_format_msg(const gchar *template, const gchar *expected, LogMessage *msg); void assert_template_format_with_escaping(const gchar *template, gboolean escaping, const gchar *expected); void assert_template_format_with_escaping_msg(const gchar *template, gboolean escaping, const gchar *expected, LogMessage *msg); void assert_template_format_with_context(const gchar *template, const gchar *expected); void assert_template_format_with_context_msgs(const gchar *template, const gchar *expected, LogMessage **msgs, gint num_messages); void assert_template_format_with_len(const gchar *template, const gchar *expected, gssize expected_len); void assert_template_format_with_escaping_and_context_msgs(const gchar *template, gboolean escaping, const gchar *expected, gssize expected_len, LogMessageValueType expected_type, LogMessage **msgs, gint num_messages); void assert_template_format_value_and_type(const gchar *template, const gchar *expected, LogMessageValueType expected_type); void assert_template_format_value_and_type_msg(const gchar *template, const gchar *expected, LogMessageValueType expected_type, LogMessage *msg); void assert_template_format_value_and_type_with_escaping(const gchar *template, gboolean escaping, const gchar *expected, LogMessageValueType expected_type); void assert_template_failure(const gchar *template, const gchar *expected_failure); void perftest_template(gchar *template); LogMessage *create_empty_message(void); LogMessage *create_sample_message(void); LogMessage *message_from_list(va_list ap); LogTemplate *compile_template(const gchar *template); LogTemplate *compile_escaped_template(const gchar *template); LogTemplate *compile_template_with_escaping(const gchar *template, gboolean escaping); void init_template_tests(void); void deinit_template_tests(void); #endif syslog-ng-syslog-ng-4.4.0/libtest/fake-time.c000066400000000000000000000023641450431004300210340ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "fake-time.h" #include "timeutils/cache.h" void fake_time(time_t now) { GTimeVal tv = { now, 123 * 1000 }; set_cached_time(&tv); } void fake_time_add(time_t diff) { GTimeVal tv; cached_g_current_time(&tv); tv.tv_sec += diff; set_cached_time(&tv); } syslog-ng-syslog-ng-4.4.0/libtest/fake-time.h000066400000000000000000000022061450431004300210340ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2019 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIBTEST_FAKE_TIME_H_INCLUDED #define LIBTEST_FAKE_TIME_H_INCLUDED #include void fake_time(time_t now); void fake_time_add(time_t diff); #endif syslog-ng-syslog-ng-4.4.0/libtest/grab-logging.c000066400000000000000000000064411450431004300215310ustar00rootroot00000000000000/* * Copyright (c) 2012-2018 Balabit * Copyright (c) 2012 Peter Gyorko * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "grab-logging.h" #include "syslog-ng.h" #include "logmsg/logmsg.h" #include "messages.h" #include GList *internal_messages = NULL; static void grab_message(LogMessage *msg) { internal_messages = g_list_append(internal_messages, msg); } void reset_grabbed_messages(void) { g_list_foreach(internal_messages, (GFunc) log_msg_unref, NULL); g_list_free(internal_messages); internal_messages = NULL; } void start_grabbing_messages(void) { reset_grabbed_messages(); msg_set_post_func(grab_message); } void display_grabbed_messages(void) { GList *l; if (internal_messages) { fprintf(stderr, " # Grabbed internal messages follow:\n"); for (l = internal_messages; l; l = l->next) { LogMessage *msg = (LogMessage *) l->data; const gchar *msg_text = log_msg_get_value(msg, LM_V_MESSAGE, NULL); fprintf(stderr, " #\t%s\n", msg_text); } } else { fprintf(stderr, " # No internal messeges grabbed!\n"); } } void format_grabbed_messages(GString *log_buffer) { GList *l; if (internal_messages) { g_string_append(log_buffer, " # Grabbed internal messages follow:\n"); for (l = internal_messages; l; l = l->next) { LogMessage *msg = (LogMessage *) l->data; const gchar *msg_text = log_msg_get_value(msg, LM_V_MESSAGE, NULL); g_string_append_printf(log_buffer, " #\t%s\n", msg_text); } } else { g_string_append(log_buffer, " # No internal messages grabbed!\n"); } } void stop_grabbing_messages(void) { msg_set_post_func(NULL); } gboolean find_grabbed_message(const gchar *pattern) { GList *l; for (l = internal_messages; l; l = l->next) { LogMessage *msg = (LogMessage *) l->data; const gchar *msg_text = log_msg_get_value(msg, LM_V_MESSAGE, NULL); if (strstr(msg_text, pattern)) { return TRUE; } } return FALSE; } void assert_grabbed_log_contains(const gchar *pattern) { if (find_grabbed_message(pattern)) return; GString *log_buffer = g_string_sized_new(1024); format_grabbed_messages(log_buffer); cr_assert(FALSE, "Cannot find pattern `%s' in the log output:\n%s\n", pattern, log_buffer->str); g_string_free(log_buffer, TRUE); } syslog-ng-syslog-ng-4.4.0/libtest/grab-logging.h000066400000000000000000000026521450431004300215360ustar00rootroot00000000000000/* * Copyright (c) 2012-2018 Balabit * Copyright (c) 2012 Peter Gyorko * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIBTEST_GRAB_LOGGING_H_INCLUDED #define LIBTEST_GRAB_LOGGING_H_INCLUDED #include "syslog-ng.h" gboolean find_grabbed_message(const gchar *pattern); void reset_grabbed_messages(void); void start_grabbing_messages(void); void stop_grabbing_messages(void); void display_grabbed_messages(void); void format_grabbed_messages(GString *log_buffer); void assert_grabbed_log_contains(const gchar *pattern); #endif syslog-ng-syslog-ng-4.4.0/libtest/libtest.c000066400000000000000000000021141450431004300206310ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ void msg_event(int prio, const char *desc, void *tag1, ...) { ; } void main_loop_wakeup(void) { ; } syslog-ng-syslog-ng-4.4.0/libtest/mock-cfg-parser.c000066400000000000000000000041021450431004300221420ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mock-cfg-parser.h" #include "cfg-grammar.h" #include void cfg_parser_mock_clear_token(CfgParserMock *self) { if (self->yylval->type) cfg_lexer_free_token(self->yylval); self->yylval->type = 0; } void cfg_parser_mock_next_token(CfgParserMock *self) { cfg_parser_mock_clear_token(self); cfg_lexer_lex(self->lexer, self->yylval, self->yylloc); } void cfg_parser_mock_input(CfgParserMock *self, const gchar *buffer) { cfg_lexer_include_buffer(self->lexer, "#test-buffer", buffer, strlen(buffer)); } CfgParserMock * cfg_parser_mock_new(void) { CfgParserMock *self = g_new0(CfgParserMock, 1); self->yylval = g_new0(CFG_STYPE, 1); self->yylloc = g_new0(CFG_LTYPE, 1); self->yylval->type = LL_CONTEXT_ROOT; self->yylloc->first_column = 1; self->yylloc->first_line = 1; self->yylloc->last_column = 1; self->yylloc->last_line = 1; self->lexer = cfg_lexer_new_buffer(configuration, "", 0); return self; } void cfg_parser_mock_free(CfgParserMock *self) { cfg_parser_mock_clear_token(self); if (self->lexer) cfg_lexer_free(self->lexer); g_free(self->yylval); g_free(self->yylloc); g_free(self); } syslog-ng-syslog-ng-4.4.0/libtest/mock-cfg-parser.h000066400000000000000000000026401450431004300221540ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIBTEST_MOCK_CFG_PARSER_H_INCLUDED #define LIBTEST_MOCK_CFG_PARSER_H_INCLUDED #include "cfg-lexer.h" typedef struct { CFG_STYPE *yylval; CFG_LTYPE *yylloc; CfgLexer *lexer; } CfgParserMock; void cfg_parser_mock_input(CfgParserMock *self, const gchar *buffer); void cfg_parser_mock_clear_token(CfgParserMock *self); void cfg_parser_mock_next_token(CfgParserMock *self); CfgParserMock *cfg_parser_mock_new(void); void cfg_parser_mock_free(CfgParserMock *self); #endif syslog-ng-syslog-ng-4.4.0/libtest/mock-logpipe.c000066400000000000000000000036631450431004300215630ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mock-logpipe.h" LogMessage * log_pipe_mock_get_message(LogPipeMock *self, gint ndx) { g_assert(ndx >= 0 && ndx < self->captured_messages->len); return (LogMessage *) g_ptr_array_index(self->captured_messages, ndx); } static void log_pipe_mock_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { LogPipeMock *self = (LogPipeMock *) s; g_ptr_array_add(self->captured_messages, log_msg_ref(msg)); log_pipe_forward_msg(s, msg, path_options); } static void log_pipe_mock_free(LogPipe *s) { LogPipeMock *self = (LogPipeMock *) s; g_ptr_array_free(self->captured_messages, TRUE); log_pipe_free_method(s); } LogPipeMock * log_pipe_mock_new(GlobalConfig *cfg) { LogPipeMock *self = g_new0(LogPipeMock, 1); log_pipe_init_instance(&self->super, cfg); self->captured_messages = g_ptr_array_new_full(0, (GDestroyNotify) log_msg_unref); self->super.queue = log_pipe_mock_queue; self->super.free_fn = log_pipe_mock_free; return self; } syslog-ng-syslog-ng-4.4.0/libtest/mock-logpipe.h000066400000000000000000000024151450431004300215620ustar00rootroot00000000000000/* * Copyright (c) 2022 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MOCK_LOGPIPE_H_INCLUDED #define MOCK_LOGPIPE_H_INCLUDED #include "logpipe.h" typedef struct _LogPipeMock { LogPipe super; GPtrArray *captured_messages; } LogPipeMock; LogMessage *log_pipe_mock_get_message(LogPipeMock *self, gint ndx); LogPipeMock *log_pipe_mock_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/libtest/mock-transport.c000066400000000000000000000257531450431004300221640ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "mock-transport.h" #include "gsockaddr.h" #include #include #include #include #include typedef enum data_type { DATA_STRING, DATA_ERROR, } data_type_t; struct iovec_const { const gchar *iov_base; /* Pointer to data. */ gsize iov_len; /* Length of data. */ }; typedef struct data { data_type_t type; union { struct iovec_const iov; guint error_code; }; } data_t; struct _LogTransportMock { LogTransport super; /* data is stored in a series of data chunks, that are going to be returned as individual reads */ GArray *value; /* index currently read i/o chunk */ GArray *write_buffer; gint write_buffer_index; gint current_value_ndx; gsize write_chunk_limit; /* position within the current I/O chunk */ gint current_iov_pos; gboolean input_is_a_stream; gboolean eof_is_eagain; gpointer user_data; }; static void destroy_write_buffer_element(gpointer d) { data_t *data = (data_t *)d; if (data->type == DATA_STRING) g_free((gchar *)data->iov.iov_base); }; static GArray * clone_write_buffer(GArray *orig_write_buffer) { GArray *write_buffer = g_array_new(TRUE, TRUE, sizeof(data_t)); g_array_append_vals(write_buffer, orig_write_buffer->data, orig_write_buffer->len); for (int i = 0; i < write_buffer->len; i++) { data_t *data = &g_array_index(write_buffer, data_t, i); if (data->type == DATA_STRING) data->iov.iov_base = g_strndup(data->iov.iov_base, data->iov.iov_len); } return write_buffer; } LogTransportMock * log_transport_mock_clone(LogTransportMock *self) { LogTransportMock *clone = g_new(LogTransportMock, 1); *clone = *self; clone->write_buffer = clone_write_buffer(self->write_buffer); clone->value = g_array_new(TRUE, TRUE, sizeof(data_t)); g_array_append_vals(clone->value, self->value->data, self->value->len); return clone; } gpointer log_transport_mock_get_user_data(LogTransportMock *self) { return self->user_data; } void log_transport_mock_set_user_data(LogTransportMock *self, gpointer user_data) { self->user_data = user_data; } static GString * concat_write_buffer(GArray *write_buffer) { GString *concatenated = g_string_new(""); for (int i = 0; i < write_buffer->len; i++) { data_t *data = &g_array_index(write_buffer, data_t, i); g_string_append_len(concatenated, data->iov.iov_base, data->iov.iov_len); } return concatenated; } gssize log_transport_mock_read_from_write_buffer(LogTransportMock *self, gchar *buffer, gsize len) { GString *all_written_data = concat_write_buffer(self->write_buffer); gsize data_len = MIN(all_written_data->len - self->write_buffer_index, len); memcpy(buffer, all_written_data->str + self->write_buffer_index, data_len); self->write_buffer_index += data_len; g_string_free(all_written_data, TRUE); return data_len; } static void find_chunk(GArray *write_buffer, gsize location, gsize *chunk_index, gsize *chunk_offset) { gsize chunk_location = 0; int i; for (i = 0; i < write_buffer->len; i++) { gsize chunk_len = g_array_index(write_buffer, data_t, i).iov.iov_len; if (chunk_location + chunk_len > location) break; chunk_location += chunk_len; } g_assert(i != write_buffer->len); /* location is too large */ *chunk_index = i; *chunk_offset = location - chunk_location; } gssize log_transport_mock_read_chunk_from_write_buffer(LogTransportMock *self, gchar *buffer) { gsize chunk_index; gsize chunk_offset; find_chunk(self->write_buffer, self->write_buffer_index, &chunk_index, &chunk_offset); data_t data = g_array_index(self->write_buffer, data_t, chunk_index); gssize written_len = data.iov.iov_len - chunk_offset; memcpy(buffer, data.iov.iov_base + chunk_offset, written_len); self->write_buffer_index += written_len; return written_len; } void log_transport_mock_set_write_chunk_limit(LogTransportMock *self, gsize chunk_limit) { self->write_chunk_limit = chunk_limit; } void log_transport_mock_empty_write_buffer(LogTransportMock *self) { g_array_set_size(self->write_buffer, 0); self->write_buffer_index = 0; self->current_value_ndx = 0; } gssize log_transport_mock_read_method(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux) { LogTransportMock *self = (LogTransportMock *) s; struct iovec_const *current_iov; if (self->current_value_ndx >= self->value->len) { count = 0; goto exit; } switch (g_array_index(self->value, data_t, self->current_value_ndx).type) { case DATA_STRING: if (self->input_is_a_stream) count = 1; current_iov = &g_array_index(self->value, data_t, self->current_value_ndx).iov; if (count + self->current_iov_pos > current_iov->iov_len) count = current_iov->iov_len - self->current_iov_pos; memcpy(buf, current_iov->iov_base + self->current_iov_pos, count); self->current_iov_pos += count; if (self->current_iov_pos >= current_iov->iov_len) { self->current_iov_pos = 0; self->current_value_ndx++; } break; case DATA_ERROR: errno = g_array_index(self->value, data_t, self->current_value_ndx).error_code; self->current_value_ndx++; return -1; default: g_assert_not_reached(); } if (aux) aux->peer_addr = g_sockaddr_inet_new("1.2.3.4", 5555); exit: if (count == 0 && self->eof_is_eagain) { errno = EAGAIN; return -1; } return count; } gssize log_transport_mock_write_method(LogTransport *s, const gpointer buf, gsize count) { LogTransportMock *self = (LogTransportMock *)s; data_t data; if (self->write_chunk_limit && self->write_chunk_limit < count) count = self->write_chunk_limit; data.type = DATA_STRING; data.iov.iov_base = g_strndup(buf, count); data.iov.iov_len = count; g_array_append_val(self->write_buffer, data); return count; } gssize log_transport_mock_writev_method(LogTransport *s, struct iovec *iov, gint iov_count) { LogTransportMock *self = (LogTransportMock *)s; gssize sum = 0; for (gint i = 0; i < iov_count; i++) { data_t value; value.type = DATA_STRING; value.iov.iov_len = iov[i].iov_len; if (self->write_chunk_limit && sum + iov[i].iov_len > self->write_chunk_limit) value.iov.iov_len = self->write_chunk_limit - sum; value.iov.iov_base = g_strndup(iov[i].iov_base, value.iov.iov_len); g_array_append_val(self->write_buffer, value); sum += value.iov.iov_len; if (value.iov.iov_len != iov[i].iov_len) break; } return sum; } void log_transport_mock_free_method(LogTransport *s) { LogTransportMock *self = (LogTransportMock *)s; for (int i = 0; i < self->write_buffer->len; i++) { data_t *data = &g_array_index(self->write_buffer, data_t, i); destroy_write_buffer_element(data); } g_array_free(self->write_buffer, TRUE); g_array_free(self->value, TRUE); log_transport_free_method(s); } static void inject_error(LogTransportMock *self, const gchar *buffer, gssize length) { data_t data; data.type = DATA_ERROR; data.error_code = GPOINTER_TO_UINT(buffer); g_array_append_val(self->value, data); } static void inject_chunk(LogTransportMock *self, const gchar *buffer, gssize length) { if (length == -1) length = strlen(buffer); data_t data; data.type = DATA_STRING; data.iov = (struct iovec_const) { .iov_base = buffer, .iov_len = length }; g_array_append_val(self->value, data); } void log_transport_mock_inject_data(LogTransportMock *self, const gchar *buffer, gssize length) { if (length == LTM_INJECT_ERROR_LENGTH) inject_error(self, buffer, length); else inject_chunk(self, buffer, length); } void log_transport_mock_init(LogTransportMock *self, const gchar *read_buffer1, gssize read_buffer_length1, va_list va) { const gchar *buffer; gssize length; log_transport_init_instance(&self->super, 0); self->super.read = log_transport_mock_read_method; self->super.write = log_transport_mock_write_method; self->super.writev = log_transport_mock_writev_method; self->super.free_fn = log_transport_mock_free_method; buffer = read_buffer1; length = read_buffer_length1; while (buffer) { log_transport_mock_inject_data(self, buffer, length); buffer = va_arg(va, const gchar *); length = va_arg(va, gint); } self->current_value_ndx = 0; self->current_iov_pos = 0; } LogTransportMock * log_transport_mock_new(void) { LogTransportMock *self = g_new0(LogTransportMock, 1); self->write_buffer = g_array_new(TRUE, TRUE, sizeof(data_t)); self->value = g_array_new(TRUE, TRUE, sizeof(data_t)); return self; } LogTransport * log_transport_mock_stream_new(const gchar *read_buffer1, gssize read_buffer_length1, ...) { LogTransportMock *self = log_transport_mock_new(); va_list va; va_start(va, read_buffer_length1); log_transport_mock_init(self, read_buffer1, read_buffer_length1, va); va_end(va); self->input_is_a_stream = TRUE; return &self->super; } LogTransport * log_transport_mock_endless_stream_new(const gchar *read_buffer1, gssize read_buffer_length1, ...) { LogTransportMock *self = log_transport_mock_new(); va_list va; va_start(va, read_buffer_length1); log_transport_mock_init(self, read_buffer1, read_buffer_length1, va); va_end(va); self->input_is_a_stream = TRUE; self->eof_is_eagain = TRUE; return &self->super; } LogTransport * log_transport_mock_records_new(const gchar *read_buffer1, gssize read_buffer_length1, ...) { LogTransportMock *self = log_transport_mock_new(); va_list va; va_start(va, read_buffer_length1); log_transport_mock_init(self, read_buffer1, read_buffer_length1, va); va_end(va); return &self->super; } LogTransport * log_transport_mock_endless_records_new(const gchar *read_buffer1, gssize read_buffer_length1, ...) { LogTransportMock *self = log_transport_mock_new(); va_list va; va_start(va, read_buffer_length1); log_transport_mock_init(self, read_buffer1, read_buffer_length1, va); va_end(va); self->eof_is_eagain = TRUE; return &self->super; } syslog-ng-syslog-ng-4.4.0/libtest/mock-transport.h000066400000000000000000000060311450431004300221550ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MOCK_TRANSPORT_H_INCLUDED #define MOCK_TRANSPORT_H_INCLUDED 1 #include "transport/logtransport.h" typedef LogTransport *(*LogTransportMockConstructor)(const gchar *, gssize, ...); typedef struct _LogTransportMock LogTransportMock; /* macro to be used when injecting an error in the I/O stream */ #define LTM_INJECT_ERROR_LENGTH -2 #define LTM_INJECT_ERROR(err) (GUINT_TO_POINTER(err)), LTM_INJECT_ERROR_LENGTH /* macro to be used at the end of the I/O stream */ #define LTM_EOF NULL, 0 #define LTM_PADDING "padd", -1, "padd", -1, "padd", -1, "padd", -1, "padd", -1 LogTransport * log_transport_mock_stream_new(const gchar *read_buffer1, gssize read_buffer_length1, ...); LogTransport * log_transport_mock_endless_stream_new(const gchar *read_buffer1, gssize read_buffer_length1, ...); LogTransport * log_transport_mock_records_new(const gchar *read_buffer1, gssize read_buffer_length1, ...); LogTransport * log_transport_mock_endless_records_new(const gchar *read_buffer1, gssize read_buffer_length1, ...); void log_transport_mock_inject_data(LogTransportMock *self, const gchar *buffer, gssize length); gpointer log_transport_mock_get_user_data(LogTransportMock *self); void log_transport_mock_set_user_data(LogTransportMock *self, gpointer user_data); gssize log_transport_mock_read_from_write_buffer(LogTransportMock *self, gchar *buffer, gsize len); gssize log_transport_mock_read_chunk_from_write_buffer(LogTransportMock *self, gchar *buffer); void log_transport_mock_set_write_chunk_limit(LogTransportMock *self, gsize chunk_limit); void log_transport_mock_empty_write_buffer(LogTransportMock *self); LogTransportMock * log_transport_mock_clone(LogTransportMock *self); void log_transport_mock_init(LogTransportMock *self, const gchar *read_buffer1, gssize read_buffer_length1, va_list va); gssize log_transport_mock_write_method(LogTransport *s, const gpointer buf, gsize count); gssize log_transport_mock_read_method(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux); void log_transport_mock_free_method(LogTransport *s); #endif syslog-ng-syslog-ng-4.4.0/libtest/msg_parse_lib.c000066400000000000000000000203141450431004300217730ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "msg_parse_lib.h" #include "plugin.h" #include void init_parse_options_and_load_syslogformat(MsgFormatOptions *parse_options) { configuration = cfg_new_snippet(); cfg_load_module(configuration, "syslogformat"); msg_format_options_defaults(parse_options); msg_format_options_init(parse_options, configuration); } void deinit_syslogformat_module(void) { if (configuration) cfg_free(configuration); configuration = NULL; } void assert_log_message_has_tag(LogMessage *log_message, const gchar *tag_name) { cr_assert(log_msg_is_tag_by_name(log_message, tag_name), "Expected message to have '%s' tag", tag_name); } void assert_log_message_doesnt_have_tag(LogMessage *log_message, const gchar *tag_name) { cr_assert_not(log_msg_is_tag_by_name(log_message, tag_name), "Expected message not to have '%s' tag", tag_name); } void assert_log_message_value_unset(LogMessage *self, NVHandle handle) { gssize key_name_length; const gchar *key_name = log_msg_get_value_name(handle, &key_name_length); const gchar *value = log_msg_get_value_if_set(self, handle, &key_name_length); cr_assert(value == NULL, "Expected value for key %s to be unset but the actual value is %s", key_name, value); } void assert_log_message_value_unset_by_name(LogMessage *self, const gchar *name) { assert_log_message_value_unset(self, log_msg_get_value_handle(name)); } void assert_log_message_value_is_indirect(LogMessage *self, NVHandle handle) { NVEntry *entry = nv_table_get_entry(self->payload, handle, NULL, NULL); cr_assert(entry->indirect); } void assert_log_message_value_is_direct(LogMessage *self, NVHandle handle) { NVEntry *entry = nv_table_get_entry(self->payload, handle, NULL, NULL); cr_assert(!entry->indirect); } void assert_log_message_value_and_type(LogMessage *self, NVHandle handle, const gchar *expected_value, LogMessageValueType expected_type) { gssize key_name_length; gssize value_length; LogMessageValueType actual_type; const gchar *key_name = log_msg_get_value_name(handle, &key_name_length); const gchar *actual_value_r = log_msg_get_value_with_type(self, handle, &value_length, &actual_type); gchar *actual_value = g_strndup(actual_value_r, value_length); if (expected_value) { cr_assert_str_eq(actual_value, expected_value, "Invalid value for key %s; actual: %s, expected: %s", key_name, actual_value, expected_value); } else cr_assert_str_eq(actual_value, "", "No value is expected for key %s but its value is %s", key_name, actual_value); if (expected_type != LM_VT_NONE) cr_assert_eq(actual_type, expected_type, "Invalid value type for key %s; actual: %d, expected %d", key_name, actual_type, expected_type); g_free(actual_value); } void assert_log_message_value(LogMessage *self, NVHandle handle, const gchar *expected_value) { assert_log_message_value_and_type(self, handle, expected_value, LM_VT_NONE); } void assert_log_message_value_and_type_by_name(LogMessage *self, const gchar *name, const gchar *expected_value, LogMessageValueType expected_type) { assert_log_message_value_and_type(self, log_msg_get_value_handle(name), expected_value, expected_type); } void assert_log_message_match_value_and_type(LogMessage *self, gint index_, const gchar *expected_value, LogMessageValueType expected_type) { gssize value_length; LogMessageValueType actual_type; const gchar *actual_value_r = log_msg_get_match_with_type(self, index_, &value_length, &actual_type); gchar *actual_value = g_strndup(actual_value_r, value_length); if (expected_value) { cr_assert_str_eq(actual_value, expected_value, "Invalid value for $%d; actual: %s, expected: %s", index_, actual_value, expected_value); } else cr_assert_str_eq(actual_value, "", "No value is expected for $%d but its value is %s", index_, actual_value); if (expected_type != LM_VT_NONE) cr_assert_eq(actual_type, expected_type, "Invalid value type for $%d; actual: %d, expected %d", index_, actual_type, expected_type); g_free(actual_value); } void assert_log_message_match_value(LogMessage *self, gint index_, const gchar *expected_value) { assert_log_message_match_value_and_type(self, index_, expected_value, LM_VT_NONE); } void assert_log_message_value_by_name(LogMessage *self, const gchar *name, const gchar *expected_value) { assert_log_message_value_and_type_by_name(self, name, expected_value, LM_VT_NONE); } void assert_log_messages_saddr(LogMessage *log_message_a, LogMessage *log_message_b) { gchar address_a[256], address_b[256]; g_sockaddr_format(log_message_a->saddr, address_a, sizeof(address_a), GSA_FULL); g_sockaddr_format(log_message_b->saddr, address_b, sizeof(address_b), GSA_FULL); cr_assert_str_eq(address_a, address_b, "Non-matching socket address; a: %s, b: %s", address_a, address_b); } void assert_structured_data_of_messages(LogMessage *log_message_a, LogMessage *log_message_b) { GString *structured_data_string_a = g_string_sized_new(0); GString *structured_data_string_b = g_string_sized_new(0); log_msg_format_sdata(log_message_a, structured_data_string_a, 0); log_msg_format_sdata(log_message_b, structured_data_string_b, 0); cr_assert_str_eq(structured_data_string_a->str, structured_data_string_b->str, "Structure data string are not the same; a: %s, b: %s", structured_data_string_a->str, structured_data_string_b->str); g_string_free(structured_data_string_a, TRUE); g_string_free(structured_data_string_b, TRUE); } void assert_log_message_values_equal(LogMessage *log_message_a, LogMessage *log_message_b, NVHandle handle) { gssize key_name_length; const gchar *key_name = log_msg_get_value_name(handle, &key_name_length); const gchar *value_a = log_msg_get_value(log_message_a, handle, NULL); const gchar *value_b = log_msg_get_value(log_message_b, handle, NULL); cr_assert_str_eq(value_a, value_b, "Non-matching value for key %s; a: %s, b: %s", key_name, value_a, value_b); } void assert_log_messages_equal(LogMessage *log_message_a, LogMessage *log_message_b) { cr_assert_eq(log_message_a->timestamps[LM_TS_STAMP].ut_sec, log_message_b->timestamps[LM_TS_STAMP].ut_sec, "Timestamps are not the same"); cr_assert_eq(log_message_a->timestamps[LM_TS_STAMP].ut_usec, log_message_b->timestamps[LM_TS_STAMP].ut_usec, "Timestamps usec are not the same"); cr_assert_eq(log_message_a->timestamps[LM_TS_STAMP].ut_gmtoff, log_message_b->timestamps[LM_TS_STAMP].ut_gmtoff, "Timestamp offset are not the same"); cr_assert_eq(log_message_a->pri, log_message_b->pri, "Priorities are not the same"); assert_log_message_values_equal(log_message_a, log_message_b, LM_V_HOST); assert_log_message_values_equal(log_message_a, log_message_b, LM_V_PROGRAM); assert_log_message_values_equal(log_message_a, log_message_b, LM_V_MESSAGE); assert_log_message_values_equal(log_message_a, log_message_b, LM_V_PID); assert_log_message_values_equal(log_message_a, log_message_b, LM_V_MSGID); assert_structured_data_of_messages(log_message_a, log_message_b); assert_log_messages_saddr(log_message_a, log_message_b); } syslog-ng-syslog-ng-4.4.0/libtest/msg_parse_lib.h000066400000000000000000000056531450431004300220110ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MSG_PARSE_LIB_H_INCLUDED #define MSG_PARSE_LIB_H_INCLUDED #include "cfg.h" #include "logmsg/logmsg.h" #include "msg-format.h" void init_parse_options_and_load_syslogformat(MsgFormatOptions *parse_options); void deinit_syslogformat_module(void); void assert_log_messages_equal(LogMessage *log_message_a, LogMessage *log_message_b); void assert_log_message_value_is_direct(LogMessage *self, NVHandle handle); void assert_log_message_value_is_indirect(LogMessage *self, NVHandle handle); void assert_log_message_value_unset(LogMessage *self, NVHandle handle); void assert_log_message_value_unset_by_name(LogMessage *self, const gchar *name); void assert_log_message_value(LogMessage *self, NVHandle handle, const gchar *expected_value); void assert_log_message_value_and_type(LogMessage *self, NVHandle handle, const gchar *expected_value, LogMessageValueType expected_type); void assert_log_message_value_by_name(LogMessage *self, const gchar *name, const gchar *expected_value); void assert_log_message_value_and_type_by_name(LogMessage *self, const gchar *name, const gchar *expected_value, LogMessageValueType expected_type); void assert_log_message_value_and_type_by_name(LogMessage *self, const gchar *name, const gchar *expected_value, LogMessageValueType expected_type); void assert_log_message_match_value(LogMessage *self, gint index_, const gchar *expected_value); void assert_log_message_has_tag(LogMessage *log_message, const gchar *tag_name); void assert_log_message_doesnt_have_tag(LogMessage *log_message, const gchar *tag_name); void assert_log_messages_saddr(LogMessage *log_message_a, LogMessage *log_message_b); void assert_structured_data_of_messages(LogMessage *log_message_a, LogMessage *log_message_b); void assert_log_message_values_equal(LogMessage *log_message_a, LogMessage *log_message_b, NVHandle handle); #endif syslog-ng-syslog-ng-4.4.0/libtest/persist_lib.c000066400000000000000000000043451450431004300215120ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "persist_lib.h" #include #include #include PersistState * create_persist_state_for_test(const gchar *name) { PersistState *state = persist_state_new(name); cr_assert(persist_state_start(state)); return state; }; PersistState * clean_and_create_persist_state_for_test(const gchar *name) { unlink(name); return create_persist_state_for_test(name); }; PersistState * restart_persist_state(PersistState *state) { PersistState *new_state; gchar *name = g_strdup(persist_state_get_filename(state)); persist_state_commit(state); persist_state_free(state); new_state = create_persist_state_for_test(name); g_free(name); return new_state; }; void cancel_and_destroy_persist_state(PersistState *state) { gchar *filename = g_strdup(persist_state_get_filename(state)); persist_state_cancel(state); persist_state_free(state); unlink(filename); g_free(filename); }; void commit_and_free_persist_state(PersistState *state) { persist_state_commit(state); persist_state_free(state); }; void commit_and_destroy_persist_state(PersistState *state) { gchar *filename = g_strdup(persist_state_get_filename(state)); commit_and_free_persist_state(state); unlink(filename); g_free(filename); }; syslog-ng-syslog-ng-4.4.0/libtest/persist_lib.h000066400000000000000000000027051450431004300215150ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Viktor Tusa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LIBTEST_PERSIST_LIB_H_INCLUDED #define LIBTEST_PERSIST_LIB_H_INCLUDED #include "persist-state.h" PersistState *create_persist_state_for_test(const gchar *name); PersistState *clean_and_create_persist_state_for_test(const gchar *name); void cancel_and_destroy_persist_state(PersistState *state); void commit_and_destroy_persist_state(PersistState *state); void commit_and_free_persist_state(PersistState *state); PersistState *restart_persist_state(PersistState *state); #endif syslog-ng-syslog-ng-4.4.0/libtest/proto_lib.c000066400000000000000000000130321450431004300211550ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "proto_lib.h" #include "grab-logging.h" #include "cfg.h" #include LogProtoServerOptions proto_server_options; void assert_proto_server_status(LogProtoServer *proto, LogProtoStatus status, LogProtoStatus expected_status) { cr_assert_eq(status, expected_status, "LogProtoServer expected status mismatch"); } LogProtoStatus proto_server_fetch(LogProtoServer *proto, const guchar **msg, gsize *msg_len) { Bookmark bookmark; LogTransportAuxData aux; GSockAddr *saddr; gboolean may_read = TRUE; LogProtoStatus status; start_grabbing_messages(); do { log_transport_aux_data_init(&aux); status = log_proto_server_fetch(proto, msg, msg_len, &may_read, &aux, &bookmark); if (status == LPS_AGAIN) status = LPS_SUCCESS; } while (status == LPS_SUCCESS && *msg == NULL && may_read); saddr = aux.peer_addr; if (status == LPS_SUCCESS) { g_sockaddr_unref(saddr); } else { cr_assert_null(saddr, "returned saddr must be NULL on failure"); } stop_grabbing_messages(); return status; } LogProtoServer * construct_server_proto_plugin(const gchar *name, LogTransport *transport) { LogProtoServerFactory *proto_factory; log_proto_server_options_init(&proto_server_options, configuration); proto_factory = log_proto_server_get_factory(&configuration->plugin_context, name); cr_assert_not_null(proto_factory, "error looking up proto factory"); return log_proto_server_factory_construct(proto_factory, transport, &proto_server_options); } void assert_proto_server_fetch(LogProtoServer *proto, const gchar *expected_msg, gssize expected_msg_len) { const guchar *msg = NULL; gsize msg_len = 0; LogProtoStatus status; status = proto_server_fetch(proto, &msg, &msg_len); assert_proto_server_status(proto, status, LPS_SUCCESS); if (expected_msg_len < 0) expected_msg_len = strlen(expected_msg); cr_assert_eq(msg_len, expected_msg_len, "LogProtoServer expected message mismatch (length) " "actual: %" G_GSIZE_FORMAT " expected: %" G_GSIZE_FORMAT, msg_len, expected_msg_len); cr_assert_arr_eq((const gchar *) msg, expected_msg, expected_msg_len, "LogProtoServer expected message mismatch"); } void assert_proto_server_fetch_single_read(LogProtoServer *proto, const gchar *expected_msg, gssize expected_msg_len) { const guchar *msg = NULL; gsize msg_len = 0; LogProtoStatus status; LogTransportAuxData aux; Bookmark bookmark; gboolean may_read = TRUE; start_grabbing_messages(); log_transport_aux_data_init(&aux); status = log_proto_server_fetch(proto, &msg, &msg_len, &may_read, &aux, &bookmark); assert_proto_server_status(proto, status, LPS_SUCCESS); if (expected_msg) { if (expected_msg_len < 0) expected_msg_len = strlen(expected_msg); cr_assert_eq(msg_len, expected_msg_len, "LogProtoServer expected message mismatch (length)"); cr_assert_arr_eq((const gchar *) msg, expected_msg, expected_msg_len, "LogProtoServer expected message mismatch"); } else { cr_assert_null(msg, "when single-read finds an incomplete message, msg must be NULL"); cr_assert_null(aux.peer_addr, "returned saddr must be NULL on success"); } stop_grabbing_messages(); } void assert_proto_server_fetch_failure(LogProtoServer *proto, LogProtoStatus expected_status, const gchar *error_message) { const guchar *msg = NULL; gsize msg_len = 0; LogProtoStatus status; status = proto_server_fetch(proto, &msg, &msg_len); assert_proto_server_status(proto, status, expected_status); if (error_message) assert_grabbed_log_contains(error_message); } void assert_proto_server_fetch_ignored_eof(LogProtoServer *proto) { const guchar *msg = NULL; gsize msg_len = 0; LogProtoStatus status; LogTransportAuxData aux; Bookmark bookmark; gboolean may_read = TRUE; start_grabbing_messages(); log_transport_aux_data_init(&aux); status = log_proto_server_fetch(proto, &msg, &msg_len, &may_read, &aux, &bookmark); if (status == LPS_AGAIN) status = LPS_SUCCESS; assert_proto_server_status(proto, status, LPS_SUCCESS); cr_assert_null(msg, "when an EOF is ignored msg must be NULL"); cr_assert_null(aux.peer_addr, "returned saddr must be NULL on success"); stop_grabbing_messages(); } void init_proto_tests(void) { configuration = cfg_new_snippet(); log_proto_server_options_defaults(&proto_server_options); } void deinit_proto_tests(void) { log_proto_server_options_destroy(&proto_server_options); if (configuration) cfg_free(configuration); } syslog-ng-syslog-ng-4.4.0/libtest/proto_lib.h000066400000000000000000000040151450431004300211630ustar00rootroot00000000000000/* * Copyright (c) 2012-2019 Balabit * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef PROTO_LIB_H_INCLUDED #define PROTO_LIB_H_INCLUDED #include "logproto/logproto-server.h" extern LogProtoServerOptions proto_server_options; void assert_proto_server_status(LogProtoServer *proto, LogProtoStatus status, LogProtoStatus expected_status); void assert_proto_server_fetch(LogProtoServer *proto, const gchar *expected_msg, gssize expected_msg_len); void assert_proto_server_fetch_single_read(LogProtoServer *proto, const gchar *expected_msg, gssize expected_msg_len); void assert_proto_server_fetch_failure(LogProtoServer *proto, LogProtoStatus expected_status, const gchar *error_message); void assert_proto_server_fetch_ignored_eof(LogProtoServer *proto); LogProtoServer *construct_server_proto_plugin(const gchar *name, LogTransport *transport); void init_proto_tests(void); void deinit_proto_tests(void); static inline LogProtoServerOptions * get_inited_proto_server_options(void) { log_proto_server_options_init(&proto_server_options, configuration); return &proto_server_options; } #endif syslog-ng-syslog-ng-4.4.0/libtest/queue_utils_lib.c000066400000000000000000000053021450431004300223570ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 2016 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "queue_utils_lib.h" #include "logmsg/logmsg-serialize.h" #include #include #include #include #include int acked_messages = 0; int fed_messages = 0; gsize get_one_message_serialized_size(void) { GString *serialized = g_string_sized_new(256); SerializeArchive *sa = serialize_string_archive_new(serialized); LogMessage *msg = log_msg_new_empty(); log_msg_serialize(msg, sa, 0); gsize message_length = serialized->len; log_msg_unref(msg); g_string_free(serialized, TRUE); serialize_archive_free(sa); return message_length; } void test_ack(LogMessage *msg, AckType ack_type) { acked_messages++; } void feed_empty_messages(LogQueue *q, const LogPathOptions *path_options, gint n) { for (gint i = 0; i < n; i++) { LogMessage *msg = log_msg_new_empty(); log_msg_add_ack(msg, path_options); msg->ack_func = test_ack; log_queue_push_tail(q, msg, path_options); fed_messages++; } } void feed_some_messages(LogQueue *q, int n) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; path_options.ack_needed = TRUE; path_options.flow_control_requested = TRUE; feed_empty_messages(q, &path_options, n); } void send_some_messages(LogQueue *q, gint n, gboolean remove_from_backlog) { gint i; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; for (i = 0; i < n; i++) { LogMessage *msg = log_queue_pop_head(q, &path_options); cr_assert_not_null(msg); if (path_options.ack_needed) { log_msg_ack(msg, &path_options, AT_PROCESSED); } if (remove_from_backlog) log_queue_ack_backlog(q, 1); log_msg_unref(msg); } } syslog-ng-syslog-ng-4.4.0/libtest/queue_utils_lib.h000066400000000000000000000027141450431004300223700ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 2016 Viktor Juhasz * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef QUEUE_UTILS_LIB_H #define QUEUE_UTILS_LIB_H 1 #include "logqueue.h" #include "logpipe.h" extern int acked_messages; extern int fed_messages; void test_ack(LogMessage *msg, AckType ack_type); void feed_empty_messages(LogQueue *q, const LogPathOptions *path_options, gint n); void feed_some_messages(LogQueue *q, int n); void send_some_messages(LogQueue *q, gint n, gboolean remove_from_backlog); gsize get_one_message_serialized_size(void); #endif syslog-ng-syslog-ng-4.4.0/libtest/stopwatch.c000066400000000000000000000036261450431004300212100ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Peter Gyorko * Copyright (c) 2016 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stopwatch.h" #include #include struct timeval start_time_val; void start_stopwatch(void) { gettimeofday(&start_time_val, NULL); } /* return the amount of time spent since starting the watch in microsecs 1000000 == 1second */ guint64 stop_stopwatch_and_get_result(void) { guint64 diff; struct timeval end_time_val; gettimeofday(&end_time_val, NULL); diff = (end_time_val.tv_sec - start_time_val.tv_sec) * 1000000 + end_time_val.tv_usec - start_time_val.tv_usec; return diff; } void stop_stopwatch_and_display_result(gint iterations, const gchar *message_template, ...) { va_list args; guint64 diff; diff = stop_stopwatch_and_get_result(); va_start(args, message_template); vprintf(message_template, args); va_end(args); printf("; %.2f iterations/sec", iterations * 1e6 / diff); printf(", runtime=%lu.%06lus\n", diff / 1000000, diff % 1000000); } syslog-ng-syslog-ng-4.4.0/libtest/stopwatch.h000066400000000000000000000024771450431004300212200ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * Copyright (c) 2012 Peter Gyorko * Copyright (c) 2012 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STOPWATCH_H_INCLUDED #define STOPWATCH_H_INCLUDED 1 #include void start_stopwatch(void); guint64 stop_stopwatch_and_get_result(void); void stop_stopwatch_and_display_result(gint iterations, const gchar *message_template, ...) G_GNUC_PRINTF(2, 3); #endif syslog-ng-syslog-ng-4.4.0/libtest/syslog-ng-test.pc.in000066400000000000000000000005711450431004300226540ustar00rootroot00000000000000# Package Information for pkg-config prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ pkglibdir=@libdir@/syslog-ng includedir=@includedir@ Name: syslog-ng-test Description: Test helper package for syslog-ng modules Version: @PACKAGE_VERSION@ Requires.private: glib-2.0 syslog-ng Libs: -L${pkglibdir}/libtest -lsyslog-ng-test Cflags: -I${includedir}/syslog-ng/libtest syslog-ng-syslog-ng-4.4.0/libtest/tests/000077500000000000000000000000001450431004300201635ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/libtest/tests/CMakeLists.txt000066400000000000000000000000741450431004300227240ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_mock_transport) syslog-ng-syslog-ng-4.4.0/libtest/tests/Makefile.am000066400000000000000000000004151450431004300222170ustar00rootroot00000000000000libtest_tests_TESTS = \ libtest/tests/test_mock_transport EXTRA_DIST += libtest/tests/CMakeLists.txt check_PROGRAMS += ${libtest_tests_TESTS} libtest_tests_test_mock_transport_CFLAGS = $(TEST_CFLAGS) libtest_tests_test_mock_transport_LDADD = \ $(TEST_LDADD) syslog-ng-syslog-ng-4.4.0/libtest/tests/test_mock_transport.c000066400000000000000000000154711450431004300244430ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/mock-transport.h" #include Test(mock_transport, test_mock_transport_read) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); log_transport_mock_inject_data(transport, "chunk1", sizeof("chunk1")); log_transport_mock_inject_data(transport, LTM_INJECT_ERROR(EAGAIN)); log_transport_mock_inject_data(transport, "chunk2", sizeof("chunk2")); gchar buffer[100]; log_transport_read((LogTransport *)transport, buffer, sizeof(buffer), NULL); cr_assert_str_eq(buffer, "chunk1"); int rc; rc = log_transport_read((LogTransport *)transport, buffer, sizeof(buffer), NULL); cr_assert_eq(rc, -1); cr_assert_eq(errno, EAGAIN); log_transport_read((LogTransport *)transport, buffer, sizeof(buffer), NULL); cr_assert_str_eq(buffer, "chunk2"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_simple_write) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100]; log_transport_write((LogTransport *)transport, "chunk", sizeof("chunk")); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof(buffer)); cr_assert_str_eq(buffer, "chunk"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_write_with_chunk_limit) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100]; log_transport_mock_set_write_chunk_limit(transport, 2); gssize count = log_transport_write((LogTransport *)transport, "chunk", 6); cr_assert(count == 2); count = log_transport_write((LogTransport *)transport, "unk", 4); cr_assert(count == 2); count = log_transport_write((LogTransport *)transport, "k", 2); cr_assert(count == 2); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof(buffer)); cr_assert_str_eq(buffer, "chunk"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_writev) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100] = "chunkofdata"; struct iovec iov = { .iov_base = buffer, .iov_len = strlen(buffer) + 1 }; log_transport_writev((LogTransport *)transport, &iov, 1); memset(buffer, 0, sizeof(buffer)); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof(buffer)); cr_assert_str_eq(buffer, "chunkofdata"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_writev_with_chunk_limit) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100] = "chunkofdata"; struct iovec iov = { .iov_base = buffer, .iov_len = strlen(buffer) + 1 }; log_transport_mock_set_write_chunk_limit(transport, 2); gssize count = log_transport_writev((LogTransport *)transport, &iov, 1); cr_assert(count == 2); log_transport_mock_set_write_chunk_limit(transport, 0); iov.iov_base = &buffer[2]; iov.iov_len -= 2; count = log_transport_writev((LogTransport *)transport, &iov, 1); cr_assert(count == 10); memset(buffer, 0, sizeof(buffer)); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof(buffer)); cr_assert_str_eq(buffer, "chunkofdata"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_read_from_write_buffer) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100]; log_transport_write((LogTransport *)transport, "chunk1", sizeof("chunk1")); log_transport_write((LogTransport *)transport, "chunk2", sizeof("chunk2")); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof("chunk1")); cr_assert_str_eq(buffer, "chunk1"); log_transport_mock_read_from_write_buffer(transport, buffer, sizeof("chunk2")); cr_assert_str_eq(buffer, "chunk2"); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_mock_transport_read_chunk_from_write_buffer) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100]; int rc; log_transport_write((LogTransport *)transport, "chunk1", sizeof("chunk1")); log_transport_write((LogTransport *)transport, "chunk2", sizeof("chunk2")); log_transport_write((LogTransport *)transport, "chunk3", sizeof("chunk3")); rc = log_transport_mock_read_chunk_from_write_buffer(transport, buffer); cr_assert_str_eq(buffer, "chunk1"); cr_assert_eq(rc, sizeof("chunk1")); /* seeking 1 position to step into the middle of the chunk */ log_transport_mock_read_from_write_buffer(transport, buffer, 1); rc = log_transport_mock_read_chunk_from_write_buffer(transport, buffer); cr_assert_str_eq(buffer, "hunk2"); cr_assert_eq(rc, sizeof("hunk2")); rc = log_transport_mock_read_chunk_from_write_buffer(transport, buffer); cr_assert_str_eq(buffer, "chunk3"); cr_assert_eq(rc, sizeof("chunk3")); log_transport_free((LogTransport *)transport); } Test(mock_transport, test_cloning) { LogTransportMock *transport = (LogTransportMock *)log_transport_mock_records_new(LTM_EOF); cr_assert(transport); gchar buffer[100]; log_transport_write((LogTransport *)transport, "chunk1", sizeof("chunk1")); log_transport_write((LogTransport *)transport, "chunk2", sizeof("chunk2")); LogTransportMock *clone = log_transport_mock_clone(transport); log_transport_mock_read_from_write_buffer(clone, buffer, sizeof("chunk1")); cr_assert_str_eq(buffer, "chunk1"); log_transport_mock_read_from_write_buffer(clone, buffer, sizeof("chunk2")); cr_assert_str_eq(buffer, "chunk2"); log_transport_free((LogTransport *)transport); log_transport_free((LogTransport *)clone); } syslog-ng-syslog-ng-4.4.0/m4/000077500000000000000000000000001450431004300156735ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/m4/_ax_valgrind_check.m4000066400000000000000000000142271450431004300217350ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html # =========================================================================== # # SYNOPSIS # # AX_VALGRIND_CHECK() # # DESCRIPTION # # Checks whether Valgrind is present and, if so, allows running `make # check` under a variety of Valgrind tools to check for memory and # threading errors. # # Defines VALGRIND_CHECK_RULES which should be substituted in your # Makefile; and $enable_valgrind which can be used in subsequent configure # output. VALGRIND_ENABLED is defined and substituted, and corresponds to # the value of the --enable-valgrind option, which defaults to being # enabled if Valgrind is installed and disabled otherwise. # # If unit tests are written using a shell script and automake's # LOG_COMPILER system, the $(VALGRIND) variable can be used within the # shell scripts to enable Valgrind, as described here: # # https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html # # Usage example: # # configure.ac: # # AX_VALGRIND_CHECK # # Makefile.am: # # @VALGRIND_CHECK_RULES@ # VALGRIND_SUPPRESSIONS_FILES = my-project.supp # EXTRA_DIST = my-project.supp # # This results in a "check-valgrind" rule being added to any Makefile.am # which includes "@VALGRIND_CHECK_RULES@" (assuming the module has been # configured with --enable-valgrind). Running `make check-valgrind` in # that directory will run the module's test suite (`make check`) once for # each of the available Valgrind tools (out of memcheck, helgrind, drd and # sgcheck), and will output results to test-suite-$toolname.log for each. # The target will succeed if there are zero errors and fail otherwise. # # The macro supports running with and without libtool. # # LICENSE # # Copyright (c) 2014, 2015 Philip Withnall # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 4 AC_DEFUN([AX_VALGRIND_CHECK],[ dnl Check for --enable-valgrind AC_MSG_CHECKING([whether to enable Valgrind on the unit tests]) AC_ARG_ENABLE([valgrind], [AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])], [enable_valgrind=$enableval],[enable_valgrind=]) # Check for Valgrind. AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind]) AS_IF([test "$enable_valgrind" = "yes" -a "$VALGRIND" = ""],[ AC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind]) ]) AS_IF([test "$enable_valgrind" != "no"],[enable_valgrind=yes]) AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"]) AC_SUBST([VALGRIND_ENABLED],[$enable_valgrind]) AC_MSG_RESULT([$enable_valgrind]) # Check for Valgrind tools we care about. m4_define([valgrind_tool_list],[[memcheck], [helgrind], [drd], [exp-sgcheck]]) AS_IF([test "$VALGRIND" != ""],[ m4_foreach([vgtool],[valgrind_tool_list],[ m4_define([vgtooln],AS_TR_SH(vgtool)) m4_define([ax_cv_var],[ax_cv_valgrind_tool_]vgtooln) AC_CACHE_CHECK([for Valgrind tool ]vgtool,ax_cv_var,[ ax_cv_var= AS_IF([`$VALGRIND --tool=vgtool --help >/dev/null 2>&1`],[ ax_cv_var="vgtool" ]) ]) AC_SUBST([VALGRIND_HAVE_TOOL_]vgtooln,[$ax_cv_var]) ]) ]) VALGRIND_CHECK_RULES=' # Valgrind check # # Optional: # - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions # files to load. (Default: empty) # - VALGRIND_FLAGS: General flags to pass to all Valgrind tools. # (Default: --num-callers=30) # - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of: # memcheck, helgrind, drd, sgcheck). (Default: various) # Optional variables VALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES)) VALGRIND_FLAGS ?= --num-callers=30 VALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no VALGRIND_helgrind_FLAGS ?= --history-level=approx VALGRIND_drd_FLAGS ?= VALGRIND_sgcheck_FLAGS ?= # Internal use valgrind_tools = memcheck helgrind drd sgcheck valgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools))) valgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS) valgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS) valgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS) valgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS) valgrind_quiet = $(valgrind_quiet_$(V)) valgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY)) valgrind_quiet_0 = --quiet # Support running with and without libtool. ifneq ($(LIBTOOL),) valgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute else valgrind_lt = endif # Use recursive makes in order to ignore errors during check check-valgrind: ifeq ($(VALGRIND_ENABLED),yes) -$(foreach tool,$(valgrind_tools), \ $(if $(VALGRIND_HAVE_TOOL_$(tool))$(VALGRIND_HAVE_TOOL_exp_$(tool)), \ $(MAKE) $(AM_MAKEFLAGS) -k check-valgrind-tool VALGRIND_TOOL=$(tool); \ ) \ ) else @echo "Need to reconfigure with --enable-valgrind" endif # Valgrind running VALGRIND_TESTS_ENVIRONMENT = \ $(TESTS_ENVIRONMENT) \ env VALGRIND=$(VALGRIND) \ G_SLICE=always-malloc,debug-blocks \ G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly VALGRIND_LOG_COMPILER = \ $(valgrind_lt) \ $(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS) check-valgrind-tool: ifeq ($(VALGRIND_ENABLED),yes) $(MAKE) check-TESTS \ TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ LOG_FLAGS="$(valgrind_$(VALGRIND_TOOL)_flags)" \ TEST_SUITE_LOG=test-suite-$(VALGRIND_TOOL).log else @echo "Need to reconfigure with --enable-valgrind" endif DISTCHECK_CONFIGURE_FLAGS ?= DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind MOSTLYCLEANFILES ?= MOSTLYCLEANFILES += $(valgrind_log_files) .PHONY: check-valgrind check-valgrind-tool ' AC_SUBST([VALGRIND_CHECK_RULES]) m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])]) ]) syslog-ng-syslog-ng-4.4.0/m4/ax_cflags_gcc_option.m4000066400000000000000000000156221450431004300222760ustar00rootroot00000000000000dnl @synopsis AX_CFLAGS_GCC_OPTION (optionflag [,[shellvar][,[A][,[NA]]]) dnl dnl AX_CFLAGS_GCC_OPTION(-fvomit-frame) would show a message as like dnl "checking CFLAGS for gcc -fvomit-frame ... yes" and adds the dnl optionflag to CFLAGS if it is understood. You can override the dnl shellvar-default of CFLAGS of course. The order of arguments stems dnl from the explicit macros like AX_CFLAGS_WARN_ALL. dnl dnl The cousin AX_CXXFLAGS_GCC_OPTION would check for an option to add dnl to CXXFLAGS - and it uses the autoconf setup for C++ instead of C dnl (since it is possible to use different compilers for C and C++). dnl dnl The macro is a lot simpler than any special AX_CFLAGS_* macro (or dnl ac_cxx_rtti.m4 macro) but allows to check for arbitrary options. dnl However, if you use this macro in a few places, it would be great dnl if you would make up a new function-macro and submit it to the dnl ac-archive. dnl dnl - $1 option-to-check-for : required ("-option" as non-value) dnl - $2 shell-variable-to-add-to : CFLAGS (or CXXFLAGS in the other case) dnl - $3 action-if-found : add value to shellvariable dnl - $4 action-if-not-found : nothing dnl dnl note: in earlier versions, $1-$2 were swapped. We try to detect the dnl situation and accept a $2=~/-/ as being the old dnl option-to-check-for. dnl dnl also: there are other variants that emerged from the original macro dnl variant which did just test an option to be possibly added. dnl However, some compilers accept an option silently, or possibly for dnl just another option that was not intended. Therefore, we have to do dnl a generic test for a compiler family. For gcc we check "-pedantic" dnl being accepted which is also understood by compilers who just want dnl to be compatible with gcc even when not being made from gcc dnl sources. dnl dnl see also: dnl dnl AX_CFLAGS_SUN_OPTION AX_CFLAGS_HPUX_OPTION dnl AX_CFLAGS_AIX_OPTION AX_CFLAGS_IRIX_OPTION dnl dnl @category C dnl @author Guido U. Draheim dnl @version 2006-12-12 dnl @license GPLWithACException AC_DEFUN([AX_CFLAGS_GCC_OPTION_OLD], [dnl AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$2])dnl AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_C ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic -Werror % m4_ifval($2,$2,-option)" dnl GCC "-pedantic % m4_ifval($2,$2,-option) %% no, obsolete" dnl new GCC # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) dnl the only difference - the LANG selection... and the default FLAGS AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_OLD], [dnl AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$2])dnl AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic -Werror % m4_ifval($2,$2,-option)" dnl GCC "-pedantic % m4_ifval($2,$2,-option) %% no, obsolete" dnl new GCC # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) dnl ------------------------------------------------------------------------- AC_DEFUN([AX_CFLAGS_GCC_OPTION_NEW], [dnl AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$1])dnl AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_C ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic -Werror % m4_ifval($1,$1,-option)" dnl GCC "-pedantic % m4_ifval($1,$1,-option) %% no, obsolete" dnl new GCC # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) dnl the only difference - the LANG selection... and the default FLAGS AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_NEW], [dnl AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$1])dnl AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic -Werror % m4_ifval($1,$1,-option)" dnl GCC "-pedantic % m4_ifval($1,$1,-option) %% no, obsolete" dnl new GCC # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, [AX_CFLAGS_GCC_OPTION_NEW($@)],[AX_CFLAGS_GCC_OPTION_OLD($@)])]) AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, [AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])]) syslog-ng-syslog-ng-4.4.0/m4/ax_require_defined.m4000066400000000000000000000023021450431004300217540ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_require_defined.html # =========================================================================== # # SYNOPSIS # # AX_REQUIRE_DEFINED(MACRO) # # DESCRIPTION # # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have # been defined and thus are available for use. This avoids random issues # where a macro isn't expanded. Instead the configure script emits a # non-fatal: # # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found # # It's like AC_REQUIRE except it doesn't expand the required macro. # # Here's an example: # # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) # # LICENSE # # Copyright (c) 2014 Mike Frysinger # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 2 AC_DEFUN([AX_REQUIRE_DEFINED], [dnl m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) ])dnl AX_REQUIRE_DEFINED syslog-ng-syslog-ng-4.4.0/m4/check_java_support.m4000066400000000000000000000074401450431004300220140ustar00rootroot00000000000000AU_ALIAS([AC_CHECK_JAVA_VERSION], [AX_CHECK_JAVA_VERSION]) AU_ALIAS([AC_CHECK_GRADLE_VERSION], [AX_CHECK_GRADLE_VERSION]) AC_DEFUN([AX_READLINK], [ READLINK_TARGET=[$1] if test -n "$READLINK_TARGET"; then cd $(dirname "$READLINK_TARGET") while test -L "$READLINK_TARGET"; do READLINK_TARGET=$(readlink "$READLINK_TARGET") cd $(dirname "$READLINK_TARGET") done echo $(pwd -P)/$(basename "$READLINK_TARGET") fi ]) AC_DEFUN([AX_CHECK_GRADLE_VERSION], [AC_MSG_CHECKING([for GRADLE_VERSION]) EXPECTED_GRADLE_VERSION=[$1] GRADLE_BIN=`which gradle` if test "x$GRADLE_BIN" != "x"; then GRADLE_BIN=`AX_READLINK([$GRADLE_BIN])` GRADLE_VERSION=`gradle -version 2>&1 | grep Gradle | head -1 |sed "s/.*\ \(.*\)/\1/"` SHORT_VERSION=${GRADLE_VERSION%.*} MAJOR_VERSION=${SHORT_VERSION%.*} MINOR_VERSION=${SHORT_VERSION##*.} EXPECTED_MAJOR_VERSION=${EXPECTED_GRADLE_VERSION%.*} EXPECTED_MINOR_VERSION=${EXPECTED_GRADLE_VERSION##*.} if test "$MAJOR_VERSION" -lt "$EXPECTED_MAJOR_VERSION"; then AC_MSG_ERROR([Too old gradle version required: $EXPECTED_GRADLE_VERSION found: $GRADLE_VERSION]) elif test "$MAJOR_VERSION" -eq "$EXPECTED_MAJOR_VERSION"; then if test "$MINOR_VERSION" -lt "$EXPECTED_MINOR_VERSION"; then AC_MSG_ERROR([Too old gradle version required: $EXPECTED_GRADLE_VERSION= found: $GRADLE_VERSION]) fi fi AC_SUBST(GRADLE, "$GRADLE_BIN") $2 AC_MSG_RESULT([$SHORT_VERSION]) else $3 AC_MSG_RESULT([no]) fi ]) AC_DEFUN([AX_CHECK_JAVA_VERSION], [AC_MSG_CHECKING([for JAVA_VERSION]) case $host_os in freebsd*) DONT_RESOLVE_JAVA_BIN_LINKS="YES" ;; *) ;; esac JAVA_VERSION=[$1] JAVAC_BIN=`which javac` JAVAH_BIN=`which javah` JAR_BIN=`which jar` JAVA_HOME_CHECKER="/usr/libexec/java_home" if test "x$JAVAC_BIN" != "x"; then if test "x$DONT_RESOLVE_JAVA_BIN_LINKS" = "x"; then JAVAC_BIN=`AX_READLINK([$JAVAC_BIN])` JAVAH_BIN=`AX_READLINK([$JAVAH_BIN])` JAR_BIN=`AX_READLINK([$JAR_BIN])` fi JAVAC_VERSION=`$JAVAC_BIN -version 2>&1 | sed "s/.*\ \(.*\)/\1/"` SHORT_VERSION=${JAVAC_VERSION%.*} MAJOR_VERSION=${SHORT_VERSION%.*} MINOR_VERSION=${SHORT_VERSION##*.} VERSION_OK="1" EXPECTED_MAJOR_VERSION=${JAVA_VERSION%.*} EXPECTED_MINOR_VERSION=${JAVA_VERSION##*.} if test "$MAJOR_VERSION" -lt "$EXPECTED_MAJOR_VERSION"; then AC_MSG_NOTICE([Too old java version required: $JAVA_VERSION found: $SHORT_VERSION]) VERSION_OK="0" elif test "$MAJOR_VERSION" -eq "$EXPECTED_MAJOR_VERSION"; then if test "$MINOR_VERSION" -lt "$EXPECTED_MINOR_VERSION"; then AC_MSG_NOTICE([Too old java version required: $JAVA_VERSION found: $SHORT_VERSION]) VERSION_OK="0" fi fi if test "$VERSION_OK" = "1"; then if test -e "$JAVA_HOME_CHECKER"; then JNI_HOME=`$JAVA_HOME_CHECKER` else JNI_HOME=`echo $JAVAC_BIN | sed "s/\(.*\)[[/]]bin[[/]]java.*/\1\//"` fi JNI_LIBDIR=`find $JNI_HOME \( -name "libjvm.so" -or -name "libjvm.dylib" \) \ | sed "s-/libjvm\.so-/-" \ | sed "s-/libjvm\.dylib-/-" | head -n 1` JNI_LIBS="-L$JNI_LIBDIR -ljvm" JNI_INCLUDE_DIR=`find $JNI_HOME -name "jni.h" | sed "s/\(.*\)jni.h/\1/" | head -n 1` JNI_CFLAGS="-I$JNI_INCLUDE_DIR" JNI_MD_INCLUDE_DIR=`find $JNI_HOME -name "jni_md.h" | sed "s/\(.*\)jni_md.h/\1/" | head -n 1` JNI_CFLAGS="$JNI_CFLAGS -I$JNI_MD_INCLUDE_DIR" AC_SUBST(JNI_CFLAGS, "$JNI_CFLAGS") AC_SUBST(JNI_LIBS, "$JNI_LIBS") AC_SUBST(JAVAC, "$JAVAC_BIN") AC_SUBST(JAVAH, "$JAVAH_BIN") AC_SUBST(JAR, "$JAR_BIN") $2 AC_MSG_RESULT([$SHORT_VERSION]) else $3 AC_MSG_RESULT([no]) fi else $3 AC_MSG_RESULT([no]) fi ]) syslog-ng-syslog-ng-4.4.0/m4/m4_esyscmd_s.m4000066400000000000000000000013761450431004300205350ustar00rootroot00000000000000 # This implementation was copied from # https://github.com/Netflix/dynomite/commit/8c0b28d131f581835c7d0fcf195836bbd4aed4bf # # Although there's no explicit license text on the configure.ac file where # this was added, dynomite is under the Apache 2.0 license, so this is # covered by that as well. # # Author in the Dynomite codebase: # Akbar Ahmed, https://github.com/akbarahmed # # Merged into Dynomite by: # Shailesh Birari, https://github.com/shailesh33 # Add support for m4_esyscmd_s to autoconf-2.63 (used in RHEL/CentOS 6.7) m4_ifndef([m4_esyscmd_s], [m4_define([m4_chomp_all], [m4_format([[%.*s]], m4_bregexp(m4_translit([[$1]], [/], [/ ]), [/*$]), [$1])])]) m4_ifndef([m4_esyscmd_s], [m4_define([m4_esyscmd_s], [m4_chomp_all(m4_esyscmd([$1]))])]) syslog-ng-syslog-ng-4.4.0/modules/000077500000000000000000000000001450431004300170235ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/CMakeLists.txt000066400000000000000000000030211450431004300215570ustar00rootroot00000000000000add_subdirectory(add-contextual-data) add_subdirectory(afamqp) add_subdirectory(affile) add_subdirectory(afmongodb) add_subdirectory(afprog) add_subdirectory(afsmtp) add_subdirectory(afsocket) add_subdirectory(afsql) add_subdirectory(afstomp) add_subdirectory(afstreams) add_subdirectory(afuser) add_subdirectory(appmodel) add_subdirectory(azure-auth-header) add_subdirectory(basicfuncs) add_subdirectory(cef) add_subdirectory(confgen) add_subdirectory(cryptofuncs) add_subdirectory(csvparser) add_subdirectory(correlation) add_subdirectory(diskq) add_subdirectory(examples) add_subdirectory(ebpf) add_subdirectory(geoip2) add_subdirectory(getent) add_subdirectory(graphite) add_subdirectory(hook-commands) add_subdirectory(http) add_subdirectory(java) add_subdirectory(java-modules) add_subdirectory(json) add_subdirectory(kafka) add_subdirectory(kvformat) add_subdirectory(linux-kmsg-format) add_subdirectory(map-value-pairs) add_subdirectory(mqtt) add_subdirectory(native) add_subdirectory(openbsd) add_subdirectory(pacctformat) add_subdirectory(pseudofile) add_subdirectory(python) add_subdirectory(python-modules) add_subdirectory(redis) add_subdirectory(riemann) add_subdirectory(afsnmp) add_subdirectory(secure-logging) add_subdirectory(stardate) add_subdirectory(syslogformat) add_subdirectory(systemd-journal) add_subdirectory(system-source) add_subdirectory(tagsparser) add_subdirectory(timestamp) add_subdirectory(xml) add_subdirectory(regexp-parser) add_subdirectory(rate-limit-filter) add_subdirectory(metrics-probe) add_subdirectory(grpc) syslog-ng-syslog-ng-4.4.0/modules/Makefile.am000066400000000000000000000072301450431004300210610ustar00rootroot00000000000000include modules/add-contextual-data/Makefile.am include modules/afamqp/Makefile.am include modules/affile/Makefile.am include modules/afmongodb/Makefile.am include modules/afprog/Makefile.am include modules/afsmtp/Makefile.am include modules/afsocket/Makefile.am include modules/afsql/Makefile.am include modules/afstomp/Makefile.am include modules/afstreams/Makefile.am include modules/afuser/Makefile.am include modules/appmodel/Makefile.am include modules/azure-auth-header/Makefile.am include modules/basicfuncs/Makefile.am include modules/cef/Makefile.am include modules/confgen/Makefile.am include modules/cryptofuncs/Makefile.am include modules/csvparser/Makefile.am include modules/timestamp/Makefile.am include modules/correlation/Makefile.am include modules/diskq/Makefile.am include modules/examples/Makefile.am include modules/ebpf/Makefile.am include modules/geoip2/Makefile.am include modules/getent/Makefile.am include modules/graphite/Makefile.am include modules/hook-commands/Makefile.am include modules/http/Makefile.am include modules/java/Makefile.am include modules/java-modules/Makefile.am include modules/json/Makefile.am include modules/kafka/Makefile.am include modules/kvformat/Makefile.am include modules/linux-kmsg-format/Makefile.am include modules/map-value-pairs/Makefile.am include modules/mqtt/Makefile.am include modules/native/Makefile.am include modules/openbsd/Makefile.am include modules/pacctformat/Makefile.am include modules/pseudofile/Makefile.am include modules/python/Makefile.am include modules/python-modules/Makefile.am include modules/redis/Makefile.am include modules/riemann/Makefile.am include modules/afsnmp/Makefile.am include modules/secure-logging/Makefile.am include modules/stardate/Makefile.am include modules/syslogformat/Makefile.am include modules/systemd-journal/Makefile.am include modules/system-source/Makefile.am include modules/tagsparser/Makefile.am include modules/xml/Makefile.am include modules/regexp-parser/Makefile.am include modules/rate-limit-filter/Makefile.am include modules/metrics-probe/Makefile.am include modules/grpc/Makefile.am SYSLOG_NG_CORE_JAR=$(top_builddir)/modules/java/syslog-ng-core/libs/syslog-ng-core.jar SYSLOG_NG_MODULES = \ mod-afsocket mod-afstreams mod-affile mod-afprog \ mod-usertty mod-amqp mod-mongodb mod-smtp mod-http mod-json \ mod-syslogformat mod-linux-kmsg mod-pacctformat \ mod-confgen mod-system-source mod-csvparser mod-correlation \ mod-basicfuncs mod-cryptofuncs mod-geoip2 mod-afstomp \ mod-redis mod-pseudofile mod-graphite mod-riemann \ mod-python mod-java mod-java-modules mod-kvformat mod-date \ mod-native mod-cef mod-add-contextual-data mod-diskq mod-getent \ mod-map-value-pairs mod-tags-parser mod-xml \ mod-appmodel mod-openbsd mod-snmp mod-secure-logging \ mod-mqtt mod-regexp-parser mod-rate-limit-filter mod-metrics-probe \ mod-grpc modules modules/: ${SYSLOG_NG_MODULES} modules_test_subdirs = \ modules_afsocket modules_afstreams modules_affile \ modules_afprog modules_usertty modules_afamqp \ modules_afmongodb modules_afsmtp modules_http modules_json \ modules_syslogformat modules_linux_kmsg \ modules_pacctformat modules_confgen modules_system_source \ modules_csvparser modules_correlation modules_basicfuncs \ modules_cryptofuncs modules_geoip2 modules_afstomp \ modules_graphite modules_riemann modules_python \ modules_secure-logging modules_systemd_journal modules_kvformat modules_date \ modules_cef modules_diskq modules-add-contextual-data modules_getent \ modules_map-value-pairs modules_tagsparser modules_xml modules_appmodel \ modules_regexp-parser modules_rate-limit-filter modules_metrics-probe EXTRA_DIST += modules/CMakeLists.txt .PHONY: modules modules/ syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/000077500000000000000000000000001450431004300226465ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/CMakeLists.txt000066400000000000000000000014411450431004300254060ustar00rootroot00000000000000set(add_contextual_data_SOURCES add-contextual-data.c add-contextual-data.h add-contextual-data-parser.c add-contextual-data-parser.h add-contextual-data-plugin.c context-info-db.h context-info-db.c contextual-data-record.h contextual-data-record.c contextual-data-record-scanner.h contextual-data-record-scanner.c add-contextual-data-selector.h add-contextual-data-template-selector.h add-contextual-data-template-selector.c add-contextual-data-filter-selector.h add-contextual-data-filter-selector.c add-contextual-data-glob-selector.h add-contextual-data-glob-selector.c ) add_module( TARGET add_contextual_data GRAMMAR add-contextual-data-grammar SOURCES ${add_contextual_data_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/Makefile.am000066400000000000000000000045451450431004300247120ustar00rootroot00000000000000module_LTLIBRARIES += \ modules/add-contextual-data/libadd-contextual-data.la EXTRA_DIST += modules/add-contextual-data/CMakeLists.txt modules_add_contextual_data_libadd_contextual_data_la_SOURCES = \ modules/add-contextual-data/add-contextual-data.c \ modules/add-contextual-data/add-contextual-data.h \ modules/add-contextual-data/contextual-data-record.h \ modules/add-contextual-data/contextual-data-record.c \ modules/add-contextual-data/contextual-data-record-scanner.h \ modules/add-contextual-data/contextual-data-record-scanner.c \ modules/add-contextual-data/add-contextual-data-grammar.y \ modules/add-contextual-data/add-contextual-data-parser.c \ modules/add-contextual-data/add-contextual-data-parser.h \ modules/add-contextual-data/context-info-db.h \ modules/add-contextual-data/context-info-db.c \ modules/add-contextual-data/add-contextual-data-plugin.c \ modules/add-contextual-data/add-contextual-data-selector.h \ modules/add-contextual-data/add-contextual-data-glob-selector.h \ modules/add-contextual-data/add-contextual-data-glob-selector.c \ modules/add-contextual-data/add-contextual-data-template-selector.h \ modules/add-contextual-data/add-contextual-data-template-selector.c \ modules/add-contextual-data/add-contextual-data-filter-selector.h \ modules/add-contextual-data/add-contextual-data-filter-selector.c modules_add_contextual_data_libadd_contextual_data_la_CFLAGS = \ $(AM_CFLAGS) \ -I$(top_srcdir)/modules/add-contextual-data \ -I$(top_builddir)/modules/add-contextual-data modules_add_contextual_data_libadd_contextual_data_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_add_contextual_data_libadd_contextual_data_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_add_contextual_data_libadd_contextual_data_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) BUILT_SOURCES += \ modules/add-contextual-data/add-contextual-data-grammar.y \ modules/add-contextual-data/add-contextual-data-grammar.c \ modules/add-contextual-data/add-contextual-data-grammar.h EXTRA_DIST += \ modules/add-contextual-data/add-contextual-data-grammar.ym modules/add-contextual-data modules/add-contextual-data/ mod-add-contextual-data: \ modules/add-contextual-data/libadd_contextual_data.la .PHONY: modules/add-contextual-data/ mod-add-contextual-data include modules/add-contextual-data/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-filter-selector.c000066400000000000000000000174101450431004300317410ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "add-contextual-data-filter-selector.h" #include "syslog-ng.h" #include "cfg.h" #include "messages.h" #include "filter/filter-expr.h" #include "filter/filter-expr-parser.h" #include "filter/filter-pipe.h" typedef struct _FilterStore { GList *filters; GList *filter_names; } FilterStore; typedef struct _AddContextualDataFilterSelector { AddContextualDataSelector super; gchar *filters_path; GlobalConfig *master_cfg; GlobalConfig *filters_cfg; FilterStore *filter_store; } AddContextualDataFilterSelector; static FilterStore * _filter_store_new(void) { FilterStore *fs = g_new0(FilterStore, 1); return fs; } static void _filter_store_free(FilterStore *self) { g_list_free(self->filters); g_list_free(self->filter_names); g_free(self); } FilterStore * _filter_store_clone(FilterStore *self) { FilterStore *cloned = _filter_store_new(); cloned->filters = g_list_copy(self->filters); cloned->filter_names = g_list_copy(self->filter_names); return cloned; } static void _filter_store_prepend(FilterStore *self, gchar *name, FilterExprNode *filter) { self->filters = g_list_prepend(self->filters, filter); self->filter_names = g_list_prepend(self->filter_names, name); } static const gchar * _filter_store_get_first_matching_name(FilterStore *self, LogMessage *msg) { GList *filter_it, *name_it; FilterExprNode *filter; const gchar *name = NULL; for (filter_it = self->filters, name_it = self->filter_names; filter_it != NULL && name_it != NULL; filter_it = filter_it->next, name_it = name_it->next) { filter = (FilterExprNode *) filter_it->data; msg_debug("Evaluating filter", evt_tag_str("filter_name", name_it->data)); if (filter_expr_eval(filter, msg)) { name = (const gchar *) name_it->data; break; } } return name; } static gboolean _init_filters_from_file(AddContextualDataFilterSelector *self) { self->filters_cfg = cfg_new_subordinate(self->master_cfg); if (!cfg_read_config(self->filters_cfg, self->filters_path, NULL)) { cfg_free(self->filters_cfg); self->filters_cfg = NULL; msg_error("Error parsing filters of rule engine", evt_tag_str(EVT_TAG_FILENAME, self->filters_path)); return FALSE; } return TRUE; } static FilterExprNode * _init_filter_from_log_node(GlobalConfig *cfg, LogExprNode *node) { LogFilterPipe *filter_pipe = (LogFilterPipe *) node->children->object; FilterExprNode *selected_filter = filter_expr_clone(filter_pipe->expr); filter_expr_init(selected_filter, cfg); return selected_filter; } static gboolean _populate_filter_store(AddContextualDataFilterSelector *self) { GList *objects_in_cfg = cfg_tree_get_objects(&self->filters_cfg->tree); GList *cfg_object; for (cfg_object = objects_in_cfg; cfg_object != NULL; cfg_object = cfg_object->next) { LogExprNode *node = (LogExprNode *) cfg_object->data; if (node->content != ENC_FILTER) { msg_error("Error populating filter store; non-filter object in config"); g_list_free(objects_in_cfg); return FALSE; } FilterExprNode *selected_filter = _init_filter_from_log_node(self->filters_cfg, node); msg_debug("Insert into filter store", evt_tag_str("filter", node->name)); _filter_store_prepend(self->filter_store, node->name, selected_filter); } g_list_free(objects_in_cfg); return TRUE; } static FilterStore * _filter_store_order_by_selectors(FilterStore *self, GList *ordered_selectors) { FilterStore *fs_ordered = _filter_store_new(); GList *name_it, *filter_it, *selector_it; gboolean inserted; for(selector_it = ordered_selectors; selector_it != NULL; selector_it = selector_it->next) { inserted = FALSE; for (filter_it = self->filters, name_it = self->filter_names; filter_it != NULL && name_it != NULL; filter_it = filter_it->next, name_it = name_it->next) { if (g_strcmp0((const gchar *)selector_it->data, (const gchar *)name_it->data) == 0) { inserted = TRUE; _filter_store_prepend(fs_ordered, name_it->data, filter_it->data); self->filters = g_list_delete_link(self->filters, filter_it); self->filter_names = g_list_delete_link(self->filter_names, name_it); break; } } if (!inserted) msg_warning("A filter referenced by the database is not found in the filters file", evt_tag_str("filter", selector_it->data)); } fs_ordered->filters = g_list_reverse(fs_ordered->filters); fs_ordered->filter_names = g_list_reverse(fs_ordered->filter_names); _filter_store_free(self); return fs_ordered; } static gboolean _init(AddContextualDataSelector *s, GList *ordered_selectors) { AddContextualDataFilterSelector *self = (AddContextualDataFilterSelector *)s; if (!_init_filters_from_file(self)) return FALSE; if (!_populate_filter_store(self)) return FALSE; self->filter_store = _filter_store_order_by_selectors(self->filter_store, ordered_selectors); return TRUE; } static gchar * _resolve(AddContextualDataSelector *s, LogMessage *msg) { AddContextualDataFilterSelector *self = (AddContextualDataFilterSelector *)s; return g_strdup(_filter_store_get_first_matching_name(self->filter_store, msg)); } static void _free(AddContextualDataSelector *s) { AddContextualDataFilterSelector *self = (AddContextualDataFilterSelector *)s; if (self->filters_cfg) cfg_free(self->filters_cfg); _filter_store_free(self->filter_store); g_free(self->filters_path); } static AddContextualDataSelector *_clone(AddContextualDataSelector *s, GlobalConfig *cfg); static void add_contextual_data_filter_selector_init_instance(AddContextualDataFilterSelector *self) { self->super.ordering_required = TRUE; self->super.resolve = _resolve; self->super.free = _free; self->super.init = _init; self->super.clone = _clone; } static AddContextualDataSelector * _clone(AddContextualDataSelector *s, GlobalConfig *cfg) { AddContextualDataFilterSelector *self = (AddContextualDataFilterSelector *)s; AddContextualDataFilterSelector *cloned = g_new0(AddContextualDataFilterSelector, 1); add_contextual_data_filter_selector_init_instance(cloned); cloned->filters_path = g_strdup(self->filters_path); cloned->filters_cfg = NULL; cloned->master_cfg = self->master_cfg; cloned->filter_store = _filter_store_clone(self->filter_store); return &cloned->super; } AddContextualDataSelector * add_contextual_data_filter_selector_new(GlobalConfig *cfg, const gchar *filters_path) { AddContextualDataFilterSelector *self = g_new0(AddContextualDataFilterSelector, 1); add_contextual_data_filter_selector_init_instance(self); self->filters_path = g_strdup(filters_path); self->master_cfg = cfg; self->filters_cfg = NULL; self->filter_store = _filter_store_new(); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-filter-selector.h000066400000000000000000000022361450431004300317460ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_FILTER_SELECTOR_H_INCLUDED #define ADD_CONTEXTUAL_DATA_FILTER_SELECTOR_H_INCLUDED #include "add-contextual-data-selector.h" AddContextualDataSelector *add_contextual_data_filter_selector_new(GlobalConfig *cfg, const gchar *filters_path); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-glob-selector.c000066400000000000000000000124341450431004300314000ustar00rootroot00000000000000/* * Copyright (c) 2019 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "add-contextual-data-glob-selector.h" #include "scratch-buffers.h" #include "messages.h" typedef struct _GlobExpression { gchar *pattern; GPatternSpec *expr; } GlobExpression; static void glob_expression_populate(GlobExpression *gs, const gchar *pattern) { gs->pattern = g_strdup(pattern); gs->expr = g_pattern_spec_new(pattern); } static void glob_expression_clear(GlobExpression *gs) { g_free(gs->pattern); g_pattern_spec_free(gs->expr); } typedef struct _AddContextualDataGlobSelector { AddContextualDataSelector super; GArray *globs; LogTemplate *glob_template; } AddContextualDataGlobSelector; static GArray * _create_globs_array(void) { GArray *array = g_array_new(FALSE, TRUE, sizeof(GlobExpression)); return array; } static void _populate_globs_array(AddContextualDataGlobSelector *self, GList *ordered_selectors) { for (GList *l = ordered_selectors; l; l = l->next) { const gchar *selector = (const gchar *) l->data; GlobExpression gs; glob_expression_populate(&gs, selector); g_array_append_val(self->globs, gs); } } static GArray * _clone_globs_array(GArray *src) { GArray *dst = _create_globs_array(); for (gint i = 0; i < src->len; i++) { GlobExpression *src_expr = &g_array_index(src, GlobExpression, i); GlobExpression dst_expr; glob_expression_populate(&dst_expr, src_expr->pattern); g_array_append_val(dst, dst_expr); } return dst; } static const gchar * _find_first_matching_glob(AddContextualDataGlobSelector *self, LogMessage *msg) { GString *string = scratch_buffers_alloc(); GString *string_reversed = scratch_buffers_alloc(); log_template_format(self->glob_template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, string); g_string_assign(string_reversed, string->str); g_strreverse(string_reversed->str); for (gint i = 0; i < self->globs->len; i++) { GlobExpression *gs = &g_array_index(self->globs, GlobExpression, i); gboolean result = g_pattern_match(gs->expr, string->len, string->str, string_reversed->str); msg_trace("add-contextual-data(): Evaluating glob against message", evt_tag_str("glob-template", self->glob_template->template_str), evt_tag_str("string", string->str), evt_tag_str("pattern", gs->pattern), evt_tag_int("matched", result)); if (result) return gs->pattern; } return NULL; } static gboolean _init(AddContextualDataSelector *s, GList *ordered_selectors) { AddContextualDataGlobSelector *self = (AddContextualDataGlobSelector *)s; _populate_globs_array(self, ordered_selectors); return TRUE; } static gchar * _resolve(AddContextualDataSelector *s, LogMessage *msg) { AddContextualDataGlobSelector *self = (AddContextualDataGlobSelector *)s; return g_strdup(_find_first_matching_glob(self, msg)); } static void _free(AddContextualDataSelector *s) { AddContextualDataGlobSelector *self = (AddContextualDataGlobSelector *)s; log_template_unref(self->glob_template); for (int i = 0; i < self->globs->len; i++) { GlobExpression *gs = &g_array_index(self->globs, GlobExpression, i); glob_expression_clear(gs); } g_array_free(self->globs, TRUE); } static AddContextualDataSelector *_clone(AddContextualDataSelector *s, GlobalConfig *cfg); static void add_contextual_data_glob_selector_init_instance(AddContextualDataGlobSelector *self, LogTemplate *glob_template) { self->super.ordering_required = TRUE; self->super.resolve = _resolve; self->super.free = _free; self->super.init = _init; self->super.clone = _clone; self->glob_template = glob_template; } static AddContextualDataSelector * _clone(AddContextualDataSelector *s, GlobalConfig *cfg) { AddContextualDataGlobSelector *self = (AddContextualDataGlobSelector *) s; AddContextualDataGlobSelector *cloned = g_new0(AddContextualDataGlobSelector, 1); add_contextual_data_glob_selector_init_instance(cloned, log_template_ref(self->glob_template)); cloned->globs = _clone_globs_array(self->globs); return &cloned->super; } AddContextualDataSelector * add_contextual_data_glob_selector_new(LogTemplate *glob_template) { AddContextualDataGlobSelector *self = g_new0(AddContextualDataGlobSelector, 1); add_contextual_data_glob_selector_init_instance(self, glob_template); self->globs = _create_globs_array(); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-glob-selector.h000066400000000000000000000022431450431004300314020ustar00rootroot00000000000000/* * Copyright (c) 2019 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_GLOB_SELECTOR_H_INCLUDED #define ADD_CONTEXTUAL_DATA_GLOB_SELECTOR_H_INCLUDED #include "add-contextual-data-selector.h" AddContextualDataSelector *add_contextual_data_glob_selector_new(LogTemplate *glob_template); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-grammar.ym000066400000000000000000000066571450431004300305020ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "add-contextual-data-parser.h" } %code { #include "add-contextual-data.h" #include "cfg-grammar-internal.h" #include "add-contextual-data-template-selector.h" #include "add-contextual-data-filter-selector.h" #include "add-contextual-data-glob-selector.h" #include "syslog-names.h" #include "messages.h" } %define api.prefix {add_contextual_data_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogParser **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_ADD_CONTEXTUAL_DATA %token KW_DATABASE %token KW_SELECTOR %token KW_DEFAULT_SELECTOR %token KW_PREFIX %token KW_FILTERS %token KW_IGNORE_CASE %token KW_GLOB %type parser_expr_add_contextual_data %% start : LL_CONTEXT_PARSER parser_expr_add_contextual_data { YYACCEPT; } ; parser_expr_add_contextual_data : KW_ADD_CONTEXTUAL_DATA '(' { last_parser = *instance = add_contextual_data_parser_new(configuration); } parser_add_contextual_data_opts ')' { $$ = last_parser; } ; parser_add_contextual_data_opts : parser_add_contextual_data_opt parser_add_contextual_data_opts | ; parser_add_contextual_data_opt : KW_DATABASE '(' path_no_check ')' { add_contextual_data_set_filename(last_parser, $3); free($3); } | KW_SELECTOR '(' parser_add_contextual_data_selector_opt ')' | KW_DEFAULT_SELECTOR '(' string ')' { add_contextual_data_set_default_selector(last_parser, $3); free($3); } | KW_PREFIX '(' string ')' { add_contextual_data_set_prefix(last_parser, $3); free($3); } | KW_IGNORE_CASE '(' yesno ')' { add_contextual_data_set_ignore_case(last_parser, $3); }; parser_add_contextual_data_selector_opt : KW_FILTERS '(' string ')' { add_contextual_data_set_selector(last_parser, add_contextual_data_filter_selector_new(configuration, $3)); free($3); } | KW_GLOB '(' template_content ')' { add_contextual_data_set_selector(last_parser, add_contextual_data_glob_selector_new($3)); } | template_content { add_contextual_data_set_selector(last_parser, add_contextual_data_template_selector_new($1)); }; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-parser.c000066400000000000000000000037441450431004300301370ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "add-contextual-data.h" #include "cfg-parser.h" #include "add-contextual-data-grammar.h" #include "logpipe.h" #include "parser/parser-expr.h" #include "syslog-ng-config.h" #include extern int add_contextual_data_debug; int add_contextual_data_parse(CfgLexer *lexer, LogParser **instance, gpointer arg); static CfgLexerKeyword add_contextual_data_keywords[] = { {"add_contextual_data", KW_ADD_CONTEXTUAL_DATA}, {"database", KW_DATABASE}, {"selector", KW_SELECTOR}, {"default_selector", KW_DEFAULT_SELECTOR}, {"prefix", KW_PREFIX}, {"filters", KW_FILTERS}, {"glob", KW_GLOB}, {"ignore_case", KW_IGNORE_CASE}, {NULL} }; CfgParser add_contextual_data_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &add_contextual_data_debug, #endif .name = "add-contextual-data", .keywords = add_contextual_data_keywords, .parse = (gint(*)(CfgLexer *, gpointer *, gpointer)) add_contextual_data_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(add_contextual_data_, ADD_CONTEXTUAL_DATA_, LogParser **) syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-parser.h000066400000000000000000000022601450431004300301340ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_PARSER_H_INCLUDED #define ADD_CONTEXTUAL_DATA_PARSER_H_INCLUDED #include "cfg-parser.h" #include "parser/parser-expr.h" extern CfgParser add_contextual_data_parser; CFG_PARSER_DECLARE_LEXER_BINDING(add_contextual_data_, ADD_CONTEXTUAL_DATA_, LogParser **) #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-plugin.c000066400000000000000000000034561450431004300301410ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "add-contextual-data.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser add_contextual_data_parser; static Plugin add_contextual_data_plugins[] = { { .type = LL_CONTEXT_PARSER, .name = "add_contextual_data", .parser = &add_contextual_data_parser, }, }; gboolean add_contextual_data_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, add_contextual_data_plugins, G_N_ELEMENTS(add_contextual_data_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "add_contextual_data", .version = SYSLOG_NG_VERSION, .description = "The add_contextual_data module provides parsing support for CSV and other separated value formats for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = add_contextual_data_plugins, .plugins_len = G_N_ELEMENTS(add_contextual_data_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-selector.h000066400000000000000000000046511450431004300304660ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_SELECTOR_H_INCLUDED #define ADD_CONTEXTUAL_DATA_SELECTOR_H_INCLUDED #include "logmsg/logmsg.h" #include "context-info-db.h" typedef struct _AddContextualDataSelector AddContextualDataSelector; struct _AddContextualDataSelector { gboolean ordering_required; gchar *(*resolve)(AddContextualDataSelector *self, LogMessage *msg); void (*free)(AddContextualDataSelector *self); AddContextualDataSelector *(*clone)(AddContextualDataSelector *self, GlobalConfig *cfg); gboolean (*init)(AddContextualDataSelector *self, GList *ordered_selectors); }; static inline gchar * add_contextual_data_selector_resolve(AddContextualDataSelector *self, LogMessage *msg) { if (self && self->resolve) { return self->resolve(self, msg); } return NULL; } static inline void add_contextual_data_selector_free(AddContextualDataSelector *self) { if (self && self->free) { self->free(self); } g_free(self); } static inline gboolean add_contextual_data_selector_init(AddContextualDataSelector *self, GList *ordered_selectors) { if (self && self->init) { return self->init(self, ordered_selectors); } return FALSE; } static inline AddContextualDataSelector * add_contextual_data_selector_clone(AddContextualDataSelector *self, GlobalConfig *cfg) { if (self && self->clone) { return self->clone(self, cfg); } return NULL; } static inline gboolean add_contextual_data_selector_is_ordering_required(AddContextualDataSelector *self) { return self->ordering_required; } #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-template-selector.c000066400000000000000000000052051450431004300322660ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "add-contextual-data-template-selector.h" #include "template/templates.h" #include "syslog-ng.h" #include "messages.h" typedef struct _AddContextualDataTemplateSelector { AddContextualDataSelector super; LogTemplate *selector_template; } AddContextualDataTemplateSelector; static gboolean _init(AddContextualDataSelector *s, GList *ordered_selectors) { return TRUE; } static gchar * _resolve(AddContextualDataSelector *s, LogMessage *msg) { GString *selector_str = g_string_new(NULL); AddContextualDataTemplateSelector *self = (AddContextualDataTemplateSelector *)s; log_template_format(self->selector_template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, selector_str); return g_string_free(selector_str, FALSE); } static void _free(AddContextualDataSelector *s) { AddContextualDataTemplateSelector *self = (AddContextualDataTemplateSelector *)s; log_template_unref(self->selector_template); } static AddContextualDataSelector * _clone(AddContextualDataSelector *s, GlobalConfig *cfg) { AddContextualDataTemplateSelector *self = (AddContextualDataTemplateSelector *)s; AddContextualDataTemplateSelector *cloned = (AddContextualDataTemplateSelector *) add_contextual_data_template_selector_new(log_template_ref(self->selector_template)); return &cloned->super; } AddContextualDataSelector * add_contextual_data_template_selector_new(LogTemplate *selector_template) { AddContextualDataTemplateSelector *new_instance = g_new0(AddContextualDataTemplateSelector, 1); new_instance->selector_template = selector_template; new_instance->super.resolve = _resolve; new_instance->super.free = _free; new_instance->super.init = _init; new_instance->super.clone = _clone; return &new_instance->super; } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data-template-selector.h000066400000000000000000000022271450431004300322740ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_TEMPLATE_SELECTOR_H_INCLUDED #define ADD_CONTEXTUAL_DATA_TEMPLATE_SELECTOR_H_INCLUDED #include "add-contextual-data-selector.h" AddContextualDataSelector * add_contextual_data_template_selector_new(LogTemplate *selector_template); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data.c000066400000000000000000000213021450431004300266330ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "add-contextual-data.h" #include "logmsg/logmsg.h" #include "logpipe.h" #include "parser/parser-expr.h" #include "reloc.h" #include "cfg.h" #include "contextual-data-record-scanner.h" #include "add-contextual-data-selector.h" #include "template/templates.h" #include "context-info-db.h" #include "pathutils.h" #include "scratch-buffers.h" #include #include typedef struct AddContextualData { LogParser super; ContextInfoDB *context_info_db; AddContextualDataSelector *selector; gchar *default_selector; gchar *filename; gchar *prefix; gboolean ignore_case; } AddContextualData; void add_contextual_data_set_filename(LogParser *p, const gchar *filename) { AddContextualData *self = (AddContextualData *) p; g_free(self->filename); self->filename = g_strdup(filename); } void add_contextual_data_set_prefix(LogParser *p, const gchar *prefix) { AddContextualData *self = (AddContextualData *) p; g_free(self->prefix); self->prefix = g_strdup(prefix); } void add_contextual_data_set_ignore_case(LogParser *p, gboolean ignore) { AddContextualData *self = (AddContextualData *)p; self->ignore_case = ignore; } void add_contextual_data_set_default_selector(LogParser *p, const gchar *default_selector) { AddContextualData *self = (AddContextualData *) p; g_free(self->default_selector); self->default_selector = g_strdup(default_selector); } void add_contextual_data_set_selector(LogParser *p, AddContextualDataSelector *selector) { AddContextualData *self = (AddContextualData *) p; add_contextual_data_selector_free(self->selector); self->selector = selector; } static gboolean _is_default_selector_set(const AddContextualData *self) { return (self->default_selector != NULL); } static void _add_context_data_to_message(gpointer pmsg, const ContextualDataRecord *record) { LogMessage *msg = (LogMessage *) pmsg; GString *result = scratch_buffers_alloc(); LogMessageValueType type; log_template_format_value_and_type(record->value, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result, &type); log_msg_set_value_with_type(msg, record->value_handle, result->str, result->len, type); } static gboolean _process(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const gchar *input, gsize input_len) { AddContextualData *self = (AddContextualData *) s; LogMessage *msg = log_msg_make_writable(pmsg, path_options); gchar *resolved_selector = add_contextual_data_selector_resolve(self->selector, msg); const gchar *selector = resolved_selector; if (!context_info_db_contains(self->context_info_db, selector) && _is_default_selector_set(self)) selector = self->default_selector; msg_trace("add-contextual-data(): message lookup finished", evt_tag_str("message", input), evt_tag_str("resolved_selector", resolved_selector), evt_tag_str("selector", selector), evt_tag_msg_reference(*pmsg)); if (selector) context_info_db_foreach_record(self->context_info_db, selector, _add_context_data_to_message, (gpointer) msg); g_free(resolved_selector); return TRUE; } static void _replace_context_info_db(ContextInfoDB **old_db, ContextInfoDB *new_db) { context_info_db_unref(*old_db); *old_db = context_info_db_ref(new_db); } static LogPipe * _clone(LogPipe *s) { AddContextualData *self = (AddContextualData *) s; AddContextualData *cloned = (AddContextualData *) add_contextual_data_parser_new(s->cfg); log_parser_set_template(&cloned->super, log_template_ref(self->super.template_obj)); _replace_context_info_db(&cloned->context_info_db, self->context_info_db); add_contextual_data_set_prefix(&cloned->super, self->prefix); add_contextual_data_set_filename(&cloned->super, self->filename); add_contextual_data_set_default_selector(&cloned->super, self->default_selector); add_contextual_data_set_ignore_case(&cloned->super, self->ignore_case); cloned->selector = add_contextual_data_selector_clone(self->selector, s->cfg); return &cloned->super.super; } static void _free(LogPipe *s) { AddContextualData *self = (AddContextualData *) s; context_info_db_unref(self->context_info_db); g_free(self->filename); g_free(self->prefix); g_free(self->default_selector); add_contextual_data_selector_free(self->selector); log_parser_free_method(s); } static gboolean _is_relative_path(const gchar *filename) { return (filename[0] != '/'); } static gchar * _complete_relative_path_with_config_path(const gchar *filename) { return g_build_filename(get_installation_path_for(SYSLOG_NG_PATH_SYSCONFDIR), filename, NULL); } static FILE * _open_data_file(const gchar *filename) { FILE *f = NULL; if (_is_relative_path(filename)) { gchar *absolute_path = _complete_relative_path_with_config_path(filename); f = fopen(absolute_path, "r"); g_free(absolute_path); } else { f = fopen(filename, "r"); } return f; } static ContextualDataRecordScanner * _get_scanner(AddContextualData *self) { const gchar *type = get_filename_extension(self->filename); if (g_strcmp0(type, "csv") != 0) { msg_error("add-contextual-data(): unknown file extension, only files with a .csv extension are supported", evt_tag_str("filename", self->filename)); return NULL; } return contextual_data_record_scanner_new(log_pipe_get_config(&self->super.super), self->prefix); } static gboolean _load_context_info_db(AddContextualData *self) { ContextualDataRecordScanner *scanner; FILE *f = NULL; gboolean result = FALSE; if (!(scanner = _get_scanner(self))) goto error; f = _open_data_file(self->filename); if (!f) { msg_error("add-contextual-data(): Error opening database", evt_tag_str("filename", self->filename), evt_tag_error("error")); goto error; } if (!context_info_db_import(self->context_info_db, f, self->filename, scanner)) { msg_error("add-contextual-data(): Error while parsing database", evt_tag_str("filename", self->filename)); goto error; } result = TRUE; error: if (scanner) contextual_data_record_scanner_free(scanner); if (f) fclose(f); return result; } static gboolean _init_context_info_db(AddContextualData *self) { /* are we reinitializing after an unsuccessful config reload? in that * case we already have the context_info_db */ if (self->context_info_db) return TRUE; if (self->filename == NULL) { msg_error("add-contextual-data(): No database file set, specifying the database() option is mandatory"); return FALSE; } self->context_info_db = context_info_db_new(self->ignore_case); if (self->selector && add_contextual_data_selector_is_ordering_required(self->selector)) context_info_db_enable_ordering(self->context_info_db); return _load_context_info_db(self); } static gboolean _init_selector(AddContextualData *self) { return add_contextual_data_selector_init(self->selector, context_info_db_ordered_selectors(self->context_info_db)); } static gboolean _init(LogPipe *s) { AddContextualData *self = (AddContextualData *)s; if (!_init_context_info_db(self)) return FALSE; if (!_init_selector(self)) return FALSE; if (!log_parser_init_method(s)) return FALSE; return TRUE; } LogParser * add_contextual_data_parser_new(GlobalConfig *cfg) { AddContextualData *self = g_new0(AddContextualData, 1); log_parser_init_instance(&self->super, cfg); self->super.process = _process; self->selector = NULL; self->super.super.clone = _clone; self->super.super.free_fn = _free; self->super.super.init = _init; self->default_selector = NULL; self->prefix = NULL; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/add-contextual-data.h000066400000000000000000000030561450431004300266460ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ADD_CONTEXTUAL_DATA_H_INCLUDED #define ADD_CONTEXTUAL_DATA_H_INCLUDED #include "parser/parser-expr.h" #include "add-contextual-data-selector.h" void add_contextual_data_set_filename(LogParser *p, const gchar *filename); void add_contextual_data_set_selector(LogParser *p, AddContextualDataSelector *selector); void add_contextual_data_set_default_selector(LogParser *p, const gchar *default_selector); void add_contextual_data_set_prefix(LogParser *p, const gchar *perfix); void add_contextual_data_set_ignore_case(LogParser *p, gboolean ignore); LogParser *add_contextual_data_parser_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/context-info-db.c000066400000000000000000000231241450431004300260140ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "context-info-db.h" #include "atomic.h" #include "messages.h" #include "scratch-buffers.h" #include "compat/string.h" #include #include #include struct _ContextInfoDB { GAtomicCounter ref_cnt; GArray *data; GHashTable *index; gboolean is_data_indexed; gboolean is_ordering_enabled; GList *ordered_selectors; gboolean ignore_case; }; typedef struct _element_range { gsize offset; gsize length; } element_range; static gint _contextual_data_record_cmp(gconstpointer k1, gconstpointer k2) { ContextualDataRecord *r1 = (ContextualDataRecord *) k1; ContextualDataRecord *r2 = (ContextualDataRecord *) k2; return strcmp(r1->selector, r2->selector); } static gint _g_strcmp(gconstpointer a, gconstpointer b) { return g_strcmp0((const gchar *) a, (const gchar *) b); } static gint _g_strcasecmp(gconstpointer a, gconstpointer b) { if (!a || !b) return 1; return g_ascii_strcasecmp((const gchar *)a, (const gchar *)b); } static gint _contextual_data_record_case_cmp(gconstpointer k1, gconstpointer k2) { ContextualDataRecord *r1 = (ContextualDataRecord *) k1; ContextualDataRecord *r2 = (ContextualDataRecord *) k2; return _g_strcasecmp(r1->selector, r2->selector); } void context_info_db_enable_ordering(ContextInfoDB *self) { self->is_ordering_enabled = TRUE; } GList * context_info_db_ordered_selectors(ContextInfoDB *self) { return self->ordered_selectors; } void context_info_db_index(ContextInfoDB *self) { GCompareFunc record_cmp = self->ignore_case ? _contextual_data_record_case_cmp : _contextual_data_record_cmp; if (self->data->len > 0) { g_array_sort(self->data, record_cmp); gsize range_start = 0; ContextualDataRecord *range_start_record = &g_array_index(self->data, ContextualDataRecord, 0); for (gsize i = 1; i < self->data->len; ++i) { ContextualDataRecord *current_record = &g_array_index(self->data, ContextualDataRecord, i); if (record_cmp(range_start_record, current_record)) { element_range *current_range = g_new(element_range, 1); current_range->offset = range_start; current_range->length = i - range_start; g_hash_table_insert(self->index, range_start_record->selector, current_range); range_start_record = current_record; range_start = i; } } { element_range *last_range = g_new(element_range, 1); last_range->offset = range_start; last_range->length = self->data->len - range_start; g_hash_table_insert(self->index, range_start_record->selector, last_range); } self->is_data_indexed = TRUE; } } static void _ensure_indexed_db(ContextInfoDB *self) { if (!self->is_data_indexed) context_info_db_index(self); } static void _record_free(gpointer p) { ContextualDataRecord *rec = (ContextualDataRecord *) p; contextual_data_record_clean(rec); } static gboolean _strcase_eq(gconstpointer a, gconstpointer b) { return _g_strcasecmp(a, b) == 0; } static guint _str_case_insensitive_djb2_hash(const gchar *str) { guint hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + g_ascii_toupper(c); return hash; } static guint _strcase_hash(gconstpointer value) { return _str_case_insensitive_djb2_hash((const gchar *)value); } static void _free_array(GArray *array) { for (gsize i = 0; i < array->len; ++i) { ContextualDataRecord current_record = g_array_index(array, ContextualDataRecord, i); _record_free(¤t_record); } g_array_free(array, TRUE); } static void _free(ContextInfoDB *self) { if (self->index) { g_hash_table_unref(self->index); } if (self->data) { _free_array(self->data); } if (self->ordered_selectors) { g_list_free(self->ordered_selectors); } } static element_range * _get_range_of_records(ContextInfoDB *self, const gchar *selector) { _ensure_indexed_db(self); return (element_range *) g_hash_table_lookup(self->index, selector); } void context_info_db_purge(ContextInfoDB *self) { g_hash_table_remove_all(self->index); if (self->data->len > 0) self->data = g_array_remove_range(self->data, 0, self->data->len); } void context_info_db_insert(ContextInfoDB *self, const ContextualDataRecord *record) { g_array_append_val(self->data, *record); self->is_data_indexed = FALSE; if (self->is_ordering_enabled && !g_list_find_custom(self->ordered_selectors, record->selector, _g_strcmp)) self->ordered_selectors = g_list_append(self->ordered_selectors, record->selector); } gboolean context_info_db_contains(ContextInfoDB *self, const gchar *selector) { if (!selector) return FALSE; _ensure_indexed_db(self); return (_get_range_of_records(self, selector) != NULL); } gsize context_info_db_number_of_records(ContextInfoDB *self, const gchar *selector) { _ensure_indexed_db(self); gsize n = 0; element_range *range = _get_range_of_records(self, selector); if (range) n = range->length; return n; } void context_info_db_foreach_record(ContextInfoDB *self, const gchar *selector, ADD_CONTEXT_INFO_CB callback, gpointer arg) { _ensure_indexed_db(self); element_range *record_range = _get_range_of_records(self, selector); if (!record_range) return; for (gsize i = record_range->offset; i < record_range->offset + record_range->length; ++i) { ContextualDataRecord *record = &g_array_index(self->data, ContextualDataRecord, i); callback(arg, record); } } gboolean context_info_db_is_indexed(const ContextInfoDB *self) { return self->is_data_indexed; } gboolean context_info_db_is_loaded(const ContextInfoDB *self) { return (self->data != NULL && self->data->len > 0); } GList * context_info_db_get_selectors(ContextInfoDB *self) { _ensure_indexed_db(self); return g_hash_table_get_keys(self->index); } static void _truncate_eol(gchar *line, gsize line_len) { if (line_len >= 2 && line[line_len - 2] == '\r' && line[line_len - 1] == '\n') line[line_len - 2] = '\0'; else if (line_len >= 1 && line[line_len - 1] == '\n') line[line_len - 1] = '\0'; } static gboolean _get_line_without_eol(gchar **line_buf, gsize *line_buf_len, FILE *fp) { gssize n; if ((n = getline(line_buf, line_buf_len, fp)) == -1) return FALSE; _truncate_eol(*line_buf, n); *line_buf_len = strlen(*line_buf); return TRUE; } gboolean context_info_db_import(ContextInfoDB *self, FILE *fp, const gchar *filename, ContextualDataRecordScanner *scanner) { size_t line_buf_len; gchar *line_buf = NULL; gint lineno = 0; const ContextualDataRecord *next_record; while (_get_line_without_eol(&line_buf, &line_buf_len, fp)) { ScratchBuffersMarker marker; lineno++; if (line_buf_len == 0) continue; scratch_buffers_mark(&marker); next_record = contextual_data_record_scanner_get_next(scanner, line_buf, filename, lineno); scratch_buffers_reclaim_marked(marker); if (!next_record) { context_info_db_purge(self); g_free(line_buf); return FALSE; } msg_trace("add-contextual-data(): adding database entry", evt_tag_str("selector", next_record->selector), evt_tag_str("name", log_msg_get_value_name(next_record->value_handle, NULL)), evt_tag_str("type", log_msg_value_type_to_str(next_record->value->type_hint)), evt_tag_str("value", next_record->value->template_str)); context_info_db_insert(self, next_record); } g_free(line_buf); context_info_db_index(self); return TRUE; } ContextInfoDB * context_info_db_new(gboolean ignore_case) { ContextInfoDB *self = g_new0(ContextInfoDB, 1); g_atomic_counter_set(&self->ref_cnt, 1); self->ignore_case = ignore_case; GEqualFunc str_eq = self->ignore_case ? _strcase_eq : g_str_equal; GHashFunc str_hash = self->ignore_case ? _strcase_hash : g_str_hash; self->data = g_array_new(FALSE, FALSE, sizeof(ContextualDataRecord)); self->index = g_hash_table_new_full(str_hash, str_eq, NULL, g_free); return self; } ContextInfoDB * context_info_db_ref(ContextInfoDB *self) { if (self) { g_assert(g_atomic_counter_get(&self->ref_cnt) > 0); g_atomic_counter_inc(&self->ref_cnt); } return self; } void context_info_db_unref(ContextInfoDB *self) { if (self) { g_assert(g_atomic_counter_get(&self->ref_cnt)); if (g_atomic_counter_dec_and_test(&self->ref_cnt)) { _free(self); g_free(self); } } } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/context-info-db.h000066400000000000000000000050611450431004300260210ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTEXTINFODB_H_INCLUDED #define CONTEXTINFODB_H_INCLUDED #include "syslog-ng.h" #include "contextual-data-record-scanner.h" #include typedef struct _ContextInfoDB ContextInfoDB; typedef void (*ADD_CONTEXT_INFO_CB) (gpointer arg, const ContextualDataRecord *record); void context_info_db_enable_ordering(ContextInfoDB *self); GList *context_info_db_ordered_selectors(ContextInfoDB *self); void context_info_db_init(ContextInfoDB *self); void context_info_db_purge(ContextInfoDB *self); void context_info_db_index(ContextInfoDB *self); gboolean context_info_db_is_loaded(const ContextInfoDB *self); gboolean context_info_db_is_indexed(const ContextInfoDB *self); void context_info_db_insert(ContextInfoDB *self, const ContextualDataRecord *record); gboolean context_info_db_contains(ContextInfoDB *self, const gchar *selector); gsize context_info_db_number_of_records(ContextInfoDB *self, const gchar *selector); void context_info_db_foreach_record(ContextInfoDB *self, const gchar *selector, ADD_CONTEXT_INFO_CB callback, gpointer arg); GList *context_info_db_get_selectors(ContextInfoDB *self); gboolean context_info_db_import(ContextInfoDB *self, FILE *fp, const gchar *filename, ContextualDataRecordScanner *scanner); ContextInfoDB *context_info_db_new(gboolean ignore_case); ContextInfoDB *context_info_db_ref(ContextInfoDB *self); void context_info_db_unref(ContextInfoDB *self); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/contextual-data-record-scanner.c000066400000000000000000000213271450431004300310170ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "contextual-data-record-scanner.h" #include "scanner/csv-scanner/csv-scanner.h" #include "string-list.h" #include "messages.h" #include "cfg.h" #include struct _ContextualDataRecordScanner { ContextualDataRecord last_record; GlobalConfig *cfg; CSVScanner scanner; CSVScannerOptions options; gchar *filename; gchar *name_prefix; }; static gboolean _fetch_next(ContextualDataRecordScanner *self) { if (!csv_scanner_scan_next(&self->scanner)) { msg_error("add-contextual-data(): error parsing CSV file, expecting an additional column which was not found. Expecting (selector, name, value) triplets", evt_tag_str("target", csv_scanner_get_current_name(&self->scanner))); return FALSE; } return TRUE; } static gboolean _is_whole_record_parsed(ContextualDataRecordScanner *self) { if (!csv_scanner_scan_next(&self->scanner) && csv_scanner_is_scan_complete(&self->scanner)) return TRUE; msg_error("add-contextual-data(): extra data found at the end of line, expecting (selector, name, value) triplets"); return FALSE; } static gboolean _fetch_selector(ContextualDataRecordScanner *self, ContextualDataRecord *record) { if (!_fetch_next(self)) return FALSE; record->selector = g_strdup(csv_scanner_get_current_value(&self->scanner)); return TRUE; } static gboolean _fetch_name(ContextualDataRecordScanner *self, ContextualDataRecord *record) { if (!_fetch_next(self)) return FALSE; gchar *name = g_strdup_printf("%s%s", self->name_prefix ? : "", csv_scanner_get_current_value(&self->scanner)); record->value_handle = log_msg_get_value_handle(name); g_free(name); return TRUE; } static gboolean _fetch_value(ContextualDataRecordScanner *self, ContextualDataRecord *record) { if (!_fetch_next(self)) return FALSE; const gchar *value_template = csv_scanner_get_current_value(&self->scanner); record->value = log_template_new(self->cfg, NULL); GError *error = NULL; gboolean success; if (cfg_is_config_version_older(self->cfg, VERSION_VALUE_3_21) && strchr(value_template, '$') != NULL) { msg_warning("WARNING: the value field in add-contextual-data() CSV files has been changed " "to be a template starting with " VERSION_3_21 ". You are using an older config " "version and your CSV file contains a '$' character in this field, which needs " "to be escaped as '$$' once you change your @version declaration in the " "configuration. This message means that this string is now assumed to be a " "literal (non-template) string for compatibility", cfg_format_config_version_tag(self->cfg), evt_tag_str("selector", record->selector), evt_tag_str("name", log_msg_get_value_name(record->value_handle, NULL)), evt_tag_str("value", value_template)); log_template_compile_literal_string(record->value, value_template); success = TRUE; } else if (cfg_is_typing_feature_enabled(self->cfg)) { /* typing feature is enabled */ if (cfg_is_config_version_older(self->cfg, VERSION_VALUE_4_0)) { /* old @config, use compat mode but warn if the format would become incompatible */ if (strchr(value_template, '(') != NULL) { success = log_template_compile_with_type_hint(record->value, value_template, &error); if (!success) { log_template_set_type_hint(record->value, "string", NULL); msg_warning("WARNING: the value field in add-contextual-data() CSV files has been changed " "to support typing from " FEATURE_TYPING_VERSION ". You are using an older config " "version and your CSV file contains an unrecognized type-cast, probably a " "parenthesis in the value field. This will be interpreted in the `type(value)' " "format in future versions. Please add an " "explicit string() cast as shown in the 'fixed-value' tag of this log message " "or remove the parenthesis. The value column will be processed as a 'string' " "expression", cfg_format_config_version_tag(self->cfg), evt_tag_str("selector", record->selector), evt_tag_str("name", log_msg_get_value_name(record->value_handle, NULL)), evt_tag_str("value", value_template), evt_tag_printf("fixed-value", "string(%s)", value_template)); g_clear_error(&error); success = log_template_compile(record->value, value_template, &error); } } else { success = log_template_compile(record->value, value_template, &error); } } else { /* new @config, use the new format with error handling */ success = log_template_compile_with_type_hint(record->value, value_template, &error); } } else { /* typing feature is disabled, use old format, no warnings */ success = log_template_compile(record->value, value_template, &error); } if (!success) { msg_error("add-contextual-data(): error compiling template", evt_tag_str("selector", record->selector), evt_tag_str("name", log_msg_get_value_name(record->value_handle, NULL)), evt_tag_str("value", value_template), evt_tag_str("error", error->message)); g_clear_error(&error); return FALSE; } log_template_forget_template_string(record->value); return TRUE; } static gboolean _get_next_record(ContextualDataRecordScanner *self, const gchar *input, ContextualDataRecord *record) { gboolean result = FALSE; csv_scanner_init(&self->scanner, &self->options, input); if (!_fetch_selector(self, record)) goto error; if (!_fetch_name(self, record)) goto error; if (!_fetch_value(self, record)) goto error; if (!_is_whole_record_parsed(self)) goto error; result = TRUE; error: csv_scanner_deinit(&self->scanner); return result; } ContextualDataRecord * contextual_data_record_scanner_get_next(ContextualDataRecordScanner *self, const gchar *input, const gchar *filename, gint lineno) { contextual_data_record_init(&self->last_record); if (!_get_next_record(self, input, &self->last_record)) { contextual_data_record_clean(&self->last_record); msg_error("add-contextual-data(): the failing line is", evt_tag_str("input", input), evt_tag_printf("filename", "%s:%d", filename, lineno)); return NULL; } return &self->last_record; } void contextual_data_record_scanner_free(ContextualDataRecordScanner *self) { csv_scanner_options_clean(&self->options); g_free(self->name_prefix); g_free(self); } ContextualDataRecordScanner * contextual_data_record_scanner_new(GlobalConfig *cfg, const gchar *name_prefix) { ContextualDataRecordScanner *self = g_new0(ContextualDataRecordScanner, 1); self->cfg = cfg; csv_scanner_options_set_delimiters(&self->options, ","); csv_scanner_options_set_quote_pairs(&self->options, "\"\"''"); const gchar *column_array[] = { "selector", "name", "value", NULL }; csv_scanner_options_set_columns(&self->options, string_array_to_list(column_array)); csv_scanner_options_set_flags(&self->options, CSV_SCANNER_STRIP_WHITESPACE); csv_scanner_options_set_dialect(&self->options, CSV_SCANNER_ESCAPE_DOUBLE_CHAR); self->name_prefix = g_strdup(name_prefix); return self; } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/contextual-data-record-scanner.h000066400000000000000000000027111450431004300310200ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTEXTUAL_DATA_RECORD_SCANNER_H_INCLUDED #define CONTEXTUAL_DATA_RECORD_SCANNER_H_INCLUDED #include "contextual-data-record.h" typedef struct _ContextualDataRecordScanner ContextualDataRecordScanner; ContextualDataRecord *contextual_data_record_scanner_get_next(ContextualDataRecordScanner *self, const gchar *input, const gchar *filename, gint lineno); ContextualDataRecordScanner *contextual_data_record_scanner_new(GlobalConfig *cfg, const gchar *name_prefix); void contextual_data_record_scanner_free(ContextualDataRecordScanner *self); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/contextual-data-record.c000066400000000000000000000023561450431004300273710ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "contextual-data-record.h" void contextual_data_record_init(ContextualDataRecord *record) { record->selector = NULL; record->value_handle = 0; record->value = NULL; } void contextual_data_record_clean(ContextualDataRecord *record) { g_free(record->selector); log_template_unref(record->value); contextual_data_record_init(record); } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/contextual-data-record.h000066400000000000000000000024751450431004300274000ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONTEXTUAL_DATA_RECORD_H_INCLUDED #define CONTEXTUAL_DATA_RECORD_H_INCLUDED #include "syslog-ng.h" #include "logmsg/logmsg.h" #include "template/templates.h" typedef struct _ContextualDataRecord { gchar *selector; NVHandle value_handle; LogTemplate *value; } ContextualDataRecord; void contextual_data_record_init(ContextualDataRecord *record); void contextual_data_record_clean(ContextualDataRecord *record); #endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/000077500000000000000000000000001450431004300240105ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/CMakeLists.txt000066400000000000000000000005441450431004300265530ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_context_info_db DEPENDS add_contextual_data syslogformat basicfuncs) add_unit_test(CRITERION TARGET test_template_selector DEPENDS add_contextual_data) add_unit_test(CRITERION TARGET test_filter_selector DEPENDS add_contextual_data) add_unit_test(CRITERION TARGET test_glob_selector DEPENDS add_contextual_data) syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/Makefile.am000066400000000000000000000040571450431004300260520ustar00rootroot00000000000000modules_add_contextual_data_tests_TESTS = \ modules/add-contextual-data/tests/test_filter_selector \ modules/add-contextual-data/tests/test_template_selector \ modules/add-contextual-data/tests/test_glob_selector EXTRA_DIST += modules/add-contextual-data/tests/CMakeLists.txt check_PROGRAMS += \ ${modules_add_contextual_data_tests_TESTS} modules_add_contextual_data_tests_test_template_selector_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/add-contextual-data modules_add_contextual_data_tests_test_template_selector_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/add-contextual-data/libadd-contextual-data.la modules_add_contextual_data_tests_test_glob_selector_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/add-contextual-data modules_add_contextual_data_tests_test_glob_selector_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/add-contextual-data/libadd-contextual-data.la modules_add_contextual_data_tests_test_filter_selector_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/add-contextual-data modules_add_contextual_data_tests_test_filter_selector_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/add-contextual-data/libadd-contextual-data.la if HAVE_FMEMOPEN modules_add_contextual_data_tests_TESTS += \ modules/add-contextual-data/tests/test_context_info_db modules_add_contextual_data_tests_test_context_info_db_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/add-contextual-data modules_add_contextual_data_tests_test_context_info_db_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) \ $(PREOPEN_BASICFUNCS) \ -dlpreopen $(top_builddir)/modules/add-contextual-data/libadd-contextual-data.la endif syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/test_context_info_db.c000066400000000000000000000440751450431004300303710ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/cr_template.h" #include "context-info-db.h" #include "apphook.h" #include "scratch-buffers.h" #include "cfg.h" #include #include #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static void _count_records(gpointer arg, const ContextualDataRecord *record) { int *ctr = (int *) arg; ++(*ctr); } static void _test_empty_db(ContextInfoDB *context_info_db) { cr_assert_not(context_info_db_is_loaded(context_info_db) == TRUE, "Empty ContextInfoDB should be in unloaded state."); cr_assert_not(context_info_db_is_indexed(context_info_db) == TRUE, "Empty ContextInfoDB should be in un-indexed state."); cr_assert_not(context_info_db_contains(context_info_db, "selector") == TRUE, "Method context_info_db_contains should work with empty ContextInfoDB."); cr_assert_eq(context_info_db_number_of_records(context_info_db, "selector"), 0, "Method context_info_db_number should work with empty ContextInfoDB."); int ctr = 0; context_info_db_foreach_record(context_info_db, "selector", _count_records, (gpointer) & ctr); cr_assert_eq(ctr, 0, "Method context_info_db_foreach_record should work for with empty ContextInfoDB."); } Test(add_contextual_data, test_empty_db) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); _test_empty_db(context_info_db); context_info_db_unref(context_info_db); } Test(add_contextual_data, test_purge_empty_db) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); context_info_db_purge(context_info_db); _test_empty_db(context_info_db); context_info_db_unref(context_info_db); } Test(add_contextual_data, test_index_empty_db) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); context_info_db_index(context_info_db); _test_empty_db(context_info_db); context_info_db_unref(context_info_db); } static void _fill_context_info_db(ContextInfoDB *context_info_db, const gchar *selector_base, const gchar *name_base, const gchar *value_base, int number_of_selectors, int number_of_nv_pairs_per_selector) { int i, j; for (i = 0; i < number_of_selectors; i++) { for (j = 0; j < number_of_nv_pairs_per_selector; j++) { gchar buf[256]; ContextualDataRecord record; g_snprintf(buf, sizeof(buf), "%s-%d", selector_base, i); record.selector = g_strdup(buf); g_snprintf(buf, sizeof(buf), "%s-%d.%d", name_base, i, j); record.value_handle = log_msg_get_value_handle(buf); g_snprintf(buf, sizeof(buf), "%s-%d.%d", value_base, i, j); record.value = log_template_new(configuration, NULL); log_template_compile_literal_string(record.value, buf); context_info_db_insert(context_info_db, &record); } } } static gint _g_strcmp(const gconstpointer a, gconstpointer b) { return g_strcmp0((const gchar *) a, (const gchar *) b); } Test(add_contextual_data, test_insert) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); context_info_db_enable_ordering(context_info_db); _fill_context_info_db(context_info_db, "selector", "name", "value", 2, 5); int ctr = 0; cr_assert_eq(context_info_db_number_of_records(context_info_db, "selector-0"), 5, "selector-0 should have 5 nv-pairs"); context_info_db_foreach_record(context_info_db, "selector-0", _count_records, (gpointer) & ctr); cr_assert_eq(ctr, 5, "foreach should find 5 nv-pairs for selector-0"); cr_assert_eq(g_list_length(context_info_db_ordered_selectors(context_info_db)), 2, "2 different selectors were saved to the ordered list"); context_info_db_unref(context_info_db); } Test(add_contextual_data, test_get_selectors) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); _fill_context_info_db(context_info_db, "selector", "name", "value", 2, 5); GList *selectors = context_info_db_get_selectors(context_info_db); GList *selector0 = g_list_find_custom(selectors, "selector-0", _g_strcmp); GList *selector1 = g_list_find_custom(selectors, "selector-1", _g_strcmp); cr_assert_str_eq((const gchar *)selector0->data, "selector-0"); cr_assert_str_eq((const gchar *)selector1->data, "selector-1"); context_info_db_unref(context_info_db); g_list_free(selectors); } typedef struct _TestNVPair { const gchar *name; const gchar *value; } TestNVPair; typedef struct _TestNVPairStore { TestNVPair *pairs; int ctr; } TestNVPairStore; static void _foreach_get_nvpairs(gpointer arg, const ContextualDataRecord *record) { TestNVPairStore *store = (TestNVPairStore *) arg; TestNVPair pair; GString *result = scratch_buffers_alloc(); pair.name = log_msg_get_value_name(record->value_handle, NULL); LogMessage *msg = create_sample_message(); log_template_format(record->value, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, result); log_msg_unref(msg); pair.value = result->str; store->pairs[store->ctr++] = pair; } static void _assert_context_info_db_contains_name_value_pairs_by_selector(ContextInfoDB * context_info_db, const gchar * selector, TestNVPair * expected_nvpairs, guint number_of_expected_nvpairs) { TestNVPair result[number_of_expected_nvpairs]; TestNVPairStore result_store = {.pairs = result, .ctr = 0 }; context_info_db_foreach_record(context_info_db, selector, _foreach_get_nvpairs, (gpointer) & result_store); cr_assert_eq(result_store.ctr, number_of_expected_nvpairs); guint i; for (i = 0; i < number_of_expected_nvpairs; i++) { cr_assert_str_eq(result[i].name, expected_nvpairs[i].name); cr_assert_str_eq(result[i].value, expected_nvpairs[i].value); } } static void _assert_import_csv_with_single_selector(gchar *csv_content, gchar *selector_to_check, TestNVPair *expected_nvpairs, gsize expected_nvpairs_size) { FILE *fp = fmemopen(csv_content, strlen(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); fclose(fp); _assert_context_info_db_contains_name_value_pairs_by_selector(db, selector_to_check, expected_nvpairs, expected_nvpairs_size); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } Test(add_contextual_data, test_inserted_nv_pairs) { ContextInfoDB *context_info_db = context_info_db_new(FALSE); _fill_context_info_db(context_info_db, "selector", "name", "value", 1, 3); TestNVPair expected_nvpairs[] = { {.name = "name-0.0", .value = "value-0.0"}, {.name = "name-0.1", .value = "value-0.1"}, {.name = "name-0.2", .value = "value-0.2"} }; _assert_context_info_db_contains_name_value_pairs_by_selector (context_info_db, "selector-0", expected_nvpairs, ARRAY_SIZE(expected_nvpairs)); context_info_db_unref(context_info_db); } Test(add_contextual_data, test_import_with_valid_csv) { gchar csv_content[] = "selector1,name1,value1\n" "selector1,name1.1,value1.1\n" "selector2,name2,value2\n" "selector3,name3,value3\n" "selector3,name3.1,$(echo $HOST_FROM)"; FILE *fp = fmemopen(csv_content, sizeof(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); cr_assert(context_info_db_is_loaded(db), "The context_info_db_is_loaded reports False after a successful import operation. "); cr_assert(context_info_db_is_indexed(db), "The context_info_db_is_indexed reports False after successful import&load operations."); fclose(fp); TestNVPair expected_nvpairs_selector1[] = { {.name = "name1", .value = "value1"}, {.name = "name1.1", .value = "value1.1"}, }; TestNVPair expected_nvpairs_selector2[] = { {.name = "name2", .value = "value2"}, }; TestNVPair expected_nvpairs_selector3[] = { {.name = "name3", .value = "value3"}, {.name = "name3.1", .value = "kismacska"}, }; _assert_context_info_db_contains_name_value_pairs_by_selector(db, "selector1", expected_nvpairs_selector1, ARRAY_SIZE(expected_nvpairs_selector1)); _assert_context_info_db_contains_name_value_pairs_by_selector(db, "selector2", expected_nvpairs_selector2, ARRAY_SIZE(expected_nvpairs_selector2)); _assert_context_info_db_contains_name_value_pairs_by_selector(db, "selector3", expected_nvpairs_selector3, ARRAY_SIZE(expected_nvpairs_selector3)); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } Test(add_contextual_data, test_import_from_csv_with_crlf_line_ending, .description = "RFC 4180: Each record should be located on a separate line, delimited by a line break (CRLF).") { gchar csv_content[] = "selector1,name1,value1\r\n" "selector1,name1.1,value1.1"; TestNVPair expected_nvpairs[] = { {.name = "name1", .value = "value1"}, {.name = "name1.1", .value = "value1.1"}, }; _assert_import_csv_with_single_selector(csv_content, "selector1", expected_nvpairs, ARRAY_SIZE(expected_nvpairs)); } Test(add_contextual_data, test_import_from_csv_with_escaped_double_quote, .description = "RFC 4180: If double-quotes are used to enclose fields, then a double-quote appearing inside a " "field must be escaped by preceding it with another double quote.") { gchar csv_content[] = "selector1,name1,\"c\"\"cc\""; TestNVPair expected_nvpairs[] = { {.name = "name1", .value = "c\"cc"}, }; _assert_import_csv_with_single_selector(csv_content, "selector1", expected_nvpairs, ARRAY_SIZE(expected_nvpairs)); } Test(add_contextual_data, test_import_with_invalid_csv_content) { gchar csv_content[] = "xxx"; FILE *fp = fmemopen(csv_content, strlen(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert_not(context_info_db_import(db, fp, "dummy.csv", scanner), "Successfully import an invalid CSV file."); cr_assert_not(context_info_db_is_loaded(db), "The context_info_db_is_loaded reports True after a failing import operation. "); cr_assert_not(context_info_db_is_indexed(db), "The context_info_db_is_indexed reports True after failing import&load operations."); fclose(fp); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } Test(add_contextual_data, test_import_with_csv_contains_invalid_line) { gchar csv_content[] = "selector1,name1,value1\n" ",value1.1\n"; FILE *fp = fmemopen(csv_content, strlen(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert_not(context_info_db_import(db, fp, "dummy.csv", scanner), "Successfully import an invalid CSV file."); cr_assert_not(context_info_db_is_loaded(db), "The context_info_db_is_loaded reports True after a failing import operation. "); cr_assert_not(context_info_db_is_indexed(db), "The context_info_db_is_indexed reports True after failing import&load operations."); fclose(fp); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } struct TestNVPairPrefix { TestNVPair expected; const gchar *prefix; }; ParameterizedTestParameters(add_contextual_data, test_import_with_prefix) { static struct TestNVPairPrefix params[] = { { .expected = {.name = "name1", .value = "value1"}, .prefix = NULL }, { .expected = {.name = "name1", .value = "value1"}, .prefix = "" }, { .expected = {.name = "aaaname1", .value = "value1"}, .prefix = "aaa" }, { .expected = {.name = "aaa.name1", .value = "value1"}, .prefix = "aaa." }, { .expected = {.name = ".aaa.name1", .value = "value1"}, .prefix = ".aaa." }, { .expected = {.name = ".name1", .value = "value1"}, .prefix = "." }, { .expected = {.name = "....name1", .value = "value1"}, .prefix = "...." } }; size_t nb_params = sizeof (params) / sizeof (struct TestNVPairPrefix); return cr_make_param_array(struct TestNVPairPrefix, params, nb_params); } ParameterizedTest(struct TestNVPairPrefix *param, add_contextual_data, test_import_with_prefix) { gchar csv_content[] = "selector1,name1,value1"; FILE *fp = fmemopen(csv_content, sizeof(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, param->prefix); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); cr_assert(context_info_db_is_loaded(db), "The context_info_db_is_loaded reports False after a successful import operation. "); cr_assert(context_info_db_is_indexed(db), "The context_info_db_is_indexed reports False after successful import&load operations."); fclose(fp); _assert_context_info_db_contains_name_value_pairs_by_selector(db, "selector1", ¶m->expected, 1); } Test(add_contextual_data, test_ignore_case_on) { gchar csv_content[] = "LoCaLhOsT,tag1,value1"; FILE *fp = fmemopen(csv_content, strlen(csv_content), "r"); ContextInfoDB *db = context_info_db_new(TRUE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); cr_assert(context_info_db_contains(db, "Localhost")); cr_assert(context_info_db_contains(db, "localhost")); cr_assert(context_info_db_contains(db, "localhosT")); cr_assert(context_info_db_contains(db, "LOCALHOST")); cr_assert(context_info_db_contains(db, "LoCaLhOsT")); fclose(fp); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } Test(add_contextual_data, test_ignore_case_off) { gchar csv_content[] = "LoCaLhOsT,tag1,value1"; FILE *fp = fmemopen(csv_content, strlen(csv_content), "r"); ContextInfoDB *db = context_info_db_new(FALSE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); cr_assert_not(context_info_db_contains(db, "Localhost")); cr_assert_not(context_info_db_contains(db, "localhost")); cr_assert_not(context_info_db_contains(db, "localhosT")); cr_assert_not(context_info_db_contains(db, "LOCALHOST")); cr_assert(context_info_db_contains(db, "LoCaLhOsT")); fclose(fp); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } Test(add_contextual_data, test_selected_nvpairs_when_ignore_case_on) { gchar csv_content[] = "selector,name1,value1\n" "SeLeCtOr,name2,value2\n" "sElEcToR,name3,value3\n" "another,name4,value4"; FILE *fp = fmemopen(csv_content, sizeof(csv_content), "r"); ContextInfoDB *db = context_info_db_new(TRUE); ContextualDataRecordScanner *scanner = contextual_data_record_scanner_new(configuration, NULL); cr_assert(context_info_db_import(db, fp, "dummy.csv", scanner), "Failed to import valid CSV file."); cr_assert(context_info_db_is_loaded(db), "The context_info_db_is_loaded reports False after a successful import operation. "); cr_assert(context_info_db_is_indexed(db), "The context_info_db_is_indexed reports False after successful import&load operations."); fclose(fp); TestNVPair expected_nvpairs_selector1[] = { {.name = "name1", .value = "value1"}, {.name = "name2", .value = "value2"}, {.name = "name3", .value = "value3"}, }; TestNVPair expected_nvpairs_selector2[] = { {.name = "name4", .value = "value4"}, }; _assert_context_info_db_contains_name_value_pairs_by_selector(db, "SELECTOR", expected_nvpairs_selector1, ARRAY_SIZE(expected_nvpairs_selector1)); _assert_context_info_db_contains_name_value_pairs_by_selector(db, "another", expected_nvpairs_selector2, ARRAY_SIZE(expected_nvpairs_selector2)); context_info_db_unref(db); contextual_data_record_scanner_free(scanner); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); init_template_tests(); cfg_load_module(configuration, "syslogformat"); cfg_load_module(configuration, "basicfuncs"); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(add_contextual_data, .init=setup, .fini=teardown); syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/test_filter_selector.c000066400000000000000000000135161450431004300304060ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "add-contextual-data-filter-selector.h" #include "logmsg/logmsg.h" #include "template/macros.h" #include "cfg.h" #include "apphook.h" #include static gchar *test_filter_conf; static LogMessage * _create_log_msg(const gchar *message, const gchar *host) { LogMessage *msg = NULL; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, message, -1); log_msg_set_value(msg, LM_V_HOST, host, -1); return msg; } static gchar * _setup_filter_cfg(const gchar *cfg_content, gint size) { gchar tmp_filename[] = "testfiltersXXXXXX"; gint fd = mkstemp(tmp_filename); ssize_t retval = write(fd, cfg_content, size); if (retval > 0) close(fd); return g_strdup(tmp_filename); } static AddContextualDataSelector * _create_filter_selector(const gchar *filter_cfg, gint size, GList *ordered_filters) { GlobalConfig *cfg = cfg_new_snippet(); test_filter_conf = _setup_filter_cfg(filter_cfg, size); AddContextualDataSelector *selector = add_contextual_data_filter_selector_new(cfg, test_filter_conf); if (!add_contextual_data_selector_init(selector, ordered_filters)) return NULL; return selector; } static void setup(void) { app_startup(); /* Force to link the libtest library */ test_filter_conf = NULL; } static void teardown(void) { app_shutdown(); if (test_filter_conf) { unlink(test_filter_conf); } g_free(test_filter_conf); } TestSuite(add_contextual_data_filter_selector, .init = setup, .fini = teardown); Test(add_contextual_data_filter_selector, test_clone_selector_with_filters) { const gchar cfg_content[] = "filter f_localhost {"\ " host(\"localhost\");"\ "};"; GList *ordered_filters = NULL; ordered_filters = g_list_append(ordered_filters, "f_localhost"); AddContextualDataSelector *selector = _create_filter_selector(cfg_content, strlen(cfg_content), ordered_filters); AddContextualDataSelector *cloned_selector = add_contextual_data_selector_clone(selector, cfg_new_snippet()); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(cloned_selector, msg); cr_assert_str_eq(resolved_selector, "f_localhost", "Filter name is resolved."); g_free(resolved_selector); } Test(add_contextual_data_filter_selector, test_matching_host_filter_selection) { const gchar cfg_content[] = "filter f_localhost {"\ " host(\"localhost\");"\ "};"; GList *ordered_filters = NULL; ordered_filters = g_list_append(ordered_filters, "f_localhost"); AddContextualDataSelector *selector = _create_filter_selector(cfg_content, strlen(cfg_content), ordered_filters); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(selector, msg); cr_assert_str_eq(resolved_selector, "f_localhost", "Filter name is resolved."); g_free(resolved_selector); } Test(add_contextual_data_filter_selector, test_matching_msg_filter_selection) { const gchar cfg_content[] = "filter f_msg {"\ " message(\"testmsg\");"\ "};"; GList *ordered_filters = NULL; ordered_filters = g_list_append(ordered_filters, "f_msg"); AddContextualDataSelector *selector = _create_filter_selector(cfg_content, strlen(cfg_content), ordered_filters); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(selector, msg); cr_assert_str_eq(resolved_selector, "f_msg", "Filter name is resolved."); g_free(resolved_selector); } Test(add_contextual_data_filter_selector, test_matching_host_and_msg_filter_selection) { const gchar cfg_content[] = "filter f_localhost {"\ " host(\"localhost\");"\ "};"\ "filter f_msg {"\ " message(\"testmsg\");"\ "};"; GList *ordered_filters = NULL; ordered_filters = g_list_append(ordered_filters, "f_msg"); ordered_filters = g_list_append(ordered_filters, "f_localhost"); AddContextualDataSelector *selector = _create_filter_selector(cfg_content, strlen(cfg_content), ordered_filters); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(selector, msg); cr_assert_str_eq(resolved_selector, "f_msg", "Message filter name is resolved"); g_free(resolved_selector); } Test(add_contextual_data_filter_selector, test_invalid_filter_config) { const gchar cfg_content[] = "filter f_localhost {"\ " bad-filter-name(\"localhost\");"\ "};"; AddContextualDataSelector *selector = _create_filter_selector(cfg_content, strlen(cfg_content), NULL); cr_assert_null(selector, "Filter selector cannot be initialized."); } syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/test_glob_selector.c000066400000000000000000000100661450431004300300410ustar00rootroot00000000000000/* * Copyright (c) 2019 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "add-contextual-data-glob-selector.h" #include "scratch-buffers.h" #include "string-list.h" #include "logmsg/logmsg.h" #include "cfg.h" #include "apphook.h" static AddContextualDataSelector * _create_glob_selector(const gchar *template_string, const gchar *glob1, ...) { GlobalConfig *cfg = cfg_new_snippet(); LogTemplate *glob_template = log_template_new(cfg, NULL); cr_assert(log_template_compile(glob_template, template_string, NULL)); AddContextualDataSelector *selector = add_contextual_data_glob_selector_new(glob_template); va_list va; va_start(va, glob1); add_contextual_data_selector_init(selector, string_vargs_to_list_va(glob1, va)); va_end(va); AddContextualDataSelector *cloned = add_contextual_data_selector_clone(selector, cfg); add_contextual_data_selector_free(selector); return cloned; } #define _assert_resolved_value(selector, msg, expected_value) \ do { \ gchar *resolved = add_contextual_data_selector_resolve(selector, msg); \ cr_assert_str_eq(resolved, expected_value, "resolved value mismatch: %s != %s", resolved, expected_value); \ g_free(resolved); \ } while (0) #define _assert_resolved_value_is_null(selector, msg) \ do { \ gchar *resolved = add_contextual_data_selector_resolve(selector, msg); \ cr_assert_null(resolved, "unexpected non-NULL value: %s", resolved); \ } while (0) Test(add_contextual_data_glob_selector, glob_selector_finds_first_expr_that_matches_the_expanded_template) { AddContextualDataSelector *selector = _create_glob_selector("$HOST", "local*", "loc*", "lac*", NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_HOST, "localhost", -1); _assert_resolved_value(selector, msg, "local*"); log_msg_set_value(msg, LM_V_HOST, "lacsomething", -1); _assert_resolved_value(selector, msg, "lac*"); log_msg_unref(msg); add_contextual_data_selector_free(selector); } Test(add_contextual_data_glob_selector, glob_selector_finds_first_expr_that_matches_the_expanded_template2) { AddContextualDataSelector *selector = _create_glob_selector("$PROGRAM", "unmatch1", "unmatch2", "good*", NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_PROGRAM, "good", -1); _assert_resolved_value(selector, msg, "good*"); log_msg_set_value(msg, LM_V_HOST, "goodstuff", -1); _assert_resolved_value(selector, msg, "good*"); log_msg_unref(msg); add_contextual_data_selector_free(selector); } Test(add_contextual_data_glob_selector, glob_selector_yields_NULL_if_no_pattern_matches) { AddContextualDataSelector *selector = _create_glob_selector("$PROGRAM", "unmatch1", "unmatch2", "unmatch3", NULL); LogMessage *msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_PROGRAM, "good", -1); _assert_resolved_value_is_null(selector, msg); log_msg_unref(msg); add_contextual_data_selector_free(selector); } static void startup(void) { app_startup(); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(add_contextual_data_glob_selector, .init = startup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/add-contextual-data/tests/test_template_selector.c000066400000000000000000000062451450431004300307350ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "add-contextual-data-template-selector.h" #include "logmsg/logmsg.h" #include "template/macros.h" #include "cfg.h" #include "apphook.h" #include TestSuite(add_contextual_data_template_selector, .init = app_startup, .fini = app_shutdown); static LogMessage * _create_log_msg(const gchar *message, const gchar *host) { LogMessage *msg = NULL; msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, message, -1); log_msg_set_value(msg, LM_V_HOST, host, -1); return msg; } Test(add_contextual_data_template_selector, test_given_empty_selector_when_resolve_then_result_is_null) { AddContextualDataSelector *selector = NULL; LogMessage *msg = _create_log_msg("testmsg", "localhost"); cr_assert_null(add_contextual_data_selector_resolve(selector, msg), "When selector is NULL the resolve should return NULL."); log_msg_unref(msg); } static AddContextualDataSelector * _create_template_selector(const gchar *template_string) { GlobalConfig *cfg = cfg_new_snippet(); LogTemplate *selector_template = log_template_new(cfg, NULL); cr_assert(log_template_compile(selector_template, template_string, NULL)); AddContextualDataSelector *selector = add_contextual_data_template_selector_new(selector_template); add_contextual_data_selector_init(selector, NULL); return selector; } Test(add_contextual_data_template_selector, test_given_template_selector_when_resolve_then_result_is_the_formatted_template_value) { AddContextualDataSelector *selector = _create_template_selector("$HOST"); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(selector, msg); cr_assert_str_eq(resolved_selector, "localhost", ""); log_msg_unref(msg); add_contextual_data_selector_free(selector); } Test(add_contextual_data_template_selector, test_template_selector_cannot_be_resolved) { AddContextualDataSelector *selector = _create_template_selector("$PROGRAM"); LogMessage *msg = _create_log_msg("testmsg", "localhost"); gchar *resolved_selector = add_contextual_data_selector_resolve(selector, msg); cr_assert_str_eq(resolved_selector, "", "No template should be resolved."); log_msg_unref(msg); add_contextual_data_selector_free(selector); } syslog-ng-syslog-ng-4.4.0/modules/afamqp/000077500000000000000000000000001450431004300202705ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afamqp/CMakeLists.txt000066400000000000000000000006401450431004300230300ustar00rootroot00000000000000module_switch(ENABLE_AFAMQP "Enable afamqp module" RabbitMQ_FOUND) if (ENABLE_AFAMQP) set(AFAMQP_SOURCES "afamqp-parser.h" "afamqp.h" "compat/amqp-compat.h" "afamqp-parser.c" "afamqp-plugin.c" "afamqp.c" "compat/amqp-compat.c" ) add_module( TARGET afamqp GRAMMAR afamqp-grammar INCLUDES ${RabbitMQ_INCLUDE_DIR} DEPENDS ${RabbitMQ_LIBRARY} SOURCES ${AFAMQP_SOURCES} ) endif() syslog-ng-syslog-ng-4.4.0/modules/afamqp/Makefile.am000066400000000000000000000022411450431004300223230ustar00rootroot00000000000000if ENABLE_AMQP module_LTLIBRARIES += modules/afamqp/libafamqp.la modules_afamqp_libafamqp_la_CFLAGS = \ $(AM_CFLAGS) \ $(LIBRABBITMQ_CFLAGS) \ -I$(top_srcdir)/modules/afamqp \ -I$(top_builddir)/modules/afamqp modules_afamqp_libafamqp_la_SOURCES = \ modules/afamqp/afamqp-grammar.y \ modules/afamqp/afamqp.c \ modules/afamqp/afamqp.h \ modules/afamqp/compat/amqp-compat.c \ modules/afamqp/compat/amqp-compat.h \ modules/afamqp/afamqp-parser.c \ modules/afamqp/afamqp-parser.h \ modules/afamqp/afamqp-plugin.c modules_afamqp_libafamqp_la_LIBADD = \ $(MODULE_DEPS_LIBS) $(LIBRABBITMQ_LIBS) modules_afamqp_libafamqp_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afamqp_libafamqp_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) \ $(lr_EXTRA_DEPS) modules/afamqp modules/afamqp/ mod-afamqp mod-amqp: \ modules/afamqp/libafamqp.la else modules/afamqp modules/afamqp/ mod-afamqp mod-amqp: endif BUILT_SOURCES += \ modules/afamqp/afamqp-grammar.y \ modules/afamqp/afamqp-grammar.c \ modules/afamqp/afamqp-grammar.h EXTRA_DIST += \ modules/afamqp/afamqp-grammar.ym \ modules/afamqp/CMakeLists.txt .PHONY: modules/afamqp/ mod-afamqp mod-amqp syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp-grammar.ym000066400000000000000000000102371450431004300235330ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2012-2014 Balabit * Copyright (c) 2012-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "afamqp-parser.h" } %code { #include "cfg-grammar-internal.h" } %define api.prefix {afamqp_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_AMQP %token KW_EXCHANGE %token KW_EXCHANGE_DECLARE %token KW_EXCHANGE_TYPE %token KW_PERSISTENT %token KW_VHOST %token KW_ROUTING_KEY %token KW_BODY %token KW_AUTH_METHOD %token KW_PASSWORD %token KW_USERNAME %token KW_MAX_CHANNEL %token KW_FRAME_SIZE %token KW_HEARTBEAT %token KW_CA_FILE %token KW_KEY_FILE %token KW_CERT_FILE %token KW_PEER_VERIFY %token KW_TLS %% start : LL_CONTEXT_DESTINATION KW_AMQP { last_driver = *instance = afamqp_dd_new(configuration); } '(' _inner_dest_context_push afamqp_options _inner_dest_context_pop ')' { YYACCEPT; } ; afamqp_options : afamqp_option afamqp_options | ; afamqp_option : KW_HOST '(' string ')' { afamqp_dd_set_host(last_driver, $3); free($3); } | KW_PORT '(' positive_integer ')' { afamqp_dd_set_port(last_driver, $3); } | KW_VHOST '(' string ')' { afamqp_dd_set_vhost(last_driver, $3); free($3); } | KW_EXCHANGE '(' string ')' { afamqp_dd_set_exchange(last_driver, $3); free($3); } | KW_EXCHANGE_DECLARE '(' yesno ')' { afamqp_dd_set_exchange_declare(last_driver, $3); } | KW_EXCHANGE_TYPE '(' string ')' { afamqp_dd_set_exchange_type(last_driver, $3); free($3); } | KW_ROUTING_KEY '(' template_content ')' { afamqp_dd_set_routing_key(last_driver, $3); } | KW_BODY '(' template_content ')' { afamqp_dd_set_body(last_driver, $3); } | KW_PERSISTENT '(' yesno ')' { afamqp_dd_set_persistent(last_driver, $3); } | KW_AUTH_METHOD '(' string ')' { CHECK_ERROR(afamqp_dd_set_auth_method(last_driver, $3), @3, "unknown auth-method() argument"); free($3); } | KW_USERNAME '(' string ')' { afamqp_dd_set_user(last_driver, $3); free($3); } | KW_PASSWORD '(' string ')' { afamqp_dd_set_password(last_driver, $3); free($3); } | KW_MAX_CHANNEL '(' positive_integer ')' { afamqp_dd_set_max_channel(last_driver, $3); } | KW_FRAME_SIZE '(' positive_integer ')' { afamqp_dd_set_frame_size(last_driver, $3); } | KW_HEARTBEAT '(' nonnegative_integer ')' { afamqp_dd_set_offered_heartbeat(last_driver, $3); } | value_pair_option { afamqp_dd_set_value_pairs(last_driver, $1); } | threaded_dest_driver_general_option | afamqp_tls_option | KW_TLS '(' afamqp_tls_options ')' | { last_template_options = afamqp_dd_get_template_options(last_driver); } template_option ; afamqp_tls_options : afamqp_tls_option afamqp_tls_options | ; afamqp_tls_option : KW_CA_FILE '(' path_check ')' { afamqp_dd_set_ca_file(last_driver, $3); free($3); } | KW_KEY_FILE '(' path_secret ')' { afamqp_dd_set_key_file(last_driver, $3); free($3); } | KW_CERT_FILE '(' path_check ')' { afamqp_dd_set_cert_file(last_driver, $3); free($3); } | KW_PEER_VERIFY '(' yesno ')' { afamqp_dd_set_peer_verify(last_driver, $3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp-parser.c000066400000000000000000000044631450431004300232020ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2012, 2014 Balabit * Copyright (c) 2012, 2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afamqp.h" #include "cfg-parser.h" #include "afamqp-grammar.h" extern int afamqp_debug; int afamqp_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afamqp_keywords[] = { { "amqp", KW_AMQP }, { "vhost", KW_VHOST }, { "host", KW_HOST }, { "port", KW_PORT }, { "exchange", KW_EXCHANGE }, { "exchange_declare", KW_EXCHANGE_DECLARE }, { "exchange_type", KW_EXCHANGE_TYPE }, { "routing_key", KW_ROUTING_KEY }, { "persistent", KW_PERSISTENT }, { "auth_method", KW_AUTH_METHOD }, { "username", KW_USERNAME }, { "password", KW_PASSWORD }, { "max_channel", KW_MAX_CHANNEL }, { "frame_size", KW_FRAME_SIZE }, { "heartbeat", KW_HEARTBEAT }, { "body", KW_BODY }, { "ca_file", KW_CA_FILE }, { "key_file", KW_KEY_FILE }, { "cert_file", KW_CERT_FILE }, { "peer_verify", KW_PEER_VERIFY }, { "tls", KW_TLS }, { NULL } }; CfgParser afamqp_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afamqp_debug, #endif .name = "afamqp", .keywords = afamqp_keywords, .parse = (int (*)(CfgLexer *lexer, gpointer *instance, gpointer)) afamqp_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afamqp_, AFAMQP_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp-parser.h000066400000000000000000000023151450431004300232010ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2012 Balabit * Copyright (c) 2012 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFAMQP_PARSER_H_INCLUDED #define AFAMQP_PARSER_H_INCLUDED #include "cfg-parser.h" #include "afamqp.h" extern CfgParser afamqp_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afamqp_, AFAMQP_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp-plugin.c000066400000000000000000000031551450431004300232010ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * Copyright (c) 2018 Kokan * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afamqp-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afamqp_dd_parser; static Plugin afamqp_plugins[] = { { .type = LL_CONTEXT_DESTINATION, .name = "amqp", .parser = &afamqp_parser } }; const ModuleInfo module_info = { .canonical_name = "afamqp", .version = SYSLOG_NG_VERSION, .description = "The afamqp module provides AMQP destination support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afamqp_plugins, .plugins_len = G_N_ELEMENTS(afamqp_plugins), }; gboolean afamqp_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afamqp_plugins, G_N_ELEMENTS(afamqp_plugins)); return TRUE; } syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp.c000066400000000000000000000567021450431004300217130ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2012-2014 Balabit * Copyright (c) 2012-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afamqp.h" #include "messages.h" #include "stats/stats-registry.h" #include "logmsg/nvtable.h" #include "logqueue.h" #include "scratch-buffers.h" #include "logthrdest/logthrdestdrv.h" #include "timeutils/misc.h" #include "compat/amqp-compat.h" #include #include #include #include typedef struct { LogThreadedDestDriver super; /* Shared between main/writer; only read by the writer, never written */ gchar *exchange; gchar *exchange_type; LogTemplate *routing_key_template; LogTemplate *body_template; gboolean declare; gint persistent; gchar *vhost; gchar *host; gint port; gint auth_method; gchar *user; gchar *password; gint max_channel; gint frame_size; gint offered_heartbeat; gint heartbeat; struct iv_timer heartbeat_timer; LogTemplateOptions template_options; ValuePairs *vp; /* Writer-only stuff */ amqp_connection_state_t conn; amqp_socket_t *sockfd; amqp_table_entry_t *entries; gint32 max_entries; /* SSL props */ gchar *ca_file; gchar *key_file; gchar *cert_file; gboolean peer_verify; } AMQPDestDriver; /* * Configuration */ gboolean afamqp_dd_set_auth_method(LogDriver *d, const gchar *auth_method) { AMQPDestDriver *self = (AMQPDestDriver *) d; if (strcasecmp(auth_method, "plain") == 0) self->auth_method = AMQP_SASL_METHOD_PLAIN; else if (strcasecmp(auth_method, "external") == 0) self->auth_method = AMQP_SASL_METHOD_EXTERNAL; else return FALSE; return TRUE; } void afamqp_dd_set_user(LogDriver *d, const gchar *user) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->user); self->user = g_strdup(user); } void afamqp_dd_set_password(LogDriver *d, const gchar *password) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->password); self->password = g_strdup(password); } void afamqp_dd_set_vhost(LogDriver *d, const gchar *vhost) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->vhost); self->vhost = g_strdup(vhost); } void afamqp_dd_set_host(LogDriver *d, const gchar *host) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->host); self->host = g_strdup(host); } void afamqp_dd_set_port(LogDriver *d, gint port) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->port = (int) port; } void afamqp_dd_set_exchange(LogDriver *d, const gchar *exchange) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->exchange); self->exchange = g_strdup(exchange); } void afamqp_dd_set_exchange_declare(LogDriver *d, gboolean declare) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->declare = declare; } void afamqp_dd_set_exchange_type(LogDriver *d, const gchar *exchange_type) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->exchange_type); self->exchange_type = g_strdup(exchange_type); } void afamqp_dd_set_routing_key(LogDriver *d, LogTemplate *routing_key_template) { AMQPDestDriver *self = (AMQPDestDriver *) d; log_template_unref(self->routing_key_template); self->routing_key_template = routing_key_template; } void afamqp_dd_set_body(LogDriver *d, LogTemplate *body_template) { AMQPDestDriver *self = (AMQPDestDriver *) d; log_template_unref(self->body_template); self->body_template = body_template; } void afamqp_dd_set_persistent(LogDriver *s, gboolean persistent) { AMQPDestDriver *self = (AMQPDestDriver *) s; if (persistent) self->persistent = 2; else self->persistent = 1; } void afamqp_dd_set_value_pairs(LogDriver *d, ValuePairs *vp) { AMQPDestDriver *self = (AMQPDestDriver *) d; value_pairs_unref(self->vp); self->vp = vp; } LogTemplateOptions * afamqp_dd_get_template_options(LogDriver *s) { AMQPDestDriver *self = (AMQPDestDriver *) s; return &self->template_options; } void afamqp_dd_set_ca_file(LogDriver *d, const gchar *cacrt) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->ca_file); self->ca_file = g_strdup(cacrt); } void afamqp_dd_set_key_file(LogDriver *d, const gchar *key) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->key_file); self->key_file = g_strdup(key); } void afamqp_dd_set_cert_file(LogDriver *d, const gchar *usercrt) { AMQPDestDriver *self = (AMQPDestDriver *) d; g_free(self->cert_file); self->cert_file = g_strdup(usercrt); } void afamqp_dd_set_peer_verify(LogDriver *d, gboolean verify) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->peer_verify = verify; } void afamqp_dd_set_max_channel(LogDriver *d, gint max_channel) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->max_channel = max_channel; } void afamqp_dd_set_frame_size(LogDriver *d, gint frame_size) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->frame_size = frame_size; } void afamqp_dd_set_offered_heartbeat(LogDriver *d, gint offered_heartbeat) { AMQPDestDriver *self = (AMQPDestDriver *) d; self->offered_heartbeat = offered_heartbeat; } /* * Utilities */ static const gchar * afamqp_dd_format_stats_key(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb) { AMQPDestDriver *self = (AMQPDestDriver *) s; stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "amqp")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("vhost", self->vhost)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", self->host)); gchar num[64]; g_snprintf(num, sizeof(num), "%u", self->port); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("port", num)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("exchange", self->exchange)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("exchange_type", self->exchange_type)); return NULL; } static const gchar * afamqp_dd_format_persist_name(const LogPipe *s) { const AMQPDestDriver *self = (const AMQPDestDriver *)s; static gchar persist_name[1024]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "afamqp.%s", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "afamqp(%s,%s,%u,%s,%s)", self->vhost, self->host, self->port, self->exchange, self->exchange_type); return persist_name; } static inline void _amqp_connection_deinit(AMQPDestDriver *self) { amqp_destroy_connection(self->conn); self->conn = NULL; } static void _amqp_connection_disconnect(AMQPDestDriver *self) { amqp_channel_close(self->conn, 1, AMQP_REPLY_SUCCESS); amqp_connection_close(self->conn, AMQP_REPLY_SUCCESS); _amqp_connection_deinit(self); } static void afamqp_dd_disconnect(LogThreadedDestDriver *s) { AMQPDestDriver *self = (AMQPDestDriver *)s; if (self->conn != NULL) { _amqp_connection_disconnect(self); } if (iv_timer_registered(&self->heartbeat_timer)) iv_timer_unregister(&self->heartbeat_timer); } static gboolean afamqp_is_ok(AMQPDestDriver *self, const gchar *context, amqp_rpc_reply_t ret) { switch (ret.reply_type) { case AMQP_RESPONSE_NORMAL: break; case AMQP_RESPONSE_NONE: msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", "missing RPC reply type"), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; case AMQP_RESPONSE_LIBRARY_EXCEPTION: { msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", amqp_error_string2(ret.library_error)), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } case AMQP_RESPONSE_SERVER_EXCEPTION: switch (ret.reply.id) { case AMQP_CONNECTION_CLOSE_METHOD: { amqp_connection_close_t *m = (amqp_connection_close_t *) ret.reply.decoded; msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", "server connection error"), evt_tag_int("code", m->reply_code), evt_tag_str("text", m->reply_text.bytes), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } case AMQP_CHANNEL_CLOSE_METHOD: { amqp_channel_close_t *m = (amqp_channel_close_t *) ret.reply.decoded; msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", "server channel error"), evt_tag_int("code", m->reply_code), evt_tag_str("text", m->reply_text.bytes), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } default: msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", "unknown server error"), evt_tag_printf("method_id", "0x%08X", ret.reply.id), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } default: msg_error(context, evt_tag_str("driver", self->super.super.super.id), evt_tag_int("reply_type", ret.reply_type), evt_tag_str("error", "unknown response type"), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } return TRUE; } static gboolean _is_using_tls(AMQPDestDriver *self) { return self->ca_file != NULL; } static gboolean _tls_socket_init(AMQPDestDriver *self) { self->sockfd = amqp_ssl_socket_new(self->conn); if (self->sockfd == NULL) { msg_error("Error connecting to AMQP server while initializing socket with TLS", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } int ca_file_ret = amqp_ssl_socket_set_cacert(self->sockfd, self->ca_file); if (ca_file_ret != AMQP_STATUS_OK) { msg_error("Error connecting to AMQP server while setting ca_file", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", amqp_error_string2(ca_file_ret)), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } if (self->key_file && self->cert_file) { int setkey_ret = amqp_ssl_socket_set_key(self->sockfd, self->cert_file, self->key_file); if (setkey_ret != AMQP_STATUS_OK) { msg_error("Error connecting to AMQP server while setting key_file and cert_file", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", amqp_error_string2(setkey_ret)), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } } amqp_compat_set_verify(self->sockfd, self->peer_verify); return TRUE; } static gboolean _tcp_socket_init(AMQPDestDriver *self) { self->sockfd = amqp_tcp_socket_new(self->conn); if (self->sockfd == NULL) { msg_error("Error connecting to AMQP server while initializing socket", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("time_reopen", self->super.time_reopen)); return FALSE; } return TRUE; } static gboolean afamqp_dd_socket_init(AMQPDestDriver *self) { self->conn = amqp_new_connection(); if (self->conn == NULL) { msg_error("Error allocating AMQP connection."); return FALSE; } if (_is_using_tls(self)) return _tls_socket_init(self); return _tcp_socket_init(self); } static gboolean afamqp_dd_login(AMQPDestDriver *self) { const gchar *identity; amqp_rpc_reply_t ret; switch (self->auth_method) { case AMQP_SASL_METHOD_PLAIN: ret = amqp_login(self->conn, self->vhost, self->max_channel, self->frame_size, self->offered_heartbeat, self->auth_method, self->user, self->password); break; case AMQP_SASL_METHOD_EXTERNAL: // The identity is generally not needed for external authentication, but must be set to // something non-empty otherwise the API call will fail, so just default it to something // meaningless identity = (self->user && self->user[0] != '\0') ? self->user : "."; ret = amqp_login(self->conn, self->vhost, self->max_channel, self->frame_size, self->offered_heartbeat, self->auth_method, identity); break; default: g_assert_not_reached(); return FALSE; } self->heartbeat = amqp_get_heartbeat(self->conn); msg_debug("Amqp heartbeat negotiation", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("heartbeat", self->heartbeat)); return afamqp_is_ok(self, "Error during AMQP login", ret); } static gboolean afamqp_dd_connect(AMQPDestDriver *self) { int sockfd_ret; amqp_rpc_reply_t ret; if (self->conn) { ret = amqp_get_rpc_reply(self->conn); if (ret.reply_type == AMQP_RESPONSE_NORMAL) { return TRUE; } else { _amqp_connection_disconnect(self); } } if(!afamqp_dd_socket_init(self)) goto exception_amqp_dd_connect_failed_init; struct timeval delay; delay.tv_sec = 1; delay.tv_usec = 0; sockfd_ret = amqp_socket_open_noblock(self->sockfd, self->host, self->port, &delay); if (sockfd_ret != AMQP_STATUS_OK) { msg_error("Error connecting to AMQP server", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", amqp_error_string2(sockfd_ret)), evt_tag_int("time_reopen", self->super.time_reopen)); goto exception_amqp_dd_connect_failed_init; } if (!afamqp_dd_login(self)) { goto exception_amqp_dd_connect_failed_init; } amqp_channel_open(self->conn, 1); ret = amqp_get_rpc_reply(self->conn); if (!afamqp_is_ok(self, "Error during AMQP channel open", ret)) { goto exception_amqp_dd_connect_failed_channel; } if (self->declare) { amqp_exchange_declare(self->conn, 1, amqp_cstring_bytes(self->exchange), amqp_cstring_bytes(self->exchange_type), 0, 0, 0, 0, amqp_empty_table); ret = amqp_get_rpc_reply(self->conn); if (!afamqp_is_ok(self, "Error during AMQP exchange declaration", ret)) { goto exception_amqp_dd_connect_failed_exchange; } } msg_debug ("Connecting to AMQP succeeded", evt_tag_str("driver", self->super.super.super.id)); if (self->heartbeat) { iv_validate_now(); self->heartbeat_timer.expires = iv_now; iv_timer_register(&self->heartbeat_timer); } return TRUE; /* Exceptions */ exception_amqp_dd_connect_failed_exchange: amqp_channel_close(self->conn, 1, AMQP_REPLY_SUCCESS); exception_amqp_dd_connect_failed_channel: amqp_connection_close(self->conn, AMQP_REPLY_SUCCESS); exception_amqp_dd_connect_failed_init: _amqp_connection_deinit(self); return FALSE; } /* * Worker thread */ /* TODO escape '\0' when passing down the value */ static gboolean afamqp_vp_foreach(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { amqp_table_entry_t **entries = (amqp_table_entry_t **) ((gpointer *)user_data)[0]; gint *pos = (gint *) ((gpointer *)user_data)[1]; gint32 *max_size = (gint32 *) ((gpointer *)user_data)[2]; if (*pos == *max_size) { *max_size *= 2; *entries = g_renew(amqp_table_entry_t, *entries, *max_size); } (*entries)[*pos].key = amqp_cstring_bytes(strdup(name)); (*entries)[*pos].value.kind = AMQP_FIELD_KIND_UTF8; (*entries)[*pos].value.value.bytes = amqp_cstring_bytes(strdup(value)); (*pos)++; return FALSE; } static LogThreadedResult map_amqp_result_to_log_threaded_result(gint amqp_result) { switch (amqp_result) { case AMQP_STATUS_OK: return LTR_SUCCESS; case AMQP_STATUS_TABLE_TOO_BIG: return LTR_DROP; default: return LTR_ERROR; } } static LogThreadedResult afamqp_worker_publish(AMQPDestDriver *self, LogMessage *msg) { gint pos = 0, amqp_result; amqp_table_t table; amqp_basic_properties_t props; GString *routing_key = scratch_buffers_alloc(); GString *body = scratch_buffers_alloc(); amqp_bytes_t body_bytes = amqp_cstring_bytes(""); gpointer user_data[] = { &self->entries, &pos, &self->max_entries }; LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; value_pairs_foreach(self->vp, afamqp_vp_foreach, msg, &options, user_data); table.num_entries = pos; table.entries = self->entries; props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG | AMQP_BASIC_HEADERS_FLAG; props.content_type = amqp_cstring_bytes("text/plain"); props.delivery_mode = self->persistent; props.headers = table; LogTemplateEvalOptions routing_key_options = {&self->template_options, LTZ_LOCAL, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(self->routing_key_template, msg, &routing_key_options, routing_key); if (self->body_template) { log_template_format(self->body_template, msg, &options, body); body_bytes = amqp_cstring_bytes(body->str); } amqp_result = amqp_basic_publish(self->conn, 1, amqp_cstring_bytes(self->exchange), amqp_cstring_bytes(routing_key->str), 0, 0, &props, body_bytes); if (amqp_result < 0) { msg_error("Network error while inserting into AMQP server", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", amqp_error_string2(amqp_result)), evt_tag_int("time_reopen", self->super.time_reopen)); } while (--pos >= 0) { amqp_bytes_free(self->entries[pos].key); amqp_bytes_free(self->entries[pos].value.value.bytes); } return map_amqp_result_to_log_threaded_result(amqp_result); } static LogThreadedResult afamqp_worker_insert(LogThreadedDestDriver *s, LogMessage *msg) { AMQPDestDriver *self = (AMQPDestDriver *)s; if (!afamqp_dd_connect(self)) return LTR_NOT_CONNECTED; return afamqp_worker_publish(self, msg); } static void _handle_heartbeat(void *cookie) { AMQPDestDriver *self = (AMQPDestDriver *) cookie; amqp_frame_t frame; struct timeval tv = {0, 0}; gint status; while (AMQP_STATUS_OK == (status = amqp_simple_wait_frame_noblock(self->conn, &frame, &tv))); if (AMQP_STATUS_TIMEOUT != status) { msg_error("Unexpected error while reading from amqp server", log_pipe_location_tag((LogPipe *)self), evt_tag_str("error", amqp_error_string2(status))); log_threaded_dest_worker_disconnect(&self->super.worker.instance); return; } iv_validate_now(); self->heartbeat_timer.expires = iv_now; timespec_add_msec(&self->heartbeat_timer.expires, self->heartbeat*1000); iv_timer_register(&self->heartbeat_timer); } /* * Main thread */ static gboolean afamqp_dd_init(LogPipe *s) { AMQPDestDriver *self = (AMQPDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (self->auth_method == AMQP_SASL_METHOD_PLAIN && (!self->user || !self->password)) { msg_error("Error initializing AMQP destination: username and password MUST be set!", evt_tag_str("driver", self->super.super.super.id)); return FALSE; } if (!log_threaded_dest_driver_init_method(s)) return FALSE; log_template_options_init(&self->template_options, cfg); msg_verbose("Initializing AMQP destination", evt_tag_str("vhost", self->vhost), evt_tag_str("host", self->host), evt_tag_int("port", self->port), evt_tag_str("exchange", self->exchange), evt_tag_str("exchange_type", self->exchange_type)); return TRUE; } static void afamqp_dd_free(LogPipe *d) { AMQPDestDriver *self = (AMQPDestDriver *) d; log_template_options_destroy(&self->template_options); g_free(self->exchange); g_free(self->exchange_type); log_template_unref(self->routing_key_template); log_template_unref(self->body_template); g_free(self->user); g_free(self->password); g_free(self->host); g_free(self->vhost); g_free(self->entries); value_pairs_unref(self->vp); g_free(self->ca_file); g_free(self->key_file); g_free(self->cert_file); log_threaded_dest_driver_free(d); } static gboolean afamqp_dd_worker_connect(LogThreadedDestDriver *s) { AMQPDestDriver *self = (AMQPDestDriver *)s; return afamqp_dd_connect(self); } /* * Plugin glue. */ LogDriver * afamqp_dd_new(GlobalConfig *cfg) { AMQPDestDriver *self = g_new0(AMQPDestDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = afamqp_dd_init; self->super.super.super.super.free_fn = afamqp_dd_free; self->super.super.super.super.generate_persist_name = afamqp_dd_format_persist_name; self->super.worker.connect = afamqp_dd_worker_connect; self->super.worker.disconnect = afamqp_dd_disconnect; self->super.worker.insert = afamqp_worker_insert; self->super.format_stats_key = afamqp_dd_format_stats_key; self->super.stats_source = stats_register_type("amqp"); self->routing_key_template = log_template_new(cfg, NULL); log_template_compile_literal_string(self->routing_key_template, ""); LogDriver *driver = &self->super.super.super; afamqp_dd_set_auth_method(driver, "plain"); afamqp_dd_set_vhost(driver, "/"); afamqp_dd_set_host(driver, "127.0.0.1"); afamqp_dd_set_port(driver, 5672); afamqp_dd_set_exchange(driver, "syslog"); afamqp_dd_set_exchange_type(driver, "fanout"); afamqp_dd_set_persistent(driver, TRUE); afamqp_dd_set_exchange_declare(driver, FALSE); afamqp_dd_set_max_channel(driver, AMQP_DEFAULT_MAX_CHANNELS); afamqp_dd_set_frame_size(driver, AMQP_DEFAULT_FRAME_SIZE); self->max_entries = 256; self->entries = g_new(amqp_table_entry_t, self->max_entries); log_template_options_defaults(&self->template_options); afamqp_dd_set_value_pairs(&self->super.super.super, value_pairs_new_default(cfg)); afamqp_dd_set_peer_verify((LogDriver *) self, TRUE); IV_TIMER_INIT(&self->heartbeat_timer); self->heartbeat_timer.cookie = self; self->heartbeat_timer.handler = _handle_heartbeat; return (LogDriver *) self; } syslog-ng-syslog-ng-4.4.0/modules/afamqp/afamqp.h000066400000000000000000000047611450431004300217160ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2012 Balabit * Copyright (c) 2012 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFAMQP_H_INCLUDED #define AFAMQP_H_INCLUDED #include "driver.h" #include "value-pairs/value-pairs.h" LogDriver *afamqp_dd_new(GlobalConfig *cfg); void afamqp_dd_set_host(LogDriver *d, const gchar *host); void afamqp_dd_set_port(LogDriver *d, gint port); void afamqp_dd_set_exchange(LogDriver *d, const gchar *database); void afamqp_dd_set_exchange_declare(LogDriver *d, gboolean declare); void afamqp_dd_set_exchange_type(LogDriver *d, const gchar *exchange_type); void afamqp_dd_set_vhost(LogDriver *d, const gchar *vhost); void afamqp_dd_set_routing_key(LogDriver *d, LogTemplate *routing_key_template); void afamqp_dd_set_body(LogDriver *d, LogTemplate *body_template); void afamqp_dd_set_persistent(LogDriver *d, gboolean persistent); gboolean afamqp_dd_set_auth_method(LogDriver *d, const gchar *auth_method); void afamqp_dd_set_user(LogDriver *d, const gchar *user); void afamqp_dd_set_password(LogDriver *d, const gchar *password); void afamqp_dd_set_max_channel(LogDriver *d, gint max_channel); void afamqp_dd_set_frame_size(LogDriver *d, gint frame_size); void afamqp_dd_set_offered_heartbeat(LogDriver *d, gint heartbeat); void afamqp_dd_set_value_pairs(LogDriver *d, ValuePairs *vp); void afamqp_dd_set_ca_file(LogDriver *d, const gchar *cacrt); void afamqp_dd_set_key_file(LogDriver *d, const gchar *key); void afamqp_dd_set_cert_file(LogDriver *d, const gchar *usercrt); void afamqp_dd_set_peer_verify(LogDriver *d, gboolean verify); LogTemplateOptions *afamqp_dd_get_template_options(LogDriver *s); #endif syslog-ng-syslog-ng-4.4.0/modules/afamqp/compat/000077500000000000000000000000001450431004300215535ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afamqp/compat/amqp-compat.c000066400000000000000000000023731450431004300241430ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #include "compat/amqp-compat.h" #include void amqp_compat_set_verify(amqp_socket_t *self, gboolean verify) { #ifdef SYSLOG_NG_HAVE_AMQP_SSL_SOCKET_SET_VERIFY_PEER amqp_ssl_socket_set_verify_peer(self, verify); amqp_ssl_socket_set_verify_hostname(self, verify); #else amqp_ssl_socket_set_verify(self, verify); #endif } syslog-ng-syslog-ng-4.4.0/modules/afamqp/compat/amqp-compat.h000066400000000000000000000020521450431004300241420ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFAMQP_COMPAT_H_INCLUDED #define AFAMQP_COMPAT_H_INCLUDED #include void amqp_compat_set_verify(amqp_socket_t *self, gboolean verify); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/000077500000000000000000000000001450431004300202515ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/affile/CMakeLists.txt000066400000000000000000000025661450431004300230220ustar00rootroot00000000000000set(AFFILE_SOURCES "affile-dest.h" "affile-dest-internal-queue-filter.h" "affile-parser.h" "affile-source.h" "collection-comparator.h" "directory-monitor-factory.h" "directory-monitor.h" "directory-monitor-poll.h" "file-opener.h" "file-reader.h" "file-specializations.h" "logproto-file-reader.h" "logproto-file-writer.h" "named-pipe.h" "poll-file-changes.h" "poll-multiline-file-changes.h" "stdin.h" "stdout.h" "transport-prockmsg.h" "wildcard-source.h" "wildcard-file-reader.h" "file-list.h" "affile-dest.c" "affile-parser.c" "affile-plugin.c" "affile-source.c" "collection-comparator.c" "directory-monitor.c" "directory-monitor-factory.c" "directory-monitor-poll.c" "file-opener.c" "file-reader.c" "linux-kmsg.c" "logproto-file-reader.c" "logproto-file-writer.c" "named-pipe.c" "poll-file-changes.c" "poll-multiline-file-changes.c" "regular-files.c" "stdin.c" "stdout.c" "transport-prockmsg.c" "wildcard-source.c" "wildcard-file-reader.c" "file-list.c" ) if(SYSLOG_NG_HAVE_INOTIFY) list(APPEND AFFILE_SOURCES "directory-monitor-inotify.h" "directory-monitor-inotify.c" ) endif() add_module( TARGET affile GRAMMAR affile-grammar SOURCES ${AFFILE_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/affile/Makefile.am000066400000000000000000000055471450431004300223200ustar00rootroot00000000000000module_LTLIBRARIES += modules/affile/libaffile.la modules_affile_libaffile_la_SOURCES = \ modules/affile/logproto-file-writer.c \ modules/affile/logproto-file-writer.h \ modules/affile/logproto-file-reader.c \ modules/affile/logproto-file-reader.h \ modules/affile/poll-file-changes.c \ modules/affile/poll-file-changes.h \ modules/affile/poll-multiline-file-changes.c \ modules/affile/poll-multiline-file-changes.h \ modules/affile/transport-prockmsg.c \ modules/affile/transport-prockmsg.h \ modules/affile/file-reader.c \ modules/affile/file-reader.h \ modules/affile/wildcard-file-reader.c \ modules/affile/wildcard-file-reader.h \ modules/affile/wildcard-source.h \ modules/affile/wildcard-source.c \ modules/affile/directory-monitor.h \ modules/affile/directory-monitor.c \ modules/affile/directory-monitor-factory.h \ modules/affile/directory-monitor-factory.c \ modules/affile/collection-comparator.h \ modules/affile/collection-comparator.c \ modules/affile/directory-monitor-poll.h \ modules/affile/directory-monitor-poll.c \ modules/affile/file-opener.c \ modules/affile/file-opener.h \ modules/affile/file-specializations.h \ modules/affile/regular-files.c \ modules/affile/named-pipe.c \ modules/affile/named-pipe.h \ modules/affile/linux-kmsg.c \ modules/affile/stdin.c \ modules/affile/stdin.h \ modules/affile/stdout.c \ modules/affile/stdout.h \ modules/affile/affile-source.c \ modules/affile/affile-source.h \ modules/affile/affile-dest.c \ modules/affile/affile-dest.h \ modules/affile/affile-grammar.y \ modules/affile/affile-parser.c \ modules/affile/affile-parser.h \ modules/affile/affile-plugin.c \ modules/affile/file-list.h \ modules/affile/file-list.c \ modules/affile/affile-dest-internal-queue-filter.h if HAVE_INOTIFY modules_affile_libaffile_la_SOURCES += \ modules/affile/directory-monitor-inotify.h \ modules/affile/directory-monitor-inotify.c else EXTRA_DIST += \ modules/affile/directory-monitor-inotify.h \ modules/affile/directory-monitor-inotify.c endif BUILT_SOURCES += \ modules/affile/affile-grammar.y \ modules/affile/affile-grammar.c \ modules/affile/affile-grammar.h EXTRA_DIST += \ modules/affile/affile-grammar.ym \ modules/affile/CMakeLists.txt modules_affile_libaffile_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/affile \ -I$(top_builddir)/modules/affile modules_affile_libaffile_la_LIBADD = $(MODULE_DEPS_LIBS) $(IVYKIS_LIBS) modules_affile_libaffile_la_LDFLAGS = $(MODULE_LDFLAGS) modules_affile_libaffile_la_DEPENDENCIES= $(MODULE_DEPS_LIBS) modules/affile modules/affile/ mod-affile mod-file: modules/affile/libaffile.la .PHONY: modules/affile/ mod-affile mod-file include modules/affile/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/affile/affile-dest-internal-queue-filter.h000066400000000000000000000021661450431004300270310ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_DEST_INTERNAL_QUEUE_FILTER_H_INCLUDED #define AFFILE_DEST_INTERNAL_QUEUE_FILTER_H_INCLUDED #include "syslog-ng.h" static inline gboolean affile_dw_queue_enabled_for_msg(LogMessage *msg) { return TRUE; } #endif syslog-ng-syslog-ng-4.4.0/modules/affile/affile-dest.c000066400000000000000000000643031450431004300226060ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-opener.h" #include "affile-dest.h" #include "driver.h" #include "messages.h" #include "serialize.h" #include "gprocess.h" #include "stats/stats-registry.h" #include "mainloop-call.h" #include "transport/transport-file.h" #include "logproto-file-writer.h" #include "transport/transport-file.h" #include "transport/transport-pipe.h" #include "logwriter.h" #include "affile-dest-internal-queue-filter.h" #include "file-specializations.h" #include "apphook.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include #include #include #include #include #include #include #include #include /* * Threading notes: * * Apart from standard initialization/deinitialization (normally performed * by the main thread when syslog-ng starts up) the following processes are * performed in various threads. * * - queue runs in the thread of the source thread that generated the message * - if the message is to be written to a not-yet-opened file, a new gets * opened and stored in the writer_hash hashtable (initiated from queue, * but performed in the main thread, but more on that later) * - currently opened destination files are checked regularly and closed * if they are idle for a given amount of time (time_reap) (this is done * in the main thread) * * Some of these operations have to be performed in the main thread, others * are done in the queue call. * * References * ========== * * The AFFileDestDriver instance is registered into the current * configuration, thus its presence is always given, it cannot go away while * syslog-ng is running. * * AFFileDestWriter instances are created dynamically when a new file is * opened. A reference is stored in the writer_hash hashtable. This is then: * - looked up in _queue() (in the source thread) * - cleaned up in reap callback (in the main thread) * * writer_hash is locked (currently a simple mutex) using * AFFileDestDriver->lock. The "queue" method cannot hold the lock while * forwarding it to the next pipe, thus a reference is taken under the * protection of the lock, keeping a the next pipe alive, even if that would * go away in a parallel reaper process. */ static GList *affile_dest_drivers = NULL; struct _AFFileDestWriter { LogPipe super; GMutex lock; AFFileDestDriver *owner; gchar *filename; LogWriter *writer; time_t last_msg_stamp; time_t last_open_stamp; gboolean reopen_pending, queue_pending; }; static gchar * affile_dw_format_persist_name(AFFileDestWriter *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "affile_dw_queue(%s)", self->filename); return persist_name; } static void affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw); static void affile_dw_reap(AFFileDestWriter *self) { AFFileDestDriver *owner = self->owner; main_loop_assert_main_thread(); g_mutex_lock(&owner->lock); if (!log_writer_has_pending_writes((LogWriter *) self->writer) && !self->queue_pending) { msg_verbose("Destination timed out, reaping", evt_tag_str("template", self->owner->filename_template->template_str), evt_tag_str("filename", self->filename)); affile_dd_reap_writer(self->owner, self); } g_mutex_unlock(&owner->lock); } static gboolean affile_dw_reopen(AFFileDestWriter *self) { int fd; struct stat st; LogProtoClient *proto = NULL; msg_verbose("Initializing destination file writer", evt_tag_str("template", self->owner->filename_template->template_str), evt_tag_str("filename", self->filename), evt_tag_str("symlink_as", self->owner->symlink_as)); self->last_open_stamp = self->last_msg_stamp; if (self->owner->overwrite_if_older > 0 && stat(self->filename, &st) == 0 && st.st_mtime < time(NULL) - self->owner->overwrite_if_older) { msg_info("Destination file is older than overwrite_if_older(), overwriting", evt_tag_str("filename", self->filename), evt_tag_int("overwrite_if_older", self->owner->overwrite_if_older)); unlink(self->filename); } FileOpenerResult open_result = file_opener_open_fd(self->owner->file_opener, self->filename, AFFILE_DIR_WRITE, &fd); if (open_result == FILE_OPENER_RESULT_SUCCESS) { if (self->owner->symlink_as != NULL) file_opener_symlink(self->owner->file_opener, self->owner->symlink_as, self->filename); LogTransport *transport = file_opener_construct_transport(self->owner->file_opener, fd); proto = file_opener_construct_dst_proto(self->owner->file_opener, transport, &self->owner->writer_options.proto_options.super); } else if (open_result == FILE_OPENER_RESULT_ERROR_PERMANENT) { return FALSE; } else { msg_error("Error opening file for writing", evt_tag_str("filename", self->filename), evt_tag_error(EVT_TAG_OSERROR)); } log_writer_reopen(self->writer, proto); return TRUE; } static void _init_stats_key_builders(AFFileDestWriter *self, StatsClusterKeyBuilder **writer_sck_builder, StatsClusterKeyBuilder **driver_sck_builder, StatsClusterKeyBuilder **queue_sck_builder) { *writer_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*writer_sck_builder, stats_cluster_label("driver", "file")); stats_cluster_key_builder_add_legacy_label(*writer_sck_builder, stats_cluster_label("filename", self->filename)); *driver_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("driver", "file")); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("id", self->owner->super.super.id)); stats_cluster_key_builder_add_legacy_label(*driver_sck_builder, stats_cluster_label("filename", self->filename)); stats_cluster_key_builder_set_legacy_alias(*driver_sck_builder, self->owner->writer_options.stats_source | SCS_DESTINATION, self->owner->super.super.id, self->filename); *queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("driver", "file")); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("id", self->owner->super.super.id)); stats_cluster_key_builder_add_legacy_label(*queue_sck_builder, stats_cluster_label("filename", self->filename)); } static gboolean affile_dw_init(LogPipe *s) { AFFileDestWriter *self = (AFFileDestWriter *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!self->writer) { self->writer = log_writer_new(self->owner->writer_flags, cfg); } StatsClusterKeyBuilder *writer_sck_builder; StatsClusterKeyBuilder *driver_sck_builder; StatsClusterKeyBuilder *queue_sck_builder; _init_stats_key_builders(self, &writer_sck_builder, &driver_sck_builder, &queue_sck_builder); log_pipe_set_options((LogPipe *) self->writer, &s->options); log_writer_set_options(self->writer, s, &self->owner->writer_options, self->owner->super.super.id, writer_sck_builder); gint stats_level = log_pipe_is_internal(&self->super) ? STATS_LEVEL3 : self->owner->writer_options.stats_level; LogQueue *queue = log_dest_driver_acquire_queue(&self->owner->super, affile_dw_format_persist_name(self), stats_level, driver_sck_builder, queue_sck_builder); log_writer_set_queue(self->writer, queue); stats_cluster_key_builder_free(driver_sck_builder); stats_cluster_key_builder_free(queue_sck_builder); if (!log_pipe_init((LogPipe *) self->writer)) { msg_error("Error initializing log writer"); goto error; } log_pipe_append(&self->super, (LogPipe *) self->writer); if (!affile_dw_reopen(self)) { log_pipe_deinit((LogPipe *) self->writer); log_writer_set_queue(self->writer, NULL); goto error; } return TRUE; error: log_pipe_unref((LogPipe *) self->writer); self->writer = NULL; return FALSE; } static gboolean affile_dw_deinit(LogPipe *s) { AFFileDestWriter *self = (AFFileDestWriter *) s; main_loop_assert_main_thread(); if (self->writer) { log_pipe_deinit((LogPipe *) self->writer); } log_writer_set_queue(self->writer, NULL); return TRUE; } /* * NOTE: the caller (e.g. AFFileDestDriver) holds a reference to @self, thus * @self may _never_ be freed, even if the reaper timer is elapsed in the * main thread. */ static void affile_dw_queue(LogPipe *s, LogMessage *lm, const LogPathOptions *path_options) { if (!affile_dw_queue_enabled_for_msg(lm)) { log_msg_drop(lm, path_options, AT_PROCESSED); return; } AFFileDestWriter *self = (AFFileDestWriter *) s; g_mutex_lock(&self->lock); self->last_msg_stamp = cached_g_current_time_sec(); if (self->last_open_stamp == 0) self->last_open_stamp = self->last_msg_stamp; if (!log_writer_opened(self->writer) && !self->reopen_pending && (self->last_open_stamp < self->last_msg_stamp - self->owner->writer_options.time_reopen)) { self->reopen_pending = TRUE; /* if the file couldn't be opened, try it again every time_reopen seconds */ g_mutex_unlock(&self->lock); affile_dw_reopen(self); g_mutex_lock(&self->lock); self->reopen_pending = FALSE; } g_mutex_unlock(&self->lock); log_pipe_forward_msg(&self->super, lm, path_options); } static void affile_dw_set_owner(AFFileDestWriter *self, AFFileDestDriver *owner) { GlobalConfig *cfg = log_pipe_get_config(&owner->super.super.super); if (self->owner) log_pipe_unref(&self->owner->super.super.super); log_pipe_ref(&owner->super.super.super); self->owner = owner; self->super.expr_node = owner->super.super.super.expr_node; log_pipe_set_options(&self->super, &owner->super.super.super.options); log_pipe_set_config(&self->super, cfg); if (self->writer) { StatsClusterKeyBuilder *writer_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(writer_sck_builder, stats_cluster_label("driver", "file")); stats_cluster_key_builder_add_legacy_label(writer_sck_builder, stats_cluster_label("filename", self->filename)); log_pipe_set_config((LogPipe *) self->writer, cfg); log_writer_set_options(self->writer, &self->super, &owner->writer_options, self->owner->super.super.id, writer_sck_builder); } } static void affile_dw_free(LogPipe *s) { AFFileDestWriter *self = (AFFileDestWriter *) s; log_pipe_unref((LogPipe *) self->writer); g_mutex_clear(&self->lock); self->writer = NULL; g_free(self->filename); log_pipe_unref(&self->owner->super.super.super); log_pipe_free_method(s); } static void affile_dw_notify(LogPipe *s, gint notify_code, gpointer user_data) { AFFileDestWriter *self = (AFFileDestWriter *)s; switch(notify_code) { case NC_REOPEN_REQUIRED: affile_dw_reopen(self); break; case NC_CLOSE: affile_dw_reap(self); break; default: break; } } static AFFileDestWriter * affile_dw_new(const gchar *filename, GlobalConfig *cfg) { AFFileDestWriter *self = g_new0(AFFileDestWriter, 1); log_pipe_init_instance(&self->super, cfg); self->super.init = affile_dw_init; self->super.deinit = affile_dw_deinit; self->super.free_fn = affile_dw_free; self->super.queue = affile_dw_queue; self->super.notify = affile_dw_notify; /* we have to take care about freeing filename later. This avoids a move of the filename. */ self->filename = g_strdup(filename); g_mutex_init(&self->lock); return self; } static void affile_dw_reopen_writer(gpointer key, gpointer value, gpointer user_data) { AFFileDestWriter *writer = (AFFileDestWriter *) value; affile_dw_reopen(writer); } static void affile_dd_reopen_all_writers(gpointer data, gpointer user_data) { AFFileDestDriver *driver = (AFFileDestDriver *) data; if (driver->single_writer) affile_dw_reopen(driver->single_writer); else if (driver->writer_hash) g_hash_table_foreach(driver->writer_hash, affile_dw_reopen_writer, NULL); } static void affile_dd_register_reopen_hook(gint hook_type, gpointer user_data) { g_list_foreach(affile_dest_drivers, affile_dd_reopen_all_writers, NULL); } void affile_dd_set_create_dirs(LogDriver *s, gboolean create_dirs) { AFFileDestDriver *self = (AFFileDestDriver *) s; self->file_opener_options.create_dirs = create_dirs; } void affile_dd_set_overwrite_if_older(LogDriver *s, gint overwrite_if_older) { AFFileDestDriver *self = (AFFileDestDriver *) s; self->overwrite_if_older = overwrite_if_older; } void affile_dd_set_symlink_as(LogDriver *s, const gchar *symlink_as) { AFFileDestDriver *self = (AFFileDestDriver *) s; g_free(self->symlink_as); self->symlink_as = g_strdup(symlink_as); } void affile_dd_set_fsync(LogDriver *s, gboolean use_fsync) { AFFileDestDriver *self = (AFFileDestDriver *) s; self->use_fsync = use_fsync; } void affile_dd_set_time_reap(LogDriver *s, gint time_reap) { AFFileDestDriver *self = (AFFileDestDriver *) s; log_proto_client_options_set_timeout(&self->writer_options.proto_options.super, time_reap); } static gint affile_dd_get_time_reap(AFFileDestDriver *self) { return log_proto_client_options_get_timeout(&self->writer_options.proto_options.super); } static inline const gchar * affile_dd_format_persist_name(const LogPipe *s) { const AFFileDestDriver *self = (const AFFileDestDriver *)s; static gchar persist_name[1024]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "affile_dd.%s.writers", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "affile_dd_writers(%s)", self->filename_template->template_str); return persist_name; } /* DestDriver lock must be held before calling this function */ static void affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw) { LogWriter *writer = (LogWriter *)dw->writer; main_loop_assert_main_thread(); if (self->filename_is_a_template) { /* remove from hash table */ g_hash_table_remove(self->writer_hash, dw->filename); } else { g_assert(dw == self->single_writer); self->single_writer = NULL; } LogQueue *queue = log_writer_get_queue(writer); log_pipe_deinit(&dw->super); log_dest_driver_release_queue(&self->super, queue); log_pipe_unref(&dw->super); } /** * affile_dd_reuse_writer: * * This function is called as a g_hash_table_foreach() callback to set the * owner of each writer, previously connected to an AFileDestDriver instance * in an earlier configuration. This way AFFileDestWriter instances are * remembered across reloads. * **/ static void affile_dd_reuse_writer(gpointer key, gpointer value, gpointer user_data) { AFFileDestDriver *self = (AFFileDestDriver *) user_data; AFFileDestWriter *writer = (AFFileDestWriter *) value; affile_dw_set_owner(writer, self); if (!log_pipe_init(&writer->super)) { affile_dw_set_owner(writer, NULL); log_pipe_unref(&writer->super); g_hash_table_remove(self->writer_hash, key); } } static gboolean affile_dd_init(LogPipe *s) { AFFileDestDriver *self = (AFFileDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_dest_driver_init_method(s)) return FALSE; file_opener_options_init(&self->file_opener_options, cfg); file_opener_set_options(self->file_opener, &self->file_opener_options); log_writer_options_init(&self->writer_options, cfg, 0); if (affile_dd_get_time_reap(self) == -1) affile_dd_set_time_reap(&self->super.super, cfg->time_reap); if (self->filename_is_a_template) { self->writer_hash = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(s)); if (self->writer_hash) g_hash_table_foreach(self->writer_hash, affile_dd_reuse_writer, self); } else { self->single_writer = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(s)); if (self->single_writer) { affile_dw_set_owner(self->single_writer, self); if (!log_pipe_init(&self->single_writer->super)) { log_pipe_unref(&self->single_writer->super); return FALSE; } } } return TRUE; } /** * This is registered as a destroy-notify callback for an AFFileDestWriter * instance. It destructs and frees the writer instance. **/ static void affile_dd_destroy_writer(gpointer value) { AFFileDestWriter *writer = (AFFileDestWriter *) value; main_loop_assert_main_thread(); log_pipe_deinit(&writer->super); log_pipe_unref(&writer->super); } /* * This function is called as a g_hash_table_foreach_remove() callback to * free the specific AFFileDestWriter instance in the hashtable. */ static gboolean affile_dd_destroy_writer_hr(gpointer key, gpointer value, gpointer user_data) { affile_dd_destroy_writer(value); return TRUE; } /** * affile_dd_destroy_writer_hash: * @value: GHashTable instance passed as a generic pointer * * Destroy notify callback for the GHashTable storing AFFileDestWriter instances. **/ static void affile_dd_destroy_writer_hash(gpointer value) { GHashTable *writer_hash = (GHashTable *) value; g_hash_table_foreach_remove(writer_hash, affile_dd_destroy_writer_hr, NULL); g_hash_table_destroy(writer_hash); } static void affile_dd_deinit_writer(gpointer key, gpointer value, gpointer user_data) { log_pipe_deinit((LogPipe *) value); } static gboolean affile_dd_deinit(LogPipe *s) { AFFileDestDriver *self = (AFFileDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); /* NOTE: we free all AFFileDestWriter instances here as otherwise we'd * have circular references between AFFileDestDriver and file writers */ if (self->single_writer) { g_assert(self->writer_hash == NULL); log_pipe_deinit(&self->single_writer->super); cfg_persist_config_add(cfg, affile_dd_format_persist_name(s), self->single_writer, affile_dd_destroy_writer); self->single_writer = NULL; } else if (self->writer_hash) { g_assert(self->single_writer == NULL); g_hash_table_foreach(self->writer_hash, affile_dd_deinit_writer, NULL); cfg_persist_config_add(cfg, affile_dd_format_persist_name(s), self->writer_hash, affile_dd_destroy_writer_hash); self->writer_hash = NULL; } if (!log_dest_driver_deinit_method(s)) return FALSE; return TRUE; } /* * This function is ran in the main thread whenever a writer is not yet * instantiated. Returns a reference to the newly constructed LogPipe * instance where the caller needs to forward its message. */ static LogPipe * affile_dd_open_writer(gpointer args[]) { AFFileDestDriver *self = args[0]; AFFileDestWriter *next; main_loop_assert_main_thread(); if (!self->filename_is_a_template) { if (!self->single_writer) { next = affile_dw_new(log_template_get_literal_value(self->filename_template, NULL), log_pipe_get_config(&self->super.super.super)); affile_dw_set_owner(next, self); if (next && log_pipe_init(&next->super)) { log_pipe_ref(&next->super); g_mutex_lock(&self->lock); self->single_writer = next; g_mutex_unlock(&self->lock); } else { log_pipe_unref(&next->super); next = NULL; } } else { next = self->single_writer; log_pipe_ref(&next->super); } } else { GString *filename = args[1]; /* hash table construction is serialized, as we only do that in the main thread. */ if (!self->writer_hash) self->writer_hash = g_hash_table_new(g_str_hash, g_str_equal); /* we don't need to lock the hashtable as it is only written in * the main thread, which we're running right now. lookups in * other threads must be locked. writers must be locked even in * this thread to exclude lookups in other threads. */ next = g_hash_table_lookup(self->writer_hash, filename->str); if (!next) { next = affile_dw_new(filename->str, log_pipe_get_config(&self->super.super.super)); affile_dw_set_owner(next, self); if (!log_pipe_init(&next->super)) { log_pipe_unref(&next->super); next = NULL; } else { log_pipe_ref(&next->super); g_mutex_lock(&self->lock); g_hash_table_insert(self->writer_hash, next->filename, next); g_mutex_unlock(&self->lock); } } else { log_pipe_ref(&next->super); } } if (next) { next->queue_pending = TRUE; /* we're returning a reference */ return &next->super; } return NULL; } static void affile_dd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { AFFileDestDriver *self = (AFFileDestDriver *) s; AFFileDestWriter *next; gpointer args[2] = { self, NULL }; if (!self->filename_is_a_template) { /* we need to lock single_writer in order to get a reference and * make sure it is not a stale pointer by the time we ref it */ g_mutex_lock(&self->lock); if (!self->single_writer) { g_mutex_unlock(&self->lock); next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE); } else { next = self->single_writer; next->queue_pending = TRUE; log_pipe_ref(&next->super); g_mutex_unlock(&self->lock); } } else { GString *filename; filename = g_string_sized_new(32); LogTemplateEvalOptions options = {&self->writer_options.template_options, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; log_template_format(self->filename_template, msg, &options, filename); g_mutex_lock(&self->lock); if (self->writer_hash) next = g_hash_table_lookup(self->writer_hash, filename->str); else next = NULL; if (next) { log_pipe_ref(&next->super); next->queue_pending = TRUE; g_mutex_unlock(&self->lock); } else { g_mutex_unlock(&self->lock); args[1] = filename; next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE); } g_string_free(filename, TRUE); } if (next) { log_msg_add_ack(msg, path_options); log_pipe_queue(&next->super, log_msg_ref(msg), path_options); next->queue_pending = FALSE; log_pipe_unref(&next->super); } log_dest_driver_queue_method(s, msg, path_options); } static void affile_dd_free(LogPipe *s) { AFFileDestDriver *self = (AFFileDestDriver *) s; g_mutex_clear(&self->lock); affile_dest_drivers = g_list_remove(affile_dest_drivers, self); /* NOTE: this must be NULL as deinit has freed it, otherwise we'd have circular references */ g_assert(self->single_writer == NULL && self->writer_hash == NULL); log_template_unref(self->filename_template); log_writer_options_destroy(&self->writer_options); file_opener_options_deinit(&self->file_opener_options); file_opener_free(self->file_opener); g_free(self->symlink_as); log_dest_driver_free(s); } AFFileDestDriver * affile_dd_new_instance(LogTemplate *filename_template, GlobalConfig *cfg) { AFFileDestDriver *self = g_new0(AFFileDestDriver, 1); log_dest_driver_init_instance(&self->super, cfg); self->super.super.super.init = affile_dd_init; self->super.super.super.deinit = affile_dd_deinit; self->super.super.super.queue = affile_dd_queue; self->super.super.super.free_fn = affile_dd_free; self->super.super.super.generate_persist_name = affile_dd_format_persist_name; self->filename_template = filename_template; log_writer_options_defaults(&self->writer_options); self->writer_options.mark_mode = MM_NONE; self->writer_options.stats_level = STATS_LEVEL1; self->writer_flags = LW_FORMAT_FILE; if (!log_template_is_literal_string(filename_template)) { self->filename_is_a_template = TRUE; } file_opener_options_defaults(&self->file_opener_options); affile_dd_set_time_reap(&self->super.super, self->filename_is_a_template ? -1 : 0); g_mutex_init(&self->lock); affile_dest_drivers = g_list_append(affile_dest_drivers, self); return self; } LogDriver * affile_dd_new(LogTemplate *filename_template, GlobalConfig *cfg) { AFFileDestDriver *self = affile_dd_new_instance(filename_template, cfg); self->writer_flags |= LW_SOFT_FLOW_CONTROL; self->writer_options.stats_source = stats_register_type("file"); self->file_opener = file_opener_for_regular_dest_files_new(&self->writer_options, &self->use_fsync); return &self->super.super; } void affile_dd_global_init(void) { static gboolean initialized = FALSE; if (!initialized) { register_application_hook(AH_REOPEN_FILES, affile_dd_register_reopen_hook, NULL, AHM_RUN_REPEAT); initialized = TRUE; } } syslog-ng-syslog-ng-4.4.0/modules/affile/affile-dest.h000066400000000000000000000043521450431004300226110ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_DEST_H_INCLUDED #define AFFILE_DEST_H_INCLUDED #include "driver.h" #include "logwriter.h" #include "file-opener.h" typedef struct _AFFileDestWriter AFFileDestWriter; typedef struct _AFFileDestDriver { LogDestDriver super; GMutex lock; LogTemplate *filename_template; AFFileDestWriter *single_writer; gboolean filename_is_a_template; gboolean template_escape; gboolean use_fsync; FileOpenerOptions file_opener_options; FileOpener *file_opener; TimeZoneInfo *local_time_zone_info; LogWriterOptions writer_options; guint32 writer_flags; GHashTable *writer_hash; gint overwrite_if_older; gchar *symlink_as; gboolean use_time_recvd; } AFFileDestDriver; AFFileDestDriver *affile_dd_new_instance(LogTemplate *filename_template, GlobalConfig *cfg); LogDriver *affile_dd_new(LogTemplate *filename_template, GlobalConfig *cfg); void affile_dd_set_create_dirs(LogDriver *s, gboolean create_dirs); void affile_dd_set_fsync(LogDriver *s, gboolean enable); void affile_dd_set_overwrite_if_older(LogDriver *s, gint overwrite_if_older); void affile_dd_set_symlink_as(LogDriver *s, const gchar *symlink_as); void affile_dd_set_local_time_zone(LogDriver *s, const gchar *local_time_zone); void affile_dd_set_time_reap(LogDriver *s, gint time_reap); void affile_dd_global_init(void); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/affile-grammar.ym000066400000000000000000000242511450431004300234760ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "affile-parser.h" } %code { #include "file-opener.h" #include "affile-source.h" #include "wildcard-source.h" #include "affile-dest.h" #include "cfg-parser.h" #include "syslog-names.h" #include "messages.h" #include "plugin.h" #include "cfg-grammar-internal.h" #include "stdin.h" #include "stdout.h" #include "named-pipe.h" #include FileReaderOptions *last_file_reader_options; LogProtoFileReaderOptions *last_log_proto_options; MultiLineOptions *last_multi_line_options; WildcardSourceDriver *last_legacy_wildcard_src_driver; static void affile_grammar_set_file_source_driver(AFFileSourceDriver *sd) { last_driver = &sd->super.super; last_file_reader_options = &sd->file_reader_options; last_reader_options = &last_file_reader_options->reader_options; last_file_perm_options = &sd->file_opener_options.file_perm_options; last_log_proto_options = file_reader_options_get_log_proto_options(last_file_reader_options); last_multi_line_options = &last_log_proto_options->multi_line_options; } static void affile_grammar_set_wildcard_file_source_driver(WildcardSourceDriver *sd) { last_driver = &sd->super.super; last_file_reader_options = &sd->file_reader_options; last_reader_options = &last_file_reader_options->reader_options; last_file_perm_options = &sd->file_opener_options.file_perm_options; last_log_proto_options = file_reader_options_get_log_proto_options(last_file_reader_options); last_multi_line_options = &last_log_proto_options->multi_line_options; } } %define api.prefix {affile_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_FILE %token KW_PIPE %token KW_FSYNC %token KW_FOLLOW_FREQ %token KW_OVERWRITE_IF_OLDER %token KW_SYMLINK_AS %token KW_MULTI_LINE_TIMEOUT %token KW_TIME_REAP %token KW_WILDCARD_FILE %token KW_BASE_DIR %token KW_FILENAME_PATTERN %token KW_RECURSIVE %token KW_MAX_FILES %token KW_MONITOR_METHOD %token KW_FORCE_DIRECTORY_POLLING %token KW_STDIN %token KW_STDOUT %type source_affile %type source_affile_params %type source_afpipe_params %type source_stdin_params %type dest_affile %type dest_affile_params %type dest_afpipe_params %type dest_stdout_params %% start : LL_CONTEXT_SOURCE source_affile { YYACCEPT; } | LL_CONTEXT_DESTINATION dest_affile { YYACCEPT; } ; source_affile : KW_FILE '(' _inner_src_context_push source_affile_params _inner_src_context_pop ')' { $$ = $4; } | KW_PIPE '(' _inner_src_context_push source_afpipe_params _inner_src_context_pop ')' { $$ = $4; } | KW_STDIN '(' _inner_src_context_push source_stdin_params _inner_src_context_pop ')' { $$ = $4; } | KW_WILDCARD_FILE { WildcardSourceDriver *sd = (WildcardSourceDriver *) wildcard_sd_new(configuration);; *instance = &sd->super.super; affile_grammar_set_wildcard_file_source_driver(sd); } '(' _inner_src_context_push source_wildcard_params _inner_src_context_pop ')' { $$ = last_driver; } ; source_wildcard_params : source_wildcard_options ; source_wildcard_options : source_wildcard_option source_wildcard_options | ; source_stdin_params : { AFFileSourceDriver *sd = (AFFileSourceDriver *) stdin_sd_new(configuration); *instance = &sd->super.super; affile_grammar_set_file_source_driver(sd); } source_affile_options { $$ = last_driver; } ; source_affile_params : string { if (!affile_is_legacy_wildcard_source($1)) { AFFileSourceDriver *sd = (AFFileSourceDriver *) affile_sd_new($1, configuration); *instance = &sd->super.super; affile_grammar_set_file_source_driver(sd); } else { WildcardSourceDriver *sd = (WildcardSourceDriver *) wildcard_sd_legacy_new($1, configuration); last_legacy_wildcard_src_driver = sd; *instance = &sd->super.super; affile_grammar_set_wildcard_file_source_driver(sd); } } source_affile_options { $$ = last_driver; last_legacy_wildcard_src_driver = NULL; free($1); } ; source_affile_options : source_affile_option source_affile_options | source_legacy_wildcard_option source_affile_options | ; source_affile_option : KW_FOLLOW_FREQ '(' nonnegative_float ')' { file_reader_options_set_follow_freq(last_file_reader_options, (long) ($3 * 1000)); } | KW_PAD_SIZE '(' nonnegative_integer ')' { last_log_proto_options->pad_size = $3; } | multi_line_option | multi_line_timeout | file_perm_option | source_reader_option | source_driver_option ; source_wildcard_option : KW_BASE_DIR '(' string ')' { wildcard_sd_set_base_dir(last_driver, $3); free($3); } | KW_FILENAME_PATTERN '(' string ')' { wildcard_sd_set_filename_pattern(last_driver, $3); free($3); } | KW_RECURSIVE '(' yesno ')' { wildcard_sd_set_recursive(last_driver, $3); } | KW_MAX_FILES '(' positive_integer ')' { wildcard_sd_set_max_files(last_driver, $3); } | KW_MONITOR_METHOD '(' string ')' { CHECK_ERROR(wildcard_sd_set_monitor_method(last_driver, $3), @3, "Invalid monitor-method"); free($3); } | source_affile_option ; source_legacy_wildcard_option : KW_FORCE_DIRECTORY_POLLING '(' yesno ')' { CHECK_ERROR(last_legacy_wildcard_src_driver, @1, "Invalid option, force-directory-polling() can only be used in legacy wildcard file sources"); wildcard_sd_set_monitor_method(&last_legacy_wildcard_src_driver->super.super, $3 ? "poll" : "auto"); } | KW_RECURSIVE '(' yesno ')' { CHECK_ERROR(last_legacy_wildcard_src_driver, @1, "Invalid option, recursive() can only be used in legacy wildcard file sources"); wildcard_sd_set_recursive(&last_legacy_wildcard_src_driver->super.super, $3); } ; source_afpipe_params : string { AFFileSourceDriver *sd = (AFFileSourceDriver *) pipe_sd_new($1, configuration); *instance = &sd->super.super; affile_grammar_set_file_source_driver(sd); } source_afpipe_options { $$ = last_driver; free($1); } ; source_afpipe_options : source_afpipe_option source_afpipe_options | ; source_afpipe_option : KW_OPTIONAL '(' yesno ')' { last_driver->optional = $3; } | KW_PAD_SIZE '(' nonnegative_integer ')' { last_log_proto_options->pad_size = $3; } | KW_CREATE_DIRS '(' yesno ')' { pipe_sd_set_create_dirs(last_driver, $3); } | multi_line_option | file_perm_option | source_reader_option | source_driver_option ; multi_line_timeout : KW_MULTI_LINE_TIMEOUT '(' nonnegative_integer ')' { file_reader_options_set_multi_line_timeout(last_file_reader_options, ($3 * 1000)); } ; dest_affile : KW_FILE '(' _inner_dest_context_push dest_affile_params _inner_dest_context_pop ')' { $$ = $4; } | KW_PIPE '(' _inner_dest_context_push dest_afpipe_params _inner_dest_context_pop ')' { $$ = $4; } | KW_STDOUT '(' _inner_dest_context_push dest_stdout_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_affile_params : template_content { last_driver = *instance = affile_dd_new($1, configuration); last_writer_options = &((AFFileDestDriver *) last_driver)->writer_options; last_file_perm_options = &((AFFileDestDriver *) last_driver)->file_opener_options.file_perm_options; } dest_affile_options { $$ = last_driver; } ; dest_affile_options : dest_affile_option dest_affile_options | ; dest_affile_option : dest_writer_option | dest_driver_option | file_perm_option | KW_OPTIONAL '(' yesno ')' { last_driver->optional = $3; } | KW_OVERWRITE_IF_OLDER '(' nonnegative_integer ')' { affile_dd_set_overwrite_if_older(last_driver, $3); } | KW_SYMLINK_AS '(' string ')' { affile_dd_set_symlink_as(last_driver, $3); } | KW_FSYNC '(' yesno ')' { affile_dd_set_fsync(last_driver, $3); } | dest_affile_common_option ; dest_afpipe_params : template_content { last_driver = *instance = pipe_dd_new($1, configuration); last_writer_options = &((AFFileDestDriver *) last_driver)->writer_options; last_file_perm_options = &((AFFileDestDriver *) last_driver)->file_opener_options.file_perm_options; } dest_afpipe_options { $$ = last_driver; } ; dest_afpipe_options : dest_afpipe_option dest_afpipe_options | ; dest_afpipe_option : dest_writer_option | dest_driver_option | file_perm_option | dest_affile_common_option ; dest_affile_common_option : KW_TIME_REAP '(' nonnegative_integer ')' { affile_dd_set_time_reap(last_driver, $3); } | KW_CREATE_DIRS '(' yesno ')' { affile_dd_set_create_dirs(last_driver, $3); } ; dest_stdout_params : { last_driver = *instance = stdout_dd_new(configuration); last_writer_options = &((AFFileDestDriver *) last_driver)->writer_options; last_file_perm_options = &((AFFileDestDriver *) last_driver)->file_opener_options.file_perm_options; } dest_stdout_options ; dest_stdout_options : dest_stdout_option dest_stdout_options | ; dest_stdout_option : dest_writer_option | dest_driver_option ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/affile/affile-parser.c000066400000000000000000000046211450431004300231400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "driver.h" #include "cfg-parser.h" #include "affile-grammar.h" extern int affile_debug; int affile_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword affile_keywords[] = { { "file", KW_FILE }, { "fifo", KW_PIPE }, { "pipe", KW_PIPE }, { "stdin", KW_STDIN }, { "stdout", KW_STDOUT }, { "wildcard_file", KW_WILDCARD_FILE }, { "base_dir", KW_BASE_DIR }, { "filename_pattern", KW_FILENAME_PATTERN }, { "recursive", KW_RECURSIVE }, { "max_files", KW_MAX_FILES }, { "monitor_method", KW_MONITOR_METHOD }, { "force_directory_polling", KW_FORCE_DIRECTORY_POLLING, KWS_OBSOLETE, "Use wildcard-file(monitor-method())" }, { "fsync", KW_FSYNC }, { "remove_if_older", KW_OVERWRITE_IF_OLDER, KWS_OBSOLETE, "overwrite_if_older" }, { "overwrite_if_older", KW_OVERWRITE_IF_OLDER }, { "symlink_as", KW_SYMLINK_AS }, { "follow_freq", KW_FOLLOW_FREQ }, { "multi_line_timeout", KW_MULTI_LINE_TIMEOUT }, { "time_reap", KW_TIME_REAP }, { NULL } }; CfgParser affile_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &affile_debug, #endif .name = "affile", .keywords = affile_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) affile_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(affile_, AFFILE_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/affile/affile-parser.h000066400000000000000000000022261450431004300231440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_PARSER_H_INCLUDED #define AFFILE_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser affile_parser; CFG_PARSER_DECLARE_LEXER_BINDING(affile_, AFFILE_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/affile/affile-plugin.c000066400000000000000000000043551450431004300231460ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" #include "affile-dest.h" extern CfgParser affile_parser; static Plugin affile_plugins[] = { { .type = LL_CONTEXT_SOURCE, .name = "file", .parser = &affile_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "pipe", .parser = &affile_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "wildcard_file", .parser = &affile_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "stdin", .parser = &affile_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "file", .parser = &affile_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "pipe", .parser = &affile_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "stdout", .parser = &affile_parser, }, }; gboolean affile_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, affile_plugins, G_N_ELEMENTS(affile_plugins)); affile_dd_global_init(); return TRUE; } const ModuleInfo module_info = { .canonical_name = "affile", .version = SYSLOG_NG_VERSION, .description = "The affile module provides file source & destination support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = affile_plugins, .plugins_len = G_N_ELEMENTS(affile_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/affile/affile-source.c000066400000000000000000000124651450431004300231510ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "affile-source.h" #include "driver.h" #include "messages.h" #include "gprocess.h" #include "file-specializations.h" #include #include #include #include #include #include #include #include #include static gboolean _is_linux_proc_kmsg(const gchar *filename) { #ifdef __linux__ if (strcmp(filename, "/proc/kmsg") == 0) return TRUE; #endif return FALSE; } static gboolean _is_linux_dev_kmsg(const gchar *filename) { #ifdef __linux__ if (strcmp(filename, "/dev/kmsg") == 0) return TRUE; #endif return FALSE; } static inline gboolean _is_device_node(const gchar *filename) { struct stat st; if (stat(filename, &st) < 0) return FALSE; return !S_ISREG(st.st_mode); } static inline const gchar * affile_sd_format_persist_name(const LogPipe *s) { AFFileSourceDriver *self = (AFFileSourceDriver *)s; return log_pipe_get_persist_name(&self->file_reader->super); } static void affile_sd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { log_src_driver_queue_method(s, msg, path_options); } static gboolean affile_sd_init(LogPipe *s) { AFFileSourceDriver *self = (AFFileSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_src_driver_init_method(s)) return FALSE; if (!file_reader_options_init(&self->file_reader_options, cfg, self->super.super.group)) return FALSE; file_opener_options_init(&self->file_opener_options, cfg); file_opener_set_options(self->file_opener, &self->file_opener_options); self->file_reader = file_reader_new(self->filename->str, &self->file_reader_options, self->file_opener, &self->super, cfg); log_pipe_set_options(&self->file_reader->super, &self->super.super.super.options); log_pipe_append(&self->file_reader->super, &self->super.super.super); return log_pipe_init(&self->file_reader->super); } static gboolean affile_sd_deinit(LogPipe *s) { AFFileSourceDriver *self = (AFFileSourceDriver *) s; log_pipe_deinit(&self->file_reader->super); if (!log_src_driver_deinit_method(s)) return FALSE; return TRUE; } static void affile_sd_free(LogPipe *s) { AFFileSourceDriver *self = (AFFileSourceDriver *) s; file_opener_free(self->file_opener); log_pipe_unref(&self->file_reader->super); g_string_free(self->filename, TRUE); file_reader_options_deinit(&self->file_reader_options); file_opener_options_deinit(&self->file_opener_options); log_src_driver_free(s); } AFFileSourceDriver * affile_sd_new_instance(gchar *filename, GlobalConfig *cfg) { AFFileSourceDriver *self = g_new0(AFFileSourceDriver, 1); log_src_driver_init_instance(&self->super, cfg); self->super.super.super.init = affile_sd_init; self->super.super.super.queue = affile_sd_queue; self->super.super.super.deinit = affile_sd_deinit; self->super.super.super.free_fn = affile_sd_free; self->super.super.super.generate_persist_name = affile_sd_format_persist_name; self->filename = g_string_new(filename); file_reader_options_defaults(&self->file_reader_options); self->file_reader_options.reader_options.super.stats_level = STATS_LEVEL1; file_opener_options_defaults(&self->file_opener_options); return self; } LogDriver * affile_sd_new(gchar *filename, GlobalConfig *cfg) { AFFileSourceDriver *self = affile_sd_new_instance(filename, cfg); self->file_reader_options.reader_options.super.stats_source = stats_register_type("file"); if (_is_device_node(filename) || _is_linux_proc_kmsg(filename)) self->file_reader_options.follow_freq = 0; else self->file_reader_options.follow_freq = 1000; if (self->file_reader_options.follow_freq > 0) self->file_opener = file_opener_for_regular_source_files_new(); else if (_is_linux_proc_kmsg(self->filename->str)) { self->file_opener_options.needs_privileges = TRUE; self->file_opener = file_opener_for_prockmsg_new(); } else if (_is_linux_dev_kmsg(self->filename->str)) self->file_opener = file_opener_for_devkmsg_new(); else self->file_opener = file_opener_for_regular_source_files_new(); self->file_reader_options.restore_state = self->file_reader_options.follow_freq > 0; file_opener_options_defaults_dont_change_permissions(&self->file_opener_options); self->file_opener_options.create_dirs = FALSE; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/affile-source.h000066400000000000000000000027431450431004300231540ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_SOURCE_H_INCLUDED #define AFFILE_SOURCE_H_INCLUDED #include "driver.h" #include "logreader.h" #include "file-opener.h" #include "file-reader.h" typedef struct _AFFileSourceDriver { LogSrcDriver super; GString *filename; FileReader *file_reader; FileOpener *file_opener; FileReaderOptions file_reader_options; FileOpenerOptions file_opener_options; } AFFileSourceDriver; AFFileSourceDriver *affile_sd_new_instance(gchar *filename, GlobalConfig *cfg); LogDriver *affile_sd_new(gchar *filename, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/collection-comparator.c000066400000000000000000000110661450431004300247210ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "collection-comparator.h" #define IN_OLD 0x01 #define IN_NEW 0x02 #define IN_BOTH 0x03 typedef struct _CollectionComparatorEntry { gchar *value; guint8 flag; } CollectionComparatorEntry; struct _CollectionComparator { GList *original_list; GHashTable *original_map; gboolean running; GList *deleted_entries; gpointer callback_data; void (*handle_new_entry)(const gchar *name, gpointer callback_data); void (*handle_deleted_entry)(const gchar *name, gpointer callback_data); }; static void _free_poll_entry(gpointer s) { CollectionComparatorEntry *entry = (CollectionComparatorEntry *)s; g_free(entry->value); g_free(entry); } void collection_comparator_free(CollectionComparator *self) { g_hash_table_unref(self->original_map); g_list_free_full(self->original_list, _free_poll_entry); g_free(self); } CollectionComparator * collection_comparator_new(void) { CollectionComparator *self = g_new0(CollectionComparator, 1); self->original_map = g_hash_table_new(g_str_hash, g_str_equal); return self; } void collection_comparator_start(CollectionComparator *self) { if (!self->running) { self->running = TRUE; self->deleted_entries = NULL; } } void collection_comparator_add_value(CollectionComparator *self, const gchar *value) { CollectionComparatorEntry *entry = g_hash_table_lookup(self->original_map, value); if (entry) { entry->flag = IN_BOTH; } else { entry = g_new0(CollectionComparatorEntry, 1); entry->value = g_strdup(value); entry->flag = IN_NEW; self->original_list = g_list_append(self->original_list, entry); g_hash_table_insert(self->original_map, entry->value, entry); self->handle_new_entry(entry->value, self->callback_data); } } void collection_comparator_add_initial_value(CollectionComparator *self, const gchar *value) { CollectionComparatorEntry *entry = g_new0(CollectionComparatorEntry, 1); entry->value = g_strdup(value); entry->flag = IN_OLD; self->original_list = g_list_append(self->original_list, entry); g_hash_table_insert(self->original_map, entry->value, entry); } void _move_link(GList *item, GList **old_list, GList **new_list) { *old_list = g_list_remove_link(*old_list, item); *new_list = g_list_concat(*new_list, item); } void _deleted_entries_callback(gpointer data, gpointer user_data) { CollectionComparatorEntry *entry = (CollectionComparatorEntry *)data; CollectionComparator *self = (CollectionComparator *)user_data; self->handle_deleted_entry(entry->value, self->callback_data); } void collection_comparator_collect_deleted_entries(CollectionComparator *self) { GList *iter = self->original_list; CollectionComparatorEntry *entry; while (iter) { entry = (CollectionComparatorEntry *)iter->data; if (entry->flag == IN_OLD) { GList *next = iter->next; g_hash_table_remove(self->original_map, entry->value); _move_link(iter, &self->original_list, &self->deleted_entries); iter = next; } else { entry->flag = IN_OLD; iter = iter->next; } } } void collection_comparator_stop(CollectionComparator *self) { collection_comparator_collect_deleted_entries(self); g_list_foreach(self->deleted_entries, _deleted_entries_callback, self); g_list_free_full(self->deleted_entries, _free_poll_entry); self->running = FALSE; } void collection_comporator_set_callbacks(CollectionComparator *self, cc_callback handle_new, cc_callback handle_delete, gpointer user_data) { self->callback_data = user_data; self->handle_deleted_entry = handle_delete; self->handle_new_entry = handle_new; } syslog-ng-syslog-ng-4.4.0/modules/affile/collection-comparator.h000066400000000000000000000034251450431004300247260ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_COLLECTION_COMPARATOR_H_ #define MODULES_AFFILE_COLLECTION_COMPARATOR_H_ #include "syslog-ng.h" typedef struct _CollectionComparator CollectionComparator; typedef void (*cc_callback)(const gchar *value, gpointer user_data); CollectionComparator *collection_comparator_new(void); void collection_comparator_free(CollectionComparator *self); void collection_comparator_start(CollectionComparator *self); void collection_comparator_stop(CollectionComparator *self); void collection_comparator_add_value(CollectionComparator *self, const gchar *value); void collection_comparator_add_initial_value(CollectionComparator *self, const gchar *value); void collection_comporator_set_callbacks(CollectionComparator *self, cc_callback handle_new, cc_callback handle_delete, gpointer user_data); #endif /* MODULES_AFFILE_COLLECTION_COMPARATOR_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-factory.c000066400000000000000000000044711450431004300255610ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "directory-monitor-factory.h" #include "directory-monitor-poll.h" #if SYSLOG_NG_HAVE_INOTIFY #include "directory-monitor-inotify.h" #endif #include #include MonitorMethod directory_monitor_factory_get_monitor_method(const gchar *method) { if (strcmp(method, "auto") == 0) { return MM_AUTO; } else if (strcmp(method, "poll") == 0) { return MM_POLL; } #if SYSLOG_NG_HAVE_INOTIFY else if (strcmp(method, "inotify") == 0) { return MM_INOTIFY; } #endif return MM_UNKNOWN; } DirectoryMonitorConstructor directory_monitor_factory_get_constructor(DirectoryMonitorOptions *options) { DirectoryMonitorConstructor constructor = NULL; #if SYSLOG_NG_HAVE_INOTIFY if (options->method == MM_AUTO || options->method == MM_INOTIFY) { constructor = directory_monitor_inotify_new; } else if (options->method == MM_POLL) { constructor = directory_monitor_poll_new; } #else if (options->method == MM_AUTO || options->method == MM_POLL) { constructor = directory_monitor_poll_new; } #endif return constructor; } DirectoryMonitor * create_directory_monitor(DirectoryMonitorOptions *options) { DirectoryMonitor *monitor = NULL; DirectoryMonitorConstructor constructor = directory_monitor_factory_get_constructor(options); if (constructor) { monitor = constructor(options->dir, options->follow_freq); } return monitor; } syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-factory.h000066400000000000000000000032241450431004300255610ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_DIRECTORY_MONITOR_FACTORY_H_ #define MODULES_AFFILE_DIRECTORY_MONITOR_FACTORY_H_ #include "directory-monitor.h" typedef DirectoryMonitor *(*DirectoryMonitorConstructor)(const gchar *dir, guint recheck_time); typedef enum { MM_AUTO, MM_POLL, MM_INOTIFY, MM_UNKNOWN } MonitorMethod; typedef struct _DirectoryMonitorOptions { const gchar *dir; guint follow_freq; MonitorMethod method; } DirectoryMonitorOptions; DirectoryMonitorConstructor directory_monitor_factory_get_constructor(DirectoryMonitorOptions *options); MonitorMethod directory_monitor_factory_get_monitor_method(const gchar *method_name); DirectoryMonitor *create_directory_monitor(DirectoryMonitorOptions *options); #endif /* MODULES_AFFILE_DIRECTORY_MONITOR_FACTORY_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-inotify.c000066400000000000000000000072211450431004300255670ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "directory-monitor-inotify.h" #include "messages.h" #include #include #include typedef struct _DirectoryMonitorInotify { DirectoryMonitor super; struct iv_inotify inotify; struct iv_inotify_watch watcher; } DirectoryMonitorInotify; static DirectoryMonitorEventType _get_event_type(struct inotify_event *event, gchar *filename) { if ((event->mask & IN_CREATE) || (event->mask & IN_MOVED_TO)) { if (event->mask & IN_ISDIR) { return DIRECTORY_CREATED; } return FILE_CREATED; } else if ((event->mask & IN_DELETE) || (event->mask & IN_MOVED_FROM)) { return FILE_DELETED; } else if ((event->mask & IN_DELETE_SELF) || (event->mask & IN_MOVE_SELF)) { return DIRECTORY_DELETED; } return UNKNOWN; } static void _handle_event(gpointer s, struct inotify_event *event) { DirectoryMonitorInotify *self = (DirectoryMonitorInotify *)s; DirectoryMonitorEvent dir_event; dir_event.name = g_strdup_printf("%.*s", event->len, &event->name[0]); dir_event.full_path = build_filename(self->super.real_path, dir_event.name); dir_event.event_type = _get_event_type(event, dir_event.full_path); if (self->super.callback && dir_event.event_type != UNKNOWN) { self->super.callback(&dir_event, self->super.callback_data); } g_free(dir_event.full_path); g_free((gchar *)dir_event.name); } static void _start_watches(DirectoryMonitor *s) { DirectoryMonitorInotify *self = (DirectoryMonitorInotify *)s; IV_INOTIFY_WATCH_INIT(&self->watcher); self->watcher.inotify = &self->inotify; self->watcher.pathname = self->super.dir; self->watcher.mask = IN_CREATE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_MOVE_SELF; self->watcher.cookie = self; self->watcher.handler = _handle_event; iv_inotify_watch_register(&self->watcher); } static void _stop_watches(DirectoryMonitor *s) { DirectoryMonitorInotify *self = (DirectoryMonitorInotify *)s; iv_inotify_watch_unregister(&self->watcher); } static void _free(DirectoryMonitor *s) { DirectoryMonitorInotify *self = (DirectoryMonitorInotify *)s; iv_inotify_unregister(&self->inotify); } DirectoryMonitor * directory_monitor_inotify_new(const gchar *dir, guint recheck_time) { DirectoryMonitorInotify *self = g_new0(DirectoryMonitorInotify, 1); directory_monitor_init_instance(&self->super, dir, recheck_time); IV_INOTIFY_INIT(&self->inotify); if (iv_inotify_register(&self->inotify)) { msg_error("directory-monitor-inotify: could not create inotify object", evt_tag_error("errno")); directory_monitor_free(&self->super); return NULL; } self->super.start_watches = _start_watches; self->super.stop_watches = _stop_watches; self->super.free_fn = _free; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-inotify.h000066400000000000000000000022731450431004300255760ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_DIRECTORY_MONITOR_INOTIFY_H_ #define MODULES_AFFILE_DIRECTORY_MONITOR_INOTIFY_H_ #include "directory-monitor.h" #include DirectoryMonitor *directory_monitor_inotify_new(const gchar *dir, guint recheck_time); #endif /* MODULES_AFFILE_DIRECTORY_MONITOR_INOTIFY_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-poll.c000066400000000000000000000122731450431004300250570ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "directory-monitor-poll.h" #include "messages.h" #include "timeutils/misc.h" #include typedef struct _DirectoryMonitorPoll { DirectoryMonitor super; CollectionComparator *comparator; struct iv_timer rescan_timer; } DirectoryMonitorPoll; static void _handle_new_entry(const gchar *filename, gpointer user_data) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)user_data; DirectoryMonitorEvent event; event.name = filename; event.full_path = build_filename(self->super.real_path, event.name); event.event_type = g_file_test(event.full_path, G_FILE_TEST_IS_DIR) ? DIRECTORY_CREATED : FILE_CREATED; if (self->super.callback) { self->super.callback(&event, self->super.callback_data); } g_free(event.full_path); } static void _handle_deleted_entry(const gchar *filename, gpointer user_data) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)user_data; DirectoryMonitorEvent event; event.name = filename; event.event_type = FILE_DELETED; event.full_path = build_filename(self->super.real_path, event.name); if (self->super.callback) { self->super.callback(&event, self->super.callback_data); } g_free(event.full_path); } static void _handle_deleted_self(DirectoryMonitorPoll *self) { DirectoryMonitorEvent event; event.name = self->super.real_path; event.event_type = DIRECTORY_DELETED; event.full_path = self->super.real_path; if (self->super.callback) { self->super.callback(&event, self->super.callback_data); } } static void _rescan_directory(DirectoryMonitorPoll *self) { GError *error = NULL; GDir *directory = g_dir_open(self->super.real_path, 0, &error); collection_comparator_start(self->comparator); if (directory) { const gchar *filename; while((filename = g_dir_read_name(directory))) { collection_comparator_add_value(self->comparator, filename); } g_dir_close(directory); collection_comparator_stop(self->comparator); } else { collection_comparator_stop(self->comparator); _handle_deleted_self(self); msg_debug("Error while opening directory", evt_tag_str("dirname", self->super.real_path), evt_tag_str("error", error->message)); g_clear_error(&error); } } void _rearm_rescan_timer(DirectoryMonitorPoll *self) { iv_validate_now(); self->rescan_timer.expires = iv_now; timespec_add_msec(&self->rescan_timer.expires, self->super.recheck_time); iv_timer_register(&self->rescan_timer); } static void _start_watches(DirectoryMonitor *s) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)s; GDir *directory = NULL; directory = g_dir_open(self->super.real_path, 0, NULL); if (directory) { const gchar *filename = g_dir_read_name(directory); while (filename) { collection_comparator_add_initial_value(self->comparator, filename); filename = g_dir_read_name(directory); } g_dir_close(directory); } _rearm_rescan_timer(self); } static void _stop_watches(DirectoryMonitor *s) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)s; if (iv_timer_registered(&self->rescan_timer)) { iv_timer_unregister(&self->rescan_timer); } } static void _free_fn(DirectoryMonitor *s) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)s; collection_comparator_free(self->comparator); } static void _triggered_timer(gpointer data) { DirectoryMonitorPoll *self = (DirectoryMonitorPoll *)data; _rescan_directory(self); _rearm_rescan_timer(self); } DirectoryMonitor * directory_monitor_poll_new(const gchar *dir, guint recheck_time) { DirectoryMonitorPoll *self = g_new0(DirectoryMonitorPoll, 1); directory_monitor_init_instance(&self->super, dir, recheck_time); IV_TIMER_INIT(&self->rescan_timer); self->rescan_timer.cookie = self; self->rescan_timer.handler = _triggered_timer; self->super.start_watches = _start_watches; self->super.stop_watches = _stop_watches; self->super.free_fn = _free_fn; self->comparator = collection_comparator_new(); collection_comporator_set_callbacks(self->comparator, _handle_new_entry, _handle_deleted_entry, self); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor-poll.h000066400000000000000000000022271450431004300250620ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_DIRECTORY_MONITOR_POLL_H_ #define MODULES_AFFILE_DIRECTORY_MONITOR_POLL_H_ #include "directory-monitor.h" DirectoryMonitor *directory_monitor_poll_new(const gchar *dir, guint recheck_time); #endif /* MODULES_AFFILE_DIRECTORY_MONITOR_POLL_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor.c000066400000000000000000000157721450431004300241220ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "directory-monitor.h" #include "timeutils/misc.h" #include #include #include #include #include #include #include gchar * build_filename(const gchar *basedir, const gchar *path) { gchar *result; if (!path) return NULL; if (basedir) { result = g_build_path(G_DIR_SEPARATOR_S, basedir, path, NULL); } else { result = g_strdup(path); } return result; } #define PATH_MAX_GUESS 1024 static inline long get_path_max(void) { static long path_max = 0; if (path_max == 0) { #ifdef PATH_MAX path_max = PATH_MAX; #else /* This code based on example from the Advanced Programming in the UNIX environment * on how to determine the max path length */ static long posix_version = 0; static long xsi_version = 0; if (posix_version == 0) posix_version = sysconf(_SC_VERSION); if (xsi_version == 0) xsi_version = sysconf(_SC_XOPEN_VERSION); if ((path_max = pathconf("/", _PC_PATH_MAX)) < 0) path_max = PATH_MAX_GUESS; else path_max++; /* add one since it's relative to root */ /* * Before POSIX.1-2001, we aren't guaranteed that PATH_MAX includes * the terminating null byte. Same goes for XPG3. */ if ((posix_version < 200112L) && (xsi_version < 4)) path_max++; #endif } return path_max; } /* Resolve . and .. Resolve symlinks Resolve tricki symlinks like a -> ../a/../a/./b */ gchar * resolve_to_absolute_path(const gchar *path, const gchar *basedir) { long path_max = get_path_max(); gchar *res; gchar *w_name; w_name = build_filename(basedir, path); res = (char *)g_malloc(path_max); if (!realpath(w_name, res)) { g_free(res); if (errno == ENOENT) { res = g_strdup(path); } else { msg_error("Can't resolve to absolute path", evt_tag_str("path", path), evt_tag_error("error")); res = NULL; } } g_free(w_name); return res; } static gchar * _get_real_path(DirectoryMonitor *self) { gchar *dir_real_path = NULL; if (!g_path_is_absolute(self->dir)) { gchar *wd = g_get_current_dir(); dir_real_path = resolve_to_absolute_path(self->dir, wd); g_free(wd); } else { dir_real_path = resolve_to_absolute_path(self->dir, NULL); } return dir_real_path; } void directory_monitor_stop(DirectoryMonitor *self) { if (iv_timer_registered(&self->check_timer)) { iv_timer_unregister(&self->check_timer); } if (iv_task_registered(&self->scheduled_destructor)) { iv_task_unregister(&self->scheduled_destructor); } if (self->stop_watches && self->watches_running) { self->stop_watches(self); } self->watches_running = FALSE; } static void _collect_all_files(DirectoryMonitor *self, GDir *directory) { const gchar *filename = g_dir_read_name(directory); while (filename) { DirectoryMonitorEvent event = { .name = filename }; gchar *filename_real_path = resolve_to_absolute_path(filename, self->real_path); event.full_path = build_filename(self->real_path, filename); event.event_type = g_file_test(filename_real_path, G_FILE_TEST_IS_DIR) ? DIRECTORY_CREATED : FILE_CREATED; self->callback(&event, self->callback_data); g_free(filename_real_path); g_free(event.full_path); filename = g_dir_read_name(directory); } } static void _arm_recheck_timer(DirectoryMonitor *self) { iv_validate_now(); self->check_timer.cookie = self; self->check_timer.handler = (GDestroyNotify) directory_monitor_start; self->check_timer.expires = iv_now; timespec_add_msec(&self->check_timer.expires, self->recheck_time); iv_timer_register(&self->check_timer); } static void _set_real_path(DirectoryMonitor *self) { if (self->real_path) g_free(self->real_path); self->real_path = _get_real_path(self); } void directory_monitor_start(DirectoryMonitor *self) { GDir *directory = NULL; GError *error = NULL; if (self->watches_running) { return; } _set_real_path(self); directory = g_dir_open(self->real_path, 0, &error); if (!directory) { msg_error("Can not open directory", evt_tag_str("base_dir", self->real_path), evt_tag_str("error", error->message)); _arm_recheck_timer(self); g_error_free(error); return; } _collect_all_files(self, directory); g_dir_close(directory); if (self->start_watches) { self->start_watches(self); } self->watches_running = TRUE; return; } void directory_monitor_set_callback(DirectoryMonitor *self, DirectoryMonitorEventCallback callback, gpointer user_data) { self->callback = callback; self->callback_data = user_data; } void directory_monitor_schedule_destroy(DirectoryMonitor *self) { if (!iv_task_registered(&self->scheduled_destructor)) { iv_task_register(&self->scheduled_destructor); } } void directory_monitor_stop_and_destroy(DirectoryMonitor *self) { msg_debug("Stopping directory monitor", evt_tag_str("dir", self->dir)); directory_monitor_stop(self); directory_monitor_free(self); } void directory_monitor_init_instance(DirectoryMonitor *self, const gchar *dir, guint recheck_time) { self->dir = g_strdup(dir); self->recheck_time = recheck_time; IV_TIMER_INIT(&self->check_timer); IV_TASK_INIT(&self->scheduled_destructor); self->scheduled_destructor.cookie = self; self->scheduled_destructor.handler = (GDestroyNotify)directory_monitor_stop_and_destroy; } DirectoryMonitor * directory_monitor_new(const gchar *dir, guint recheck_time) { DirectoryMonitor *self = g_new0(DirectoryMonitor, 1); directory_monitor_init_instance(self, dir, recheck_time); return self; } void directory_monitor_free(DirectoryMonitor *self) { if (self) { msg_debug("Free directory monitor", evt_tag_str("dir", self->dir)); if (self->free_fn) { self->free_fn(self); } g_free(self->real_path); g_free(self->dir); g_free(self); } } syslog-ng-syslog-ng-4.4.0/modules/affile/directory-monitor.h000066400000000000000000000050701450431004300241150ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_DIRECTORY_MONITOR_H_ #define MODULES_AFFILE_DIRECTORY_MONITOR_H_ #include #include typedef enum { FILE_CREATED, DIRECTORY_CREATED, FILE_DELETED, DIRECTORY_DELETED, UNKNOWN } DirectoryMonitorEventType; typedef struct _DirectoryMonitorEvent { const gchar *name; gchar *full_path; DirectoryMonitorEventType event_type; } DirectoryMonitorEvent; typedef void (*DirectoryMonitorEventCallback)(const DirectoryMonitorEvent *event, gpointer user_data); typedef struct _DirectoryMonitor DirectoryMonitor; struct _DirectoryMonitor { gchar *dir; gchar *real_path; DirectoryMonitorEventCallback callback; gpointer callback_data; guint recheck_time; struct iv_timer check_timer; struct iv_task scheduled_destructor; gboolean watches_running; void (*start_watches)(DirectoryMonitor *self); void (*stop_watches)(DirectoryMonitor *self); void (*free_fn)(DirectoryMonitor *self); }; DirectoryMonitor *directory_monitor_new(const gchar *dir, guint recheck_time); void directory_monitor_init_instance(DirectoryMonitor *self, const gchar *dir, guint recheck_time); void directory_monitor_free(DirectoryMonitor *self); void directory_monitor_set_callback(DirectoryMonitor *self, DirectoryMonitorEventCallback callback, gpointer user_data); void directory_monitor_start(DirectoryMonitor *self); void directory_monitor_stop(DirectoryMonitor *self); void directory_monitor_stop_and_destroy(DirectoryMonitor *self); void directory_monitor_schedule_destroy(DirectoryMonitor *self); gchar *build_filename(const gchar *basedir, const gchar *path); #endif /* MODULES_AFFILE_DIRECTORY_MONITOR_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/file-list.c000066400000000000000000000056431450431004300223150ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-list.h" #include "compat/glib.h" struct _PendingFileList { GHashTable *index_storage; GQueue *priority_queue; }; PendingFileList *pending_file_list_new(void) { PendingFileList *self = g_new(PendingFileList, 1); self->index_storage = g_hash_table_new(g_str_hash, g_str_equal); self->priority_queue = g_queue_new(); return self; } void pending_file_list_free(PendingFileList *self) { g_hash_table_unref(self->index_storage); g_queue_free_full(self->priority_queue, g_free); g_free(self); } void pending_file_list_add(PendingFileList *self, const gchar *value) { GList *element = g_hash_table_lookup(self->index_storage, value); if (!element) { gchar *new_value = g_strdup(value); g_queue_push_tail(self->priority_queue, new_value); g_hash_table_insert(self->index_storage, new_value, self->priority_queue->tail); } } gchar *pending_file_list_pop(PendingFileList *self) { GList *it = pending_file_list_begin(self); if (it == pending_file_list_end(self)) return NULL; gchar *data = it->data; pending_file_list_steal(self, it); g_list_free_1(it); return data; } gboolean pending_file_list_remove(PendingFileList *self, const gchar *value) { gboolean is_deleted = FALSE; GList *element = g_hash_table_lookup(self->index_storage, value); if (element) { g_hash_table_steal(self->index_storage, element->data); g_free(element->data); g_queue_delete_link(self->priority_queue, element); is_deleted = TRUE; } return is_deleted; } void pending_file_list_steal(PendingFileList *self, GList *entry) { if (!entry) return; GList *element = g_hash_table_lookup(self->index_storage, entry->data); g_assert(element); g_hash_table_steal(self->index_storage, element->data); g_queue_unlink(self->priority_queue, entry); } GList *pending_file_list_begin(PendingFileList *self) { return self->priority_queue->head; } GList *pending_file_list_end(PendingFileList *self) { return NULL; } GList *pending_file_list_next(GList *it) { return it->next; } syslog-ng-syslog-ng-4.4.0/modules/affile/file-list.h000066400000000000000000000031161450431004300223130ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_FILE_LIST_H_ #define MODULES_AFFILE_FILE_LIST_H_ #include typedef struct _PendingFileList PendingFileList; PendingFileList *pending_file_list_new(void); void pending_file_list_free(PendingFileList *self); void pending_file_list_add(PendingFileList *self, const gchar *value); gchar *pending_file_list_pop(PendingFileList *self); gboolean pending_file_list_remove(PendingFileList *self, const gchar *value); void pending_file_list_steal(PendingFileList *self, GList *entry); GList *pending_file_list_begin(PendingFileList *self); GList *pending_file_list_end(PendingFileList *self); GList *pending_file_list_next(GList *it); #endif /* MODULES_AFFILE_HASHED_QUEUE_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/file-opener.c000066400000000000000000000167351450431004300226360ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-opener.h" #include "messages.h" #include "gprocess.h" #include "fdhelpers.h" #include "pathutils.h" #include "cfg.h" #include "transport/transport-file.h" #include #include #include #include #include #include #include #include static inline gboolean file_opener_prepare_open(FileOpener *self, const gchar *name) { if (self->prepare_open) return self->prepare_open(self, name); return TRUE; } static inline gint file_opener_open(FileOpener *self, const gchar *name, gint flags) { return self->open(self, name, flags); } static gint file_opener_get_open_flags_method(FileOpener *self, FileDirection dir) { switch (dir) { case AFFILE_DIR_READ: return O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE; case AFFILE_DIR_WRITE: return O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK | O_LARGEFILE | O_APPEND; default: g_assert_not_reached(); } } static inline gint file_opener_get_open_flags(FileOpener *self, FileDirection dir) { return self->get_open_flags(self, dir); } static const gchar *spurious_paths[] = {"../", "/..", NULL}; static inline gboolean _string_contains_fragment(const gchar *str, const gchar *fragments[]) { int i; for (i = 0; fragments[i]; i++) { if (strstr(str, fragments[i])) return TRUE; } return FALSE; } static inline gboolean _is_path_spurious(const gchar *name) { return _string_contains_fragment(name, spurious_paths); } static inline gboolean _obtain_capabilities(FileOpener *self, const gchar *name, cap_t *act_caps) { if (self->options->needs_privileges) { g_process_enable_cap("cap_dac_read_search"); g_process_enable_cap("cap_syslog"); } else { g_process_enable_cap("cap_dac_override"); } if (self->options->create_dirs && !file_perm_options_create_containing_directory(&self->options->file_perm_options, name)) { return FALSE; } return TRUE; } static inline void _set_fd_permission(FileOpener *self, int fd) { if (fd != -1) { g_fd_set_cloexec(fd, TRUE); g_process_enable_cap("cap_chown"); g_process_enable_cap("cap_fowner"); file_perm_options_apply_fd(&self->options->file_perm_options, fd); } } static int _open(FileOpener *self, const gchar *name, gint open_flags) { FilePermOptions *perm_opts = &self->options->file_perm_options; int fd; int mode = (perm_opts && (perm_opts->file_perm >= 0)) ? perm_opts->file_perm : 0600; fd = open(name, open_flags, mode); return fd; } FileOpenerResult file_opener_open_fd(FileOpener *self, const gchar *name, FileDirection dir, gint *fd) { cap_t saved_caps; if (_is_path_spurious(name)) { msg_error("Spurious path, logfile not created", evt_tag_str("path", name)); return FILE_OPENER_RESULT_ERROR_PERMANENT; } saved_caps = g_process_cap_save(); if (!_obtain_capabilities(self, name, &saved_caps)) { g_process_cap_restore(saved_caps); return FILE_OPENER_RESULT_ERROR_TRANSIENT; } if (!file_opener_prepare_open(self, name)) return FILE_OPENER_RESULT_ERROR_TRANSIENT; *fd = file_opener_open(self, name, file_opener_get_open_flags(self, dir)); if (!is_file_device(name)) _set_fd_permission(self, *fd); g_process_cap_restore(saved_caps); msg_trace("affile_open_file", evt_tag_str("path", name), evt_tag_int("fd", *fd)); if (*fd == -1) return FILE_OPENER_RESULT_ERROR_TRANSIENT; return FILE_OPENER_RESULT_SUCCESS; } static gboolean _is_symlink_creation_needed(const gchar *name, const gchar *target) { gboolean r = FALSE; GError *e = NULL; gchar *s = g_file_read_link(name, &e); if (e != NULL) { if (g_error_matches(e, G_FILE_ERROR, G_FILE_ERROR_NOENT)) r = TRUE; else msg_error("Error checking symlink", evt_tag_str("filename", name), evt_tag_str("message", e->message)); g_error_free(e); } else if (strcmp(s, target) != 0) { if (unlink(name) == 0) r = TRUE; else msg_error("Error removing symlink", evt_tag_str("filename", name), evt_tag_errno(EVT_TAG_OSERROR, errno)); } g_free(s); return r; } void file_opener_symlink(FileOpener *self, const gchar *name, const gchar *target) { cap_t saved_caps; msg_trace("file_opener_symlink", evt_tag_str("filename", name), evt_tag_str("target", target)); if (!_is_symlink_creation_needed(name, target)) return; saved_caps = g_process_cap_save(); if (!_obtain_capabilities(self, name, &saved_caps)) { g_process_cap_restore(saved_caps); return; } g_process_enable_cap("cap_chown"); msg_info("Creating symlink", evt_tag_str("filename", name), evt_tag_str("target", target)); if (symlink(target, name) == -1) msg_error("Error creating symlink", evt_tag_str("filename", name), evt_tag_str("target", target), evt_tag_errno(EVT_TAG_OSERROR, errno)); else if (!file_perm_options_apply_symlink(&self->options->file_perm_options, name)) msg_error("Error setting symlink ownership", evt_tag_str("filename", name), evt_tag_errno(EVT_TAG_OSERROR, errno)); g_process_cap_restore(saved_caps); } void file_opener_set_options(FileOpener *self, FileOpenerOptions *options) { self->options = options; } void file_opener_init_instance(FileOpener *self) { self->get_open_flags = file_opener_get_open_flags_method; self->open = _open; } FileOpener * file_opener_new(void) { FileOpener *self = g_new0(FileOpener, 1); file_opener_init_instance(self); return self; } void file_opener_free(FileOpener *self) { g_free(self); } void file_opener_options_defaults(FileOpenerOptions *options) { file_perm_options_defaults(&options->file_perm_options); options->create_dirs = -1; options->needs_privileges = FALSE; } void file_opener_options_defaults_dont_change_permissions(FileOpenerOptions *options) { file_opener_options_defaults(options); file_perm_options_inherit_dont_change(&options->file_perm_options); } void file_opener_options_init(FileOpenerOptions *options, GlobalConfig *cfg) { file_perm_options_inherit_from(&options->file_perm_options, &cfg->file_perm_options); if (options->create_dirs == -1) options->create_dirs = cfg->create_dirs; } void file_opener_options_deinit(FileOpenerOptions *options) { /* empty, this function only serves to meet the conventions of *Options */ } syslog-ng-syslog-ng-4.4.0/modules/affile/file-opener.h000066400000000000000000000067701450431004300226410ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_FILE_OPENER_H_INCLUDED #define AFFILE_FILE_OPENER_H_INCLUDED /* portable largefile support for affile */ #include "compat/lfs.h" #include "file-perms.h" #include "transport/logtransport.h" #include "logproto/logproto-server.h" #include "logproto/logproto-client.h" #include "logproto-file-reader.h" #include typedef enum { AFFILE_DIR_READ = 0x01, AFFILE_DIR_WRITE = 0x02, } FileDirection; typedef struct _FileOpenerOptions { FilePermOptions file_perm_options; guint needs_privileges:1; gint create_dirs; } FileOpenerOptions; typedef enum { FILE_OPENER_RESULT_SUCCESS, FILE_OPENER_RESULT_ERROR_TRANSIENT, FILE_OPENER_RESULT_ERROR_PERMANENT } FileOpenerResult; typedef struct _FileOpener FileOpener; struct _FileOpener { FileOpenerOptions *options; gboolean (*prepare_open)(FileOpener *self, const gchar *name); gint (*open)(FileOpener *self, const gchar *name, gint flags); gint (*get_open_flags)(FileOpener *self, FileDirection dir); LogTransport *(*construct_transport)(FileOpener *self, gint fd); LogProtoServer *(*construct_src_proto)(FileOpener *self, LogTransport *transport, LogProtoFileReaderOptions *proto_options); LogProtoClient *(*construct_dst_proto)(FileOpener *self, LogTransport *transport, LogProtoClientOptions *proto_options); }; static inline LogTransport * file_opener_construct_transport(FileOpener *self, gint fd) { return self->construct_transport(self, fd); } static inline LogProtoServer * file_opener_construct_src_proto(FileOpener *self, LogTransport *transport, LogProtoFileReaderOptions *proto_options) { return self->construct_src_proto(self, transport, proto_options); } static inline LogProtoClient * file_opener_construct_dst_proto(FileOpener *self, LogTransport *transport, LogProtoClientOptions *proto_options) { return self->construct_dst_proto(self, transport, proto_options); } FileOpenerResult file_opener_open_fd(FileOpener *self, const gchar *name, FileDirection dir, gint *fd); void file_opener_symlink(FileOpener *self, const gchar *name, const gchar *target); void file_opener_set_options(FileOpener *self, FileOpenerOptions *options); void file_opener_init_instance(FileOpener *self); FileOpener *file_opener_new(void); void file_opener_free(FileOpener *self); void file_opener_options_defaults(FileOpenerOptions *options); void file_opener_options_defaults_dont_change_permissions(FileOpenerOptions *options); void file_opener_options_init(FileOpenerOptions *options, GlobalConfig *cfg); void file_opener_options_deinit(FileOpenerOptions *options); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/file-reader.c000066400000000000000000000321131450431004300225740ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-reader.h" #include "driver.h" #include "messages.h" #include "serialize.h" #include "gprocess.h" #include "stats/stats-registry.h" #include "transport/transport-file.h" #include "transport/transport-pipe.h" #include "transport-prockmsg.h" #include "logproto/logproto-buffered-server.h" #include "poll-fd-events.h" #include "poll-file-changes.h" #include "poll-multiline-file-changes.h" #include "ack-tracker/ack_tracker_factory.h" #include "stats/stats-cluster-key-builder.h" #include #include #include #include #include #include #include #include #include static inline const gchar * _format_persist_name(const LogPipe *s) { const FileReader *self = (const FileReader *)s; static gchar persist_name[1024]; if (self->owner->super.super.persist_name) g_snprintf(persist_name, sizeof(persist_name), "affile_sd.%s.curpos", self->owner->super.super.persist_name); else g_snprintf(persist_name, sizeof(persist_name), "affile_sd_curpos(%s)", self->filename->str); return persist_name; } static void _recover_state(LogPipe *s, GlobalConfig *cfg, LogProtoServer *proto) { FileReader *self = (FileReader *) s; if (!self->options->restore_state) return; if (!log_proto_server_restart_with_state(proto, cfg->state, _format_persist_name(s))) { msg_error("Error converting persistent state from on-disk format, losing file position information", evt_tag_str("filename", self->filename->str)); return; } } static gboolean _is_fd_pollable(gint fd) { struct iv_fd check_fd; gboolean pollable; IV_FD_INIT(&check_fd); check_fd.fd = fd; check_fd.cookie = NULL; pollable = (iv_fd_register_try(&check_fd) == 0); if (pollable) iv_fd_unregister(&check_fd); return pollable; } static PollEvents * _construct_poll_events(FileReader *self, gint fd) { if (self->options->follow_freq > 0) { LogProtoFileReaderOptions *proto_opts = file_reader_options_get_log_proto_options(self->options); if (proto_opts->multi_line_options.mode == MLM_NONE) return poll_file_changes_new(fd, self->filename->str, self->options->follow_freq, &self->super); else return poll_multiline_file_changes_new(fd, self->filename->str, self->options->follow_freq, self->options->multi_line_timeout, self); } else if (fd >= 0 && _is_fd_pollable(fd)) return poll_fd_events_new(fd); else { msg_error("Unable to determine how to monitor this file, follow_freq() unset and it is not possible to poll it " "with the current ivykis polling method. Set follow-freq() for regular files or change " "IV_EXCLUDE_POLL_METHOD environment variable to override the automatically selected polling method", evt_tag_str("filename", self->filename->str), evt_tag_int("fd", fd)); return NULL; } } static LogTransport * _construct_transport(FileReader *self, gint fd) { return file_opener_construct_transport(self->opener, fd); } static LogProtoServer * _construct_proto(FileReader *self, gint fd) { LogReaderOptions *reader_options = &self->options->reader_options; LogProtoFileReaderOptions *proto_options = file_reader_options_get_log_proto_options(self->options); LogTransport *transport; MsgFormatHandler *format_handler; transport = _construct_transport(self, fd); format_handler = reader_options->parse_options.format_handler; if ((format_handler && format_handler->construct_proto)) { log_proto_server_options_set_ack_tracker_factory(&proto_options->super, consecutive_ack_tracker_factory_new()); return format_handler->construct_proto(&reader_options->parse_options, transport, &proto_options->super); } return file_opener_construct_src_proto(self->opener, transport, proto_options); } static void _deinit_sd_logreader(FileReader *self) { log_pipe_deinit((LogPipe *) self->reader); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; } static void _setup_logreader(LogPipe *s, PollEvents *poll_events, LogProtoServer *proto, gboolean check_immediately) { FileReader *self = (FileReader *) s; self->reader = log_reader_new(log_pipe_get_config(s)); log_pipe_set_options(&self->reader->super.super, &self->super.options); log_reader_open(self->reader, proto, poll_events); StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(kb, stats_cluster_label("driver", "file")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("filename", self->filename->str)); log_reader_set_options(self->reader, s, &self->options->reader_options, self->owner->super.id, kb); if (check_immediately) log_reader_set_immediate_check(self->reader); /* NOTE: if the file could not be opened, we ignore the last * remembered file position, if the file is created in the future * we're going to read from the start. */ log_pipe_append((LogPipe *) self->reader, s); } static gboolean _is_immediate_check_needed(gboolean file_opened, gboolean open_deferred) { if (file_opened) return TRUE; else if (open_deferred) return FALSE; return FALSE; } static gboolean _reader_open_file(LogPipe *s, gboolean recover_state) { FileReader *self = (FileReader *) s; GlobalConfig *cfg = log_pipe_get_config(s); gint fd; gboolean open_deferred = FALSE; FileOpenerResult res = file_opener_open_fd(self->opener, self->filename->str, AFFILE_DIR_READ, &fd); gboolean file_opened = res == FILE_OPENER_RESULT_SUCCESS; if (!file_opened && self->options->follow_freq > 0) { msg_info("Follow-mode file source not found, deferring open", evt_tag_str("filename", self->filename->str)); open_deferred = TRUE; fd = -1; } if (file_opened || open_deferred) { LogProtoServer *proto; PollEvents *poll_events; gboolean check_immediately; poll_events = _construct_poll_events(self, fd); if (!poll_events) { close(fd); return FALSE; } proto = _construct_proto(self, fd); check_immediately = _is_immediate_check_needed(file_opened, open_deferred); _setup_logreader(s, poll_events, proto, check_immediately); if (!log_pipe_init((LogPipe *) self->reader)) { msg_error("Error initializing log_reader, closing fd", evt_tag_int("fd", fd)); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; close(fd); return FALSE; } if (recover_state) _recover_state(s, cfg, proto); } else { msg_error("Error opening file for reading", evt_tag_str("filename", self->filename->str), evt_tag_error(EVT_TAG_OSERROR)); return self->owner->super.optional; } return TRUE; } static void _reopen_on_notify(LogPipe *s, gboolean recover_state) { FileReader *self = (FileReader *) s; _deinit_sd_logreader(self); _reader_open_file(s, recover_state); } /* NOTE: runs in the main thread */ void file_reader_notify_method(LogPipe *s, gint notify_code, gpointer user_data) { FileReader *self = (FileReader *) s; switch (notify_code) { case NC_CLOSE: if (self->options->exit_on_eof) cfg_shutdown(log_pipe_get_config(s)); break; case NC_FILE_MOVED: msg_verbose("Follow-mode file source moved, tracking of the new file is started", evt_tag_str("filename", self->filename->str)); _reopen_on_notify(s, TRUE); break; case NC_READ_ERROR: msg_verbose("Error while following source file, reopening in the hope it would work", evt_tag_str("filename", self->filename->str)); _reopen_on_notify(s, FALSE); break; default: break; } } void file_reader_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { FileReader *self = (FileReader *)s; static NVHandle filename_handle = 0; if (!filename_handle) filename_handle = log_msg_get_value_handle("FILE_NAME"); log_msg_set_value(msg, filename_handle, self->filename->str, self->filename->len); log_pipe_forward_msg(s, msg, path_options); } gboolean file_reader_init_method(LogPipe *s) { return _reader_open_file(s, TRUE); } gboolean file_reader_deinit_method(LogPipe *s) { FileReader *self = (FileReader *)s; if (self->reader) _deinit_sd_logreader(self); return TRUE; } void file_reader_free_method(LogPipe *s) { FileReader *self = (FileReader *) s; g_assert(!self->reader); g_string_free(self->filename, TRUE); } void file_reader_remove_persist_state(FileReader *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super); const gchar *old_persist_name = _format_persist_name(&self->super); gchar *new_persist_name = g_strdup_printf("%s_REMOVED", old_persist_name); /* This is required to clean the persist entry from file during restart */ persist_state_remove_entry(cfg->state, old_persist_name); /* This is required to clean the runtime persist state */ persist_state_rename_entry(cfg->state, old_persist_name, new_persist_name); g_free(new_persist_name); } void file_reader_stop_follow_file(FileReader *self) { log_reader_disable_bookmark_saving(self->reader); log_reader_close_proto(self->reader); } void file_reader_cue_buffer_flush(FileReader *self) { LogProtoBufferedServer *proto = (LogProtoBufferedServer *) self->reader->proto; log_proto_buffered_server_cue_flush(proto); } void file_reader_init_instance (FileReader *self, const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg) { log_pipe_init_instance (&self->super, cfg); self->super.init = file_reader_init_method; self->super.queue = file_reader_queue_method; self->super.deinit = file_reader_deinit_method; self->super.notify = file_reader_notify_method; self->super.free_fn = file_reader_free_method; self->super.generate_persist_name = _format_persist_name; self->filename = g_string_new (filename); self->options = options; self->opener = opener; self->owner = owner; self->super.expr_node = owner->super.super.expr_node; } FileReader * file_reader_new(const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg) { FileReader *self = g_new0(FileReader, 1); file_reader_init_instance (self, filename, options, opener, owner, cfg); return self; } void file_reader_options_set_follow_freq(FileReaderOptions *options, gint follow_freq) { options->follow_freq = follow_freq; } void file_reader_options_set_multi_line_timeout(FileReaderOptions *options, gint multi_line_timeout) { options->multi_line_timeout = multi_line_timeout; } void file_reader_options_defaults(FileReaderOptions *options) { log_reader_options_defaults(&options->reader_options); log_proto_file_reader_options_defaults(file_reader_options_get_log_proto_options(options)); options->reader_options.parse_options.flags |= LP_LOCAL; options->restore_state = FALSE; } static gboolean file_reader_options_validate(FileReaderOptions *options) { if (options->multi_line_timeout && options->follow_freq >= options->multi_line_timeout) { msg_error("multi-line-timeout() should be set to a higher value than follow-freq(), " "it is recommended to set multi-line-timeout() to a multiple of follow-freq()", evt_tag_int("multi_line_timeout", options->multi_line_timeout), evt_tag_int("follow_freq", options->follow_freq)); return FALSE; } return TRUE; } gboolean file_reader_options_init(FileReaderOptions *options, GlobalConfig *cfg, const gchar *group) { log_reader_options_init(&options->reader_options, cfg, group); if (!file_reader_options_validate(options)) return FALSE; return log_proto_file_reader_options_init(file_reader_options_get_log_proto_options(options), cfg); } void file_reader_options_deinit(FileReaderOptions *options) { log_reader_options_destroy(&options->reader_options); } syslog-ng-syslog-ng-4.4.0/modules/affile/file-reader.h000066400000000000000000000056061450431004300226100ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_FILE_READER_H_ #define MODULES_AFFILE_FILE_READER_H_ #include "driver.h" #include "logreader.h" #include "file-opener.h" typedef struct _FileReaderOptions { gint follow_freq; gint multi_line_timeout; gboolean restore_state; LogReaderOptions reader_options; gboolean exit_on_eof; } FileReaderOptions; typedef struct _FileReader { LogPipe super; LogSrcDriver *owner; GString *filename; FileReaderOptions *options; FileOpener *opener; LogReader *reader; } FileReader; static inline LogProtoFileReaderOptions * file_reader_options_get_log_proto_options(FileReaderOptions *options) { return (LogProtoFileReaderOptions *) &options->reader_options.proto_options; } FileReader *file_reader_new(const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg); void file_reader_init_instance(FileReader *self, const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg); gboolean file_reader_init_method(LogPipe *s); gboolean file_reader_deinit_method(LogPipe *s); void file_reader_free_method(LogPipe *s); void file_reader_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options); void file_reader_notify_method(LogPipe *s, gint notify_code, gpointer user_data); void file_reader_remove_persist_state(FileReader *self); void file_reader_stop_follow_file(FileReader *self); void file_reader_cue_buffer_flush(FileReader *self); void file_reader_options_set_follow_freq(FileReaderOptions *options, gint follow_freq); void file_reader_options_set_multi_line_timeout(FileReaderOptions *options, gint multi_line_timeout); void file_reader_options_defaults(FileReaderOptions *options); gboolean file_reader_options_init(FileReaderOptions *options, GlobalConfig *cfg, const gchar *group); void file_reader_options_deinit(FileReaderOptions *options); #endif /* MODULES_AFFILE_FILE_READER_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/file-specializations.h000066400000000000000000000025261450431004300245450ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_FILE_SPECIALIZATIONS_H_INCLUDED #define AFFILE_FILE_SPECIALIZATIONS_H_INCLUDED #include "file-opener.h" #include "logwriter.h" FileOpener *file_opener_for_regular_source_files_new(void); FileOpener *file_opener_for_regular_dest_files_new(const LogWriterOptions *writer_options, gboolean *use_fsync); FileOpener *file_opener_for_devkmsg_new(void); FileOpener *file_opener_for_prockmsg_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/linux-kmsg.c000066400000000000000000000061221450431004300225140ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-specializations.h" #include "transport/transport-file.h" #include "transport-prockmsg.h" #include "messages.h" #include "logproto/logproto-dgram-server.h" #include "logproto/logproto-text-server.h" #include #include /************************************************************** * /dev/kmsg support **************************************************************/ LogTransport * log_transport_devkmsg_new(gint fd) { if (lseek(fd, 0, SEEK_END) < 0) { msg_error("Error seeking /dev/kmsg to the end", evt_tag_str("error", g_strerror(errno))); } return log_transport_file_new(fd); } static LogTransport * _construct_devkmsg_transport(FileOpener *self, gint fd) { return log_transport_devkmsg_new(fd); } static LogProtoServer * _construct_devkmsg_proto(FileOpener *self, LogTransport *transport, LogProtoFileReaderOptions *options) { return log_proto_dgram_server_new(transport, &options->super); } FileOpener * file_opener_for_devkmsg_new(void) { FileOpener *self = file_opener_new(); self->construct_transport = _construct_devkmsg_transport; self->construct_src_proto = _construct_devkmsg_proto; return self; } /************************************************************** * /proc/kmsg support **************************************************************/ static LogProtoServer * log_proto_linux_proc_kmsg_reader_new(LogTransport *transport, const LogProtoServerOptions *options) { LogProtoServer *proto; proto = log_proto_text_server_new(transport, options); ((LogProtoTextServer *) proto)->super.no_multi_read = TRUE; return proto; } static LogTransport * _construct_prockmsg_transport(FileOpener *self, gint fd) { return log_transport_prockmsg_new(fd, 10); } static LogProtoServer * _construct_prockmsg_proto(FileOpener *self, LogTransport *transport, LogProtoFileReaderOptions *options) { return log_proto_linux_proc_kmsg_reader_new(transport, &options->super); } FileOpener * file_opener_for_prockmsg_new(void) { FileOpener *self = file_opener_new(); self->construct_transport = _construct_prockmsg_transport; self->construct_src_proto = _construct_prockmsg_proto; return self; } syslog-ng-syslog-ng-4.4.0/modules/affile/logproto-file-reader.c000066400000000000000000000070541450431004300244450ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-file-reader.h" #include "logproto/logproto-record-server.h" #include "logproto/logproto-multiline-server.h" #include "messages.h" LogProtoServer * log_proto_file_reader_new(LogTransport *transport, const LogProtoFileReaderOptions *options) { if (options->pad_size > 0) return log_proto_padded_record_server_new(transport, &options->super, options->pad_size); else return log_proto_multiline_server_new(transport, &options->super, multi_line_factory_construct(&options->multi_line_options)); } /* these functions only initialize the fields added on top of * LogProtoServerOptions, the rest is the responsibility of the LogReader. * This whole Options structure has become very messy. There are a lot of them. * * FileReaderOptions -> * LogReaderOptions -> * LogProtoServerOptions * This is actually a LogProtoServerOptionsStorage structure * which holds a LogProtoFileReaderOptions instance and the * LogReader only stores it. * * FileOpenerOptions is fortunately independent of this mess. * * LogProtoFileReaderOptions only needs to take care about its "extra" * fields on top of LogProtoServerOptions, that's why we don't call anything * from the "inherited" class. This is because that class is * defaulted/initialized/destroyed by LogReader. This layer just manages * what we happen to store in addition to LogProtoServerOptions. * * You have been warned! * * PS: I attempted to refactor this, but at first try it became more messy, so I * abandoned it, but it should be done eventually. **/ void _destroy_callback(LogProtoServerOptions *o) { LogProtoFileReaderOptions *options = (LogProtoFileReaderOptions *) o; multi_line_options_destroy(&options->multi_line_options); } void log_proto_file_reader_options_defaults(LogProtoFileReaderOptions *options) { options->super.destroy = _destroy_callback; multi_line_options_defaults(&options->multi_line_options); options->pad_size = 0; } static gboolean log_proto_file_reader_options_validate(LogProtoFileReaderOptions *options) { if (options->pad_size > 0 && options->multi_line_options.mode != MLM_NONE) { msg_error("pad-size() and multi-line-mode() can not be used together"); return FALSE; } return multi_line_options_validate(&options->multi_line_options); } gboolean log_proto_file_reader_options_init(LogProtoFileReaderOptions *options, GlobalConfig *cfg) { if (!log_proto_file_reader_options_validate(options)) return FALSE; if (!multi_line_options_init(&options->multi_line_options)) return FALSE; return TRUE; } syslog-ng-syslog-ng-4.4.0/modules/affile/logproto-file-reader.h000066400000000000000000000031761450431004300244530ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOG_PROTO_FILE_READER_H_INCLUDED #define LOG_PROTO_FILE_READER_H_INCLUDED #include "logproto/logproto-multiline-server.h" #include "multi-line/multi-line-factory.h" typedef struct _LogProtoFileReaderOptions { LogProtoServerOptions super; MultiLineOptions multi_line_options; gint pad_size; } LogProtoFileReaderOptions; LogProtoServer *log_proto_file_reader_new(LogTransport *transport, const LogProtoFileReaderOptions *options); void log_proto_file_reader_options_defaults(LogProtoFileReaderOptions *options); gboolean log_proto_file_reader_options_init(LogProtoFileReaderOptions *options, GlobalConfig *cfg); void log_proto_file_reader_options_destroy(LogProtoFileReaderOptions *options); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/logproto-file-writer.c000066400000000000000000000171031450431004300245130ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "logproto-file-writer.h" #include "messages.h" #include #include #include #include typedef struct _LogProtoFileWriter { LogProtoClient super; guchar *partial; gsize partial_len, partial_pos; gint partial_messages; gint buf_size; gint buf_count; gint fd; gint sum_len; gboolean fsync; struct iovec buffer[0]; } LogProtoFileWriter; /* * log_proto_file_writer_flush: * * this function flushes the file output buffer * it is called either form log_proto_file_writer_post (normal mode: the buffer is full) * or from log_proto_flush (foced flush: flush time, exit, etc) * */ static LogProtoStatus log_proto_file_writer_flush(LogProtoClient *s) { LogProtoFileWriter *self = (LogProtoFileWriter *)s; gint rc, i, i0, sum, ofs, pos; if (self->partial) { /* there is still some data from the previous file writing process */ gint len = self->partial_len - self->partial_pos; rc = log_transport_write(self->super.transport, self->partial + self->partial_pos, len); if (rc > 0 && self->fsync) fsync(self->fd); if (rc < 0) { goto write_error; } else if (rc != len) { self->partial_pos += rc; return LPS_PARTIAL; } else { log_proto_client_msg_ack(&self->super, self->partial_messages); g_free(self->partial); self->partial = NULL; } } /* we might be called from log_writer_deinit() without having a buffer at all */ if (self->buf_count == 0) return LPS_SUCCESS; rc = log_transport_writev(self->super.transport, self->buffer, self->buf_count); if (rc > 0 && self->fsync) fsync(self->fd); if (rc < 0) { goto write_error; } else if (rc != self->sum_len) { /* partial success: not everything has been written out */ /* look for the first chunk that has been cut */ sum = self->buffer[0].iov_len; /* sum is the cumulated length of the already processed items */ i = 0; while (rc > sum) sum += self->buffer[++i].iov_len; self->partial_len = sum - rc; /* this is the length of the first non-written chunk */ i0 = i; ++i; /* add the lengths of the following messages */ while (i < self->buf_count) self->partial_len += self->buffer[i++].iov_len; /* allocate and copy the remaining data */ self->partial = (guchar *)g_malloc(self->partial_len); ofs = sum - rc; /* the length of the remaining (not processed) chunk in the first message */ pos = self->buffer[i0].iov_len - ofs; memcpy(self->partial, (guchar *) self->buffer[i0].iov_base + pos, ofs); i = i0 + 1; while (i < self->buf_count) { memcpy(self->partial + ofs, self->buffer[i].iov_base, self->buffer[i].iov_len); ofs += self->buffer[i].iov_len; ++i; } self->partial_pos = 0; self->partial_messages = self->buf_count - i0; } else { log_proto_client_msg_ack(&self->super, self->buf_count); } /* free the previous message strings (the remaining part has been copied to the partial buffer) */ for (i = 0; i < self->buf_count; ++i) g_free(self->buffer[i].iov_base); self->buf_count = 0; self->sum_len = 0; return LPS_SUCCESS; write_error: if (errno != EINTR && errno != EAGAIN) { log_proto_client_msg_rewind(&self->super); msg_error("I/O error occurred while writing", evt_tag_int("fd", self->super.transport->fd), evt_tag_error(EVT_TAG_OSERROR)); return LPS_ERROR; } return LPS_SUCCESS; } /* * log_proto_file_writer_post: * @msg: formatted log message to send (this might be consumed by this function) * @msg_len: length of @msg * @consumed: pointer to a gboolean that gets set if the message was consumed by this function * @error: error information, if any * * This function posts a message to the log transport, performing buffering * of partially sent data if needed. The return value indicates whether we * successfully sent this message, or if it should be resent by the caller. **/ static LogProtoStatus log_proto_file_writer_post(LogProtoClient *s, LogMessage *logmsg, guchar *msg, gsize msg_len, gboolean *consumed) { LogProtoFileWriter *self = (LogProtoFileWriter *)s; LogProtoStatus result; *consumed = FALSE; if (self->buf_count >= self->buf_size || self->partial) { result = log_proto_file_writer_flush(s); if (result != LPS_SUCCESS || self->buf_count >= self->buf_size || self->partial) { /* don't consume a new message if flush failed OR if we couldn't * progress in flush() to empty the outgoing buffer (either * buffers or partial) */ return result; } } /* register the new message */ self->buffer[self->buf_count].iov_base = (void *) msg; self->buffer[self->buf_count].iov_len = msg_len; ++self->buf_count; self->sum_len += msg_len; *consumed = TRUE; if (self->buf_count == self->buf_size) { /* we have reached the max buffer size -> we need to write the messages */ return log_proto_file_writer_flush(s); } return LPS_SUCCESS; } static gboolean log_proto_file_writer_prepare(LogProtoClient *s, gint *fd, GIOCondition *cond, gint *timeout) { LogProtoFileWriter *self = (LogProtoFileWriter *) s; *fd = self->super.transport->fd; *cond = self->super.transport->cond; /* if there's no pending I/O in the transport layer, then we want to do a write */ if (*cond == 0) *cond = G_IO_OUT; const gboolean pending_write = self->buf_count > 0 || self->partial; if (!pending_write && s->options->timeout > 0) *timeout = s->options->timeout; return pending_write; } LogProtoClient * log_proto_file_writer_new(LogTransport *transport, const LogProtoClientOptions *options, gint flush_lines, gint fsync_) { if (flush_lines == 0) /* the flush-lines option has not been specified, use a default value */ flush_lines = 1; #ifdef IOV_MAX if (flush_lines > IOV_MAX) /* limit the flush_lines according to the current platform */ flush_lines = IOV_MAX; #endif /* allocate the structure with the proper number of items at the end */ LogProtoFileWriter *self = (LogProtoFileWriter *)g_malloc0(sizeof(LogProtoFileWriter) + sizeof( struct iovec)*flush_lines); log_proto_client_init(&self->super, transport, options); self->fd = transport->fd; self->buf_size = flush_lines; self->fsync = fsync_; self->super.prepare = log_proto_file_writer_prepare; self->super.post = log_proto_file_writer_post; self->super.flush = log_proto_file_writer_flush; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/logproto-file-writer.h000066400000000000000000000023641450431004300245230ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef LOG_PROTO_FILE_WRITER_H_INCLUDED #define LOG_PROTO_FILE_WRITER_H_INCLUDED #include "logproto/logproto-client.h" LogProtoClient *log_proto_file_writer_new(LogTransport *transport, const LogProtoClientOptions *options, gint flush_lines, gboolean fsync); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/named-pipe.c000066400000000000000000000107751450431004300224460ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "named-pipe.h" #include "affile-source.h" #include "affile-dest.h" #include "transport/transport-file.h" #include "transport/transport-pipe.h" #include "file-opener.h" #include "logproto/logproto-text-client.h" #include "messages.h" #include #include #include #include #include static gboolean _prepare_open(FileOpener *self, const gchar *name) { struct stat st; if (stat(name, &st) < 0 && (errno == ENOENT || errno == ENOTDIR)) { if (mkfifo(name, self->options->file_perm_options.file_perm) < 0) { msg_error("Error creating named pipe, mkfifo() returned an error", evt_tag_str("file", name), evt_tag_str("error", g_strerror(errno))); return FALSE; } return TRUE; } if (!S_ISFIFO(st.st_mode)) { msg_error("You are using the pipe() driver, underlying file is not a FIFO, it should be used by file()", evt_tag_str("filename", name)); errno = EINVAL; return FALSE; } return TRUE; } static gint _get_open_flags(FileOpener *self, FileDirection dir) { switch (dir) { case AFFILE_DIR_READ: case AFFILE_DIR_WRITE: return (O_RDWR | O_NOCTTY | O_NONBLOCK | O_LARGEFILE); default: g_assert_not_reached(); } } static LogTransport * _construct_transport(FileOpener *self, gint fd) { LogTransport *transport = log_transport_pipe_new(fd); transport->read = log_transport_file_read_and_ignore_eof_method; return transport; } static LogProtoServer * _construct_src_proto(FileOpener *s, LogTransport *transport, LogProtoFileReaderOptions *proto_options) { return log_proto_file_reader_new(transport, proto_options); } static LogProtoClient * _construct_dst_proto(FileOpener *self, LogTransport *transport, LogProtoClientOptions *proto_options) { return log_proto_text_client_new(transport, proto_options); } void pipe_sd_set_create_dirs(LogDriver *s, gboolean create_dirs) { AFFileSourceDriver *self = (AFFileSourceDriver *) s; self->file_opener_options.create_dirs = create_dirs; } FileOpener * file_opener_for_named_pipes_new(void) { FileOpener *self = file_opener_new(); self->prepare_open = _prepare_open; self->get_open_flags = _get_open_flags; self->construct_transport = _construct_transport; self->construct_src_proto = _construct_src_proto; self->construct_dst_proto = _construct_dst_proto; return self; } LogDriver * pipe_sd_new(gchar *filename, GlobalConfig *cfg) { AFFileSourceDriver *self = affile_sd_new_instance(filename, cfg); self->file_reader_options.reader_options.super.stats_source = stats_register_type("pipe"); if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_2)) { msg_warning_once("WARNING: the expected message format is being changed for pipe() to improve " "syslogd compatibity with " VERSION_3_2 ". If you are using custom " "applications which bypass the syslog() API, you might " "need the 'expect-hostname' flag to get the old behaviour back"); } else { self->file_reader_options.reader_options.parse_options.flags &= ~LP_EXPECT_HOSTNAME; } self->file_opener = file_opener_for_named_pipes_new(); return &self->super.super; } LogDriver * pipe_dd_new(LogTemplate *filename_template, GlobalConfig *cfg) { AFFileDestDriver *self = affile_dd_new_instance(filename_template, cfg); self->writer_options.stats_source = stats_register_type("pipe"); self->file_opener = file_opener_for_named_pipes_new(); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/named-pipe.h000066400000000000000000000025011450431004300224370ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_NAMED_PIPE_H_INCLUDED #define AFFILE_NAMED_PIPE_H_INCLUDED #include "driver.h" #include "cfg.h" #include "file-opener.h" void pipe_sd_set_create_dirs(LogDriver *s, gboolean create_dirs); FileOpener *file_opener_for_named_pipes_new(void); LogDriver *pipe_sd_new(gchar *filename, GlobalConfig *cfg); LogDriver *pipe_dd_new(LogTemplate *filename_template, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/poll-file-changes.c000066400000000000000000000165041450431004300237140ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "poll-file-changes.h" #include "logpipe.h" #include "timeutils/misc.h" #include #include #include #include #include #include #include #include #include #include #include #include static inline void poll_file_changes_on_read(PollFileChanges *self) { if (self->on_read) self->on_read(self); poll_events_invoke_callback(&self->super); } static inline void poll_file_changes_on_file_moved(PollFileChanges *self) { if (self->on_file_moved) self->on_file_moved(self); log_pipe_notify(self->control, NC_FILE_MOVED, self); } static inline gboolean poll_file_changes_on_eof(PollFileChanges *self) { gboolean result = TRUE; if (self->on_eof) result = self->on_eof(self); log_pipe_notify(self->control, NC_FILE_EOF, self); return result; } /* follow timer callback. Check if the file has new content, or deleted or * moved. Ran every follow_freq seconds. */ static void poll_file_changes_check_file(gpointer s) { PollFileChanges *self = (PollFileChanges *) s; struct stat st, followed_st; off_t pos = -1; gint fd = self->fd; msg_trace("Checking if the followed file has new lines", evt_tag_str("follow_filename", self->follow_filename)); if (fd >= 0) { pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) { msg_error("Error invoking seek on followed file", evt_tag_error("error")); goto reschedule; } if (fstat(fd, &st) < 0) { if (errno == ESTALE) { msg_trace("poll-file-changes: file moved ESTALE", evt_tag_str("follow_filename", self->follow_filename)); poll_file_changes_on_file_moved(self); return; } else { msg_error("Error invoking fstat() on followed file", evt_tag_error("error")); goto reschedule; } } msg_trace("poll-file-changes", evt_tag_int("pos", pos), evt_tag_int("size", st.st_size), evt_tag_int("fd", fd)); if (pos < st.st_size || !S_ISREG(st.st_mode)) { msg_trace("poll-file-changes: file has new content: initiate reading"); poll_file_changes_on_read(self); return; } else if (pos > st.st_size) { /* the last known position is larger than the current size of the file. it got truncated. Restart from the beginning. */ msg_trace("poll-file-changes: file got truncated, restart from beginning", evt_tag_int("pos", pos), evt_tag_int("size", st.st_size), evt_tag_int("fd", fd)); poll_file_changes_on_file_moved(self); /* we may be freed by the time the notification above returns */ return; } } if (self->follow_filename) { if (stat(self->follow_filename, &followed_st) != -1) { if (fd < 0 || (st.st_ino != followed_st.st_ino && followed_st.st_size > 0)) { msg_trace("poll-file-changes: file moved eof", evt_tag_int("pos", pos), evt_tag_int("size", followed_st.st_size), evt_tag_str("follow_filename", self->follow_filename)); /* file was moved and we are at EOF, follow the new file */ poll_file_changes_on_file_moved(self); /* we may be freed by the time the notification above returns */ return; } } else { msg_verbose("Follow mode file still does not exist", evt_tag_str("filename", self->follow_filename)); } } reschedule: poll_events_update_watches(s, G_IO_IN); } void poll_file_changes_stop_watches(PollEvents *s) { PollFileChanges *self = (PollFileChanges *) s; if (iv_timer_registered(&self->follow_timer)) iv_timer_unregister(&self->follow_timer); } static void poll_file_changes_rearm_timer(PollFileChanges *self) { iv_validate_now(); self->follow_timer.expires = iv_now; timespec_add_msec(&self->follow_timer.expires, self->follow_freq); iv_timer_register(&self->follow_timer); } static gboolean poll_file_changes_check_eof(PollFileChanges *self) { gint fd = self->fd; if (fd < 0) return FALSE; off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) { msg_error("Error invoking seek on followed file", evt_tag_str("follow_filename", self->follow_filename), evt_tag_error("error")); return FALSE; } struct stat st; gboolean end_of_file = fstat(fd, &st) == 0 && pos == st.st_size; return end_of_file; } void poll_file_changes_update_watches(PollEvents *s, GIOCondition cond) { PollFileChanges *self = (PollFileChanges *) s; gboolean check_again = TRUE; /* we can only provide input events */ g_assert((cond & ~G_IO_IN) == 0); poll_file_changes_stop_watches(s); if (poll_file_changes_check_eof(self)) { msg_trace("End of file, following file", evt_tag_str("follow_filename", self->follow_filename)); check_again = poll_file_changes_on_eof(self); } if (check_again) poll_file_changes_rearm_timer(self); } void poll_file_changes_free(PollEvents *s) { PollFileChanges *self = (PollFileChanges *) s; log_pipe_unref(self->control); g_free(self->follow_filename); } void poll_file_changes_init_instance(PollFileChanges *self, gint fd, const gchar *follow_filename, gint follow_freq, LogPipe *control) { self->super.stop_watches = poll_file_changes_stop_watches; self->super.update_watches = poll_file_changes_update_watches; self->super.free_fn = poll_file_changes_free; self->fd = fd; self->follow_filename = g_strdup(follow_filename); self->follow_freq = follow_freq; self->control = log_pipe_ref(control); IV_TIMER_INIT(&self->follow_timer); self->follow_timer.cookie = self; self->follow_timer.handler = poll_file_changes_check_file; } PollEvents * poll_file_changes_new(gint fd, const gchar *follow_filename, gint follow_freq, LogPipe *control) { PollFileChanges *self = g_new0(PollFileChanges, 1); poll_file_changes_init_instance(self, fd, follow_filename, follow_freq, control); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/poll-file-changes.h000066400000000000000000000035401450431004300237150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef POLL_FILE_CHANGES_H_INCLUDED #define POLL_FILE_CHANGES_H_INCLUDED #include "poll-events.h" #include "logpipe.h" #include typedef struct _PollFileChanges PollFileChanges; struct _PollFileChanges { PollEvents super; gint fd; gchar *follow_filename; gint follow_freq; struct iv_timer follow_timer; LogPipe *control; void (*on_read)(PollFileChanges *); gboolean (*on_eof)(PollFileChanges *); void (*on_file_moved)(PollFileChanges *); }; PollEvents *poll_file_changes_new(gint fd, const gchar *follow_filename, gint follow_freq, LogPipe *control); void poll_file_changes_init_instance(PollFileChanges *self, gint fd, const gchar *follow_filename, gint follow_freq, LogPipe *control); void poll_file_changes_update_watches(PollEvents *s, GIOCondition cond); void poll_file_changes_stop_watches(PollEvents *s); void poll_file_changes_free(PollEvents *s); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/poll-multiline-file-changes.c000066400000000000000000000105171450431004300257120ustar00rootroot00000000000000/* * Copyright (c) 2019 One Identity * Copyright (c) 2019 László Várady * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "syslog-ng.h" #include "poll-multiline-file-changes.h" #include "messages.h" #include #include #include #include typedef struct PollMultilineFileChanges { PollFileChanges super; FileReader *file_reader; gint multi_line_timeout; gboolean timed_out; gint64 last_eof; } PollMultilineFileChanges; static void _flush_partial_message(PollMultilineFileChanges *self) { file_reader_cue_buffer_flush(self->file_reader); /* invoke fetch */ poll_events_invoke_callback(&self->super.super); } static void poll_multiline_file_changes_start_timer(PollMultilineFileChanges *self) { self->last_eof = g_get_monotonic_time(); } static void poll_multiline_file_changes_stop_timer(PollMultilineFileChanges *self) { self->last_eof = 0; } static void poll_multiline_file_changes_timeout_expired(PollMultilineFileChanges *self) { msg_debug("Multi-line timeout has elapsed, processing partial message", evt_tag_str("filename", self->super.follow_filename)); self->last_eof = 0; self->timed_out = TRUE; _flush_partial_message(self); } static gboolean _is_multi_line_timeout_pending(PollMultilineFileChanges *self) { return self->last_eof != 0; } static gboolean _is_multi_line_timeout_expired(PollMultilineFileChanges *self) { if (self->last_eof == 0) return FALSE; gint64 millisecs_since_last_eof = (g_get_monotonic_time() - self->last_eof) / 1000; return millisecs_since_last_eof > self->multi_line_timeout; } static gboolean poll_multiline_file_changes_on_eof(PollFileChanges *s) { PollMultilineFileChanges *self = (PollMultilineFileChanges *) s; if (self->timed_out) return TRUE; if (!_is_multi_line_timeout_pending(self)) { poll_multiline_file_changes_start_timer(self); return TRUE; } if (_is_multi_line_timeout_expired(self)) { poll_multiline_file_changes_timeout_expired(self); return FALSE; } return TRUE; } static void poll_multiline_file_changes_on_file_moved(PollFileChanges *s) { PollMultilineFileChanges *self = (PollMultilineFileChanges *) s; poll_multiline_file_changes_stop_timer(self); } static void poll_multiline_file_changes_on_read(PollFileChanges *s) { PollMultilineFileChanges *self = (PollMultilineFileChanges *) s; poll_multiline_file_changes_stop_timer(self); self->timed_out = FALSE; } static void poll_multiline_file_changes_stop_watches(PollEvents *s) { PollMultilineFileChanges *self = (PollMultilineFileChanges *) s; poll_multiline_file_changes_stop_timer(self); poll_file_changes_stop_watches(s); } PollEvents * poll_multiline_file_changes_new(gint fd, const gchar *follow_filename, gint follow_freq, gint multi_line_timeout, FileReader *reader) { PollMultilineFileChanges *self = g_new0(PollMultilineFileChanges, 1); poll_file_changes_init_instance(&self->super, fd, follow_filename, follow_freq, &reader->super); self->multi_line_timeout = multi_line_timeout; if (!self->multi_line_timeout) return &self->super.super; self->file_reader = reader; self->super.on_read = poll_multiline_file_changes_on_read; self->super.on_eof = poll_multiline_file_changes_on_eof; self->super.on_file_moved = poll_multiline_file_changes_on_file_moved; self->super.super.update_watches = poll_file_changes_update_watches; self->super.super.stop_watches = poll_multiline_file_changes_stop_watches; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/poll-multiline-file-changes.h000066400000000000000000000024031450431004300257120ustar00rootroot00000000000000/* * Copyright (c) 2019 One Identity * Copyright (c) 2019 László Várady * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef POLL_MULTILINE_FILE_CHANGES_H #define POLL_MULTILINE_FILE_CHANGES_H #include "poll-file-changes.h" #include "file-reader.h" PollEvents *poll_multiline_file_changes_new(gint fd, const gchar *follow_filename, gint follow_freq, gint multi_line_timeout, FileReader *reader); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/regular-files.c000066400000000000000000000067571450431004300231750ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-specializations.h" #include "transport/transport-file.h" #include "logproto-file-writer.h" #include "messages.h" #include "ack-tracker/ack_tracker_factory.h" #include #include #include #include static gboolean _prepare_open(FileOpener *self, const gchar *name) { struct stat st; if (stat(name, &st) >= 0) { if (S_ISFIFO(st.st_mode)) { msg_error("You are using the file() driver, underlying file is a FIFO, it should be used by pipe()", evt_tag_str("filename", name)); errno = EINVAL; return FALSE; } } return TRUE; } static LogTransport * _construct_src_transport(FileOpener *self, gint fd) { LogTransport *transport = log_transport_file_new(fd); transport->read = log_transport_file_read_and_ignore_eof_method; return transport; } static LogProtoServer * _construct_src_proto(FileOpener *s, LogTransport *transport, LogProtoFileReaderOptions *proto_options) { log_proto_server_options_set_ack_tracker_factory(&proto_options->super, consecutive_ack_tracker_factory_new()); return log_proto_file_reader_new(transport, proto_options); } FileOpener * file_opener_for_regular_source_files_new(void) { FileOpener *self = file_opener_new(); self->prepare_open = _prepare_open; self->construct_transport = _construct_src_transport; self->construct_src_proto = _construct_src_proto; return self; } typedef struct _FileOpenerRegularDestFiles { FileOpener super; const LogWriterOptions *writer_options; gboolean *use_fsync; } FileOpenerRegularDestFiles; static LogProtoClient * _construct_dst_proto(FileOpener *s, LogTransport *transport, LogProtoClientOptions *proto_options) { FileOpenerRegularDestFiles *self = (FileOpenerRegularDestFiles *) s; return log_proto_file_writer_new(transport, proto_options, self->writer_options->flush_lines, *self->use_fsync); } static LogTransport * _construct_transport(FileOpener *s, gint fd) { return log_transport_file_new(fd); } FileOpener * file_opener_for_regular_dest_files_new(const LogWriterOptions *writer_options, gboolean *use_fsync) { FileOpenerRegularDestFiles *self = g_new0(FileOpenerRegularDestFiles, 1); file_opener_init_instance(&self->super); self->super.construct_transport = _construct_transport; self->super.construct_dst_proto = _construct_dst_proto; self->writer_options = writer_options; self->use_fsync = use_fsync; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/stdin.c000066400000000000000000000037531450431004300215460ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-specializations.h" #include "transport/transport-file.h" #include "affile-source.h" #include static LogTransport * _construct_transport(FileOpener *self, gint fd) { return log_transport_file_new(fd); } static LogProtoServer * _construct_src_proto(FileOpener *s, LogTransport *transport, LogProtoFileReaderOptions *proto_options) { return log_proto_file_reader_new(transport, proto_options); } static gint _open(FileOpener *self, const gchar *name, gint flags) { return dup(0); } FileOpener * file_opener_for_stdin_new(void) { FileOpener *self = file_opener_new(); self->construct_transport = _construct_transport; self->construct_src_proto = _construct_src_proto; self->open = _open; return self; } LogDriver * stdin_sd_new(GlobalConfig *cfg) { AFFileSourceDriver *self = affile_sd_new_instance("-", cfg); self->file_reader_options.exit_on_eof = TRUE; self->file_reader_options.reader_options.super.stats_source = stats_register_type("stdin"); self->file_opener = file_opener_for_stdin_new(); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/stdin.h000066400000000000000000000021151450431004300215420ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_STDIN_H_INCLUDED #define AFFILE_STDIN_H_INCLUDED #include "driver.h" #include "cfg.h" LogDriver *stdin_sd_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/stdout.c000066400000000000000000000041261450431004300217420ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "file-specializations.h" #include "transport/transport-file.h" #include "affile-dest.h" #include "logproto-file-writer.h" #include static LogTransport * _construct_transport(FileOpener *self, gint fd) { return log_transport_file_new(fd); } static LogProtoClient * _construct_dst_proto(FileOpener *s, LogTransport *transport, LogProtoClientOptions *proto_options) { return log_proto_file_writer_new(transport, proto_options, 0, FALSE); } static gint _open(FileOpener *self, const gchar *name, gint flags) { return dup(1); } FileOpener * file_opener_for_stdout_new(void) { FileOpener *self = file_opener_new(); self->construct_transport = _construct_transport; self->construct_dst_proto = _construct_dst_proto; self->open = _open; return self; } LogDriver * stdout_dd_new(GlobalConfig *cfg) { LogTemplate *filename_template = log_template_new(cfg, NULL); log_template_compile_literal_string(filename_template, "-"); AFFileDestDriver *self = affile_dd_new_instance(filename_template, cfg); self->writer_options.stats_source = stats_register_type("stdout"); self->file_opener = file_opener_for_stdout_new(); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/stdout.h000066400000000000000000000021201450431004300217370ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_STDOUT_H_INCLUDED #define AFFILE_STDOUT_H_INCLUDED #include "driver.h" #include "cfg.h" LogDriver *stdout_dd_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/tests/000077500000000000000000000000001450431004300214135ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/affile/tests/CMakeLists.txt000066400000000000000000000007531450431004300241600ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_wildcard_source DEPENDS affile) add_unit_test(CRITERION TARGET test_directory_monitor DEPENDS affile) add_unit_test(CRITERION TARGET test_collection_comparator DEPENDS affile) add_unit_test(CRITERION LIBTEST TARGET test_file_writer DEPENDS affile) add_unit_test(CRITERION TARGET test_file_opener DEPENDS affile) add_unit_test(CRITERION TARGET test_wildcard_file_reader DEPENDS affile) add_unit_test(CRITERION TARGET test_file_list DEPENDS affile) syslog-ng-syslog-ng-4.4.0/modules/affile/tests/Makefile.am000066400000000000000000000040531450431004300234510ustar00rootroot00000000000000check_PROGRAMS += \ ${modules_affile_tests_TESTS} EXTRA_DIST += modules/affile/tests/CMakeLists.txt modules_affile_tests_TESTS = \ modules/affile/tests/test_wildcard_source \ modules/affile/tests/test_directory_monitor \ modules/affile/tests/test_collection_comparator \ modules/affile/tests/test_file_opener \ modules/affile/tests/test_wildcard_file_reader \ modules/affile/tests/test_file_list \ modules/affile/tests/test_file_writer modules_affile_tests_test_wildcard_source_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_wildcard_source_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la modules_affile_tests_test_directory_monitor_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_directory_monitor_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la modules_affile_tests_test_collection_comparator_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_collection_comparator_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la modules_affile_tests_test_file_opener_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_file_opener_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la modules_affile_tests_test_wildcard_file_reader_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_wildcard_file_reader_LDADD = $(TEST_LDADD) modules_affile_tests_test_wildcard_file_reader_SOURCES = modules/affile/tests/test_wildcard_file_reader.c modules/affile/wildcard-file-reader.c modules_affile_tests_test_file_list_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_file_list_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la modules_affile_tests_test_file_writer_CFLAGS = $(TEST_CFLAGS) -I$(top_srcdir)/modules/affile modules_affile_tests_test_file_writer_LDADD = $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/affile/libaffile.la syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_collection_comparator.c000066400000000000000000000104071450431004300272020ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "collection-comparator.h" #include #include typedef struct _TestData { GHashTable *deleted_entries; GHashTable *new_entries; } TestData; static const gchar *TEST = "test"; TestData * test_data_new(void) { TestData *self = g_new0(TestData, 1); self->deleted_entries = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); self->new_entries = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); return self; } void test_data_free(TestData *self) { g_hash_table_unref(self->deleted_entries); g_hash_table_unref(self->new_entries); g_free(self); } static void _handle_new(const gchar *filename, gpointer data) { TestData *self = (TestData *)data; g_hash_table_insert(self->new_entries, g_strdup(filename), (gchar *)TEST); } static void _handle_delete(const gchar *filename, gpointer data) { TestData *self = (TestData *)data; g_hash_table_insert(self->deleted_entries, g_strdup(filename), (gchar *)TEST); } struct TestFileList { const gchar *initial_files[10]; const gchar *result_files[10]; const gchar *expected_deleted_files[10]; const gchar *expected_new_files[10]; }; struct TestFileList nothing_changed = {{"test1", "test2"}, {"test1", "test2"}, {NULL}, {NULL}}; struct TestFileList last_file_deleted = {{"test1", "test2"}, {"test2"}, {"test1"}, {NULL}}; struct TestFileList first_file_deleted = {{"test1", "test2"}, {"test1"}, {"test2"}, {NULL}}; struct TestFileList delete_all = {{"test1", "test2"}, {NULL}, {"test1", "test2"}, {NULL}}; struct TestFileList create_all = {{NULL}, {"test1", "test2"}, {NULL}, {"test1", "test2"}}; struct TestFileList mixed = {{"test1", "test2", "test3"}, {"test1", "test4"}, {"test2", "test3"}, {"test4"}}; ParameterizedTestParameters(params, multiple) { static struct TestFileList params[6]; params[0] = nothing_changed; params[1] = last_file_deleted; params[2] = first_file_deleted; params[3] = delete_all; params[4] = create_all; params[5] = mixed; return cr_make_param_array(struct TestFileList, params, sizeof (params) / sizeof (struct TestFileList)); } ParameterizedTest(struct TestFileList *tup, params, multiple) { TestData *data = test_data_new(); CollectionComparator *comporator = collection_comparator_new(); collection_comporator_set_callbacks(comporator, _handle_new, _handle_delete, data); gint i; for (i = 0; tup->initial_files[i] != NULL; i++) { collection_comparator_add_initial_value(comporator, tup->initial_files[i]); } collection_comparator_start(comporator); for (i = 0; tup->result_files[i] != NULL; i++) { collection_comparator_add_value(comporator, tup->result_files[i]); } collection_comparator_stop(comporator); for (i = 0; tup->expected_deleted_files[i] != NULL; i++) { cr_assert_str_eq(g_hash_table_lookup(data->deleted_entries, tup->expected_deleted_files[i]), TEST); } cr_assert_eq(g_hash_table_size(data->deleted_entries), i); for (i = 0; tup->expected_new_files[i] != NULL; i++) { cr_assert_str_eq(g_hash_table_lookup(data->new_entries, tup->expected_new_files[i]), TEST); } cr_assert_eq(g_hash_table_size(data->new_entries), i); collection_comparator_free(comporator); test_data_free(data); } syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_directory_monitor.c000066400000000000000000000112401450431004300263670ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "directory-monitor.h" #include "directory-monitor-factory.h" #if SYSLOG_NG_HAVE_INOTIFY #include "directory-monitor-inotify.h" #endif #include "directory-monitor-poll.h" #include "apphook.h" #include #include TestSuite(directory_monitor, .init = app_startup, .fini = app_shutdown); static void _callback(const DirectoryMonitorEvent *event, gpointer user_data) { GList **p_list = (GList **)user_data; if (event->event_type == FILE_CREATED) { *p_list = g_list_append(*p_list, g_strdup(event->name)); } } Test(directory_monitor, read_content_of_directory) { gchar *dir_pattern = g_strdup("read_content_of_directoryXXXXXX"); gchar *tmpdir = g_mkdtemp(dir_pattern); cr_assert(tmpdir); gchar *file_list[10] = {0}; gchar *file_list_full_path[10] = {0}; for (gint i = 0; i < 10; i++) { GError *error = NULL; file_list[i] = g_strdup_printf("file_%d.txt", i); file_list_full_path[i] = g_build_filename(tmpdir, file_list[i], NULL);; gboolean res = g_file_set_contents(file_list_full_path[i], file_list[i], strlen(file_list[i]), &error); cr_assert(res != FALSE, "Error: %s", error ? error->message : "OK"); } DirectoryMonitor *monitor = directory_monitor_new(tmpdir, 1); GList *found_files = NULL; directory_monitor_set_callback(monitor, _callback, &found_files); directory_monitor_start(monitor); for (gint i = 0; i < 10; i++) { cr_assert(g_list_find_custom(found_files, file_list[i], (GCompareFunc)strcmp), "Can not find: %s", file_list[i]); unlink(file_list_full_path[i]); g_free(file_list_full_path[i]); g_free(file_list[i]); } g_list_free_full(found_files, g_free); g_rmdir(tmpdir); g_free(tmpdir); directory_monitor_free(monitor); } Test(directory_monitor, non_existing_directory) { DirectoryMonitor *monitor = directory_monitor_new("this directory should not exist", 1); GList *found_files = NULL; directory_monitor_set_callback(monitor, _callback, &found_files); directory_monitor_start(monitor); cr_assert_null(found_files); directory_monitor_free(monitor); } TestSuite(directory_monitor_tools, .init = app_startup, .fini = app_shutdown); Test(directory_monitor_tools, build_filename) { gchar *built_path = build_filename(NULL, "tmp"); cr_assert_str_eq("tmp", built_path); g_free(built_path); built_path = build_filename("tmp", "test_dir"); cr_assert_str_eq("tmp/test_dir", built_path); g_free(built_path); built_path = build_filename("tmp", NULL); cr_assert_eq(NULL, built_path); } TestSuite(directory_monitor_factory, .init = app_startup, .fini = app_shutdown); Test(directory_monitor_factory, check_monitor_method) { #if SYSLOG_NG_HAVE_INOTIFY cr_assert_eq(MM_INOTIFY, directory_monitor_factory_get_monitor_method("inotify")); #endif cr_assert_eq(MM_AUTO, directory_monitor_factory_get_monitor_method("auto")); cr_assert_eq(MM_POLL, directory_monitor_factory_get_monitor_method("poll")); cr_assert_eq(MM_UNKNOWN, directory_monitor_factory_get_monitor_method("something else")); } Test(directory_monitor_factory, check_constructor) { DirectoryMonitorOptions options = {.dir = "/tmp", .follow_freq = 1, .method = MM_AUTO}; #if SYSLOG_NG_HAVE_INOTIFY cr_assert_eq(directory_monitor_factory_get_constructor(&options), directory_monitor_inotify_new); options.method = MM_INOTIFY; cr_assert_eq(directory_monitor_factory_get_constructor(&options), directory_monitor_inotify_new); #else cr_assert_eq(directory_monitor_factory_get_constructor(&options), directory_monitor_poll_new); #endif options.method = MM_POLL; cr_assert_eq(directory_monitor_factory_get_constructor(&options), directory_monitor_poll_new); options.method = MM_UNKNOWN; cr_assert_eq(directory_monitor_factory_get_constructor(&options), NULL); } syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_file_list.c000066400000000000000000000147651450431004300246050ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "file-list.h" TestSuite(hashed_queue, .init = NULL, .fini = NULL); Test(hashed_queue, normal) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); gchar *f1 = pending_file_list_pop(queue); gchar *f2 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert_str_eq(f1, "file1"); cr_assert_str_eq(f2, "file2"); cr_assert_str_eq(f3, "file3"); g_free(f1); g_free(f2); g_free(f3); pending_file_list_free(queue); } Test(hashed_queue, delete_first) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); cr_assert_eq(pending_file_list_remove(queue, "file1"), TRUE); gchar *f2 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert_str_eq(f2, "file2"); cr_assert_str_eq(f3, "file3"); g_free(f2); g_free(f3); pending_file_list_free(queue); } Test(hashed_queue, delete_middle) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); cr_assert_eq(pending_file_list_remove(queue, "file2"), TRUE); gchar *f1 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert_str_eq(f1, "file1"); cr_assert_str_eq(f3, "file3"); g_free(f1); g_free(f3); pending_file_list_free(queue); } Test(hashed_queue, delete_last) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); cr_assert_eq(pending_file_list_remove(queue, "file3"), TRUE); gchar *f1 = pending_file_list_pop(queue); gchar *f2 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert_str_eq(f1, "file1"); cr_assert_str_eq(f2, "file2"); cr_assert_eq(f3, NULL); g_free(f1); g_free(f2); pending_file_list_free(queue); } Test(hashed_queue, delete_non_existent) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); cr_assert_eq(pending_file_list_remove(queue, "file4"), FALSE); gchar *f1 = pending_file_list_pop(queue); gchar *f2 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert_str_eq(f1, "file1"); cr_assert_str_eq(f2, "file2"); cr_assert_str_eq(f3, "file3"); g_free(f1); g_free(f2); g_free(f3); pending_file_list_free(queue); } Test(hashed_queue, no_duplication) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); pending_file_list_add(queue, "file1"); gchar *f1 = pending_file_list_pop(queue); gchar *f2 = pending_file_list_pop(queue); gchar *f3 = pending_file_list_pop(queue); cr_assert(pending_file_list_pop(queue) == NULL); cr_assert_str_eq(f1, "file1"); cr_assert_str_eq(f2, "file2"); cr_assert_str_eq(f3, "file3"); g_free(f1); g_free(f2); g_free(f3); pending_file_list_free(queue); } Test(hashed_queue, reverse_iterator_in_empty) { PendingFileList *queue = pending_file_list_new(); GList *f1 = pending_file_list_begin(queue); cr_assert_null(f1); pending_file_list_free(queue); } Test(hashed_queue, reverse_iterator_one_entry) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); GList *f1 = pending_file_list_begin(queue); cr_assert_not_null(f1); cr_assert_str_eq(f1->data, "file1"); pending_file_list_free(queue); } Test(hashed_queue, reverse_iterator_two_entry) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file3"); pending_file_list_add(queue, "file1"); GList *f1 = pending_file_list_begin(queue); cr_assert_not_null(f1); cr_assert_str_eq(f1->data, "file3"); pending_file_list_free(queue); } Test(hashed_queue, reverse_iterator_second_entry) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); GList *it = pending_file_list_begin(queue); it = pending_file_list_next(it); cr_assert_not_null(it); cr_assert_str_eq(it->data, "file2"); pending_file_list_free(queue); } Test(hashed_queue, reverse_iterator_count_entries) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); pending_file_list_add(queue, "file2"); pending_file_list_add(queue, "file3"); gint length = 0; for (GList *it = pending_file_list_begin(queue); it != pending_file_list_end(queue); it = pending_file_list_next(it)) ++length; cr_assert_eq(length, 3); pending_file_list_free(queue); } Test(hashed_queue, steal_from_empty) { PendingFileList *queue = pending_file_list_new(); GList *it = pending_file_list_begin(queue); pending_file_list_steal(queue, it); cr_assert_null(it); pending_file_list_free(queue); } Test(hashed_queue, steal_from_one_entry) { PendingFileList *queue = pending_file_list_new(); pending_file_list_add(queue, "file1"); GList *it = pending_file_list_begin(queue); pending_file_list_steal(queue, it); cr_assert_not_null(it); cr_assert_str_eq(it->data, "file1"); cr_assert_null(pending_file_list_begin(queue)); g_free(it->data); g_list_free_1(it); pending_file_list_free(queue); } syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_file_opener.c000066400000000000000000000110011450431004300250760ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Laszlo Budai * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "file-opener.h" #include "named-pipe.h" #include "file-specializations.h" #include "messages.h" #include #include #include #include #include #include #include #define CREATE_DIRS 0x01 #define SRC_FILE 0x02 #define DST_FILE 0x04 static mode_t get_fd_file_mode(gint fd) { struct stat st; fstat(fd, &st); return st.st_mode; } static gboolean open_fd(FileOpener *file_opener, gchar *fname, gint extra_flags, gint *fd) { FileOpenerOptions open_opts; FileDirection dir; if (extra_flags & DST_FILE) dir = AFFILE_DIR_WRITE; else if (extra_flags & SRC_FILE) dir = AFFILE_DIR_READ; else g_assert_not_reached(); file_opener_options_defaults(&open_opts); file_opener_options_init(&open_opts, configuration); open_opts.create_dirs = !!(extra_flags & CREATE_DIRS); open_opts.needs_privileges = FALSE; file_opener_set_options(file_opener, &open_opts); gboolean success = file_opener_open_fd(file_opener, fname, dir, fd) == FILE_OPENER_RESULT_SUCCESS; file_opener_free(file_opener); return success; } static gboolean open_regular_source_file(gchar *fname, gint extra_flags, gint *fd) { FileOpener *file_opener = file_opener_for_regular_source_files_new(); return open_fd(file_opener, fname, extra_flags, fd); } static gboolean open_named_pipe(gchar *fname, gint extra_flags, gint *fd) { FileOpener *file_opener = file_opener_for_named_pipes_new(); return open_fd(file_opener, fname, extra_flags, fd); } Test(file_opener, test_open_regular_file) { gint fd; gchar fname[] = "test.log"; cr_assert(open_regular_source_file(fname, DST_FILE, &fd), "file_opener_open_fd failed: %s", fname); cr_assert(S_ISREG(get_fd_file_mode(fd)) != 0, "%s is not regular file", fname); close(fd); cr_assert(open_regular_source_file(fname, SRC_FILE, &fd), "file_opener_open_fd failed: %s", fname); cr_assert(S_ISREG(get_fd_file_mode(fd)) != 0, "%s is not regular file", fname); close(fd); remove(fname); } Test(file_opener, test_open_named_pipe) { gint fd; gchar fname[] = "test.pipe"; cr_assert(open_named_pipe(fname, SRC_FILE, &fd), "failed to open %s", fname); cr_assert(S_ISFIFO(get_fd_file_mode(fd)) != 0, "%s is not pipe", fname); close(fd); remove(fname); } Test(file_opener, test_spurious_path) { gint fd; gchar fname[] = "./../test.fname"; cr_assert_not(open_regular_source_file(fname, DST_FILE, &fd), "file_opener_open_fd should not be able to open: %s", fname); } Test(file_opener, test_create_file_in_nonexistent_dir) { gchar test_dir[] = "nonexistent"; gchar fname[] = "nonexistent/test.txt"; gint fd; cr_assert_not(open_regular_source_file(fname, DST_FILE, &fd), "file_opener_open_fd failed: %s", fname); cr_assert(open_regular_source_file(fname, CREATE_DIRS | DST_FILE, &fd), "file_opener_open_fd failed: %s", fname); close(fd); remove(fname); rmdir(test_dir); } Test(file_opener, test_file_flags) { gint fd; gchar fname[] = "test_flags.log"; cr_assert(open_regular_source_file(fname, DST_FILE, &fd), "file_opener_open_fd failed: %s", fname); cr_assert((fcntl(fd, F_GETFL) & O_APPEND) == O_APPEND, "invalid open flags"); close(fd); cr_assert(open_regular_source_file(fname, SRC_FILE, &fd), "file_opener_open_fd failed: %s", fname); cr_assert((fcntl(fd, F_GETFL) & O_APPEND) != O_APPEND, "invalid open flags"); close(fd); remove(fname); } static void setup(void) { msg_init(FALSE); configuration = cfg_new_snippet(); } void teardown(void) { } TestSuite(file_opener, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_file_writer.c000066400000000000000000000140711450431004300251340ustar00rootroot00000000000000/* * Copyright (c) 2019 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "libtest/mock-transport.h" #include "logproto-file-writer.h" #include "logmsg/logmsg.h" #include "apphook.h" static void _ack_callback(gint num_acked, gpointer user_data); /* helper variables used by all testcases below */ static LogProtoClientOptions options = {0}; static LogMessage *msg; static LogTransport *transport; static LogProtoClientFlowControlFuncs flow_control_funcs = { .ack_callback = _ack_callback, }; static gchar output_buffer[8192]; static LogProtoStatus status; static gint messages_acked = 0; static gboolean consumed; static const gchar *payload = "PAYLOAD"; static gssize count; static void _ack_callback(gint num_acked, gpointer user_data) { messages_acked += num_acked; } Test(file_writer, write_single_message_and_flush_is_expected_to_dump_the_payload_to_the_output) { LogProtoClient *fw = log_proto_file_writer_new(transport, &options, 100, FALSE); log_proto_client_set_client_flow_control(fw, &flow_control_funcs); status = log_proto_client_post(fw, msg, (guchar *) g_strdup(payload), strlen(payload) + 1, &consumed); cr_assert(status == LPS_SUCCESS); cr_assert(consumed == TRUE); status = log_proto_client_flush(fw); cr_assert(status == LPS_SUCCESS); log_transport_mock_read_from_write_buffer((LogTransportMock *) transport, output_buffer, sizeof(output_buffer)); cr_assert_str_eq(output_buffer, "PAYLOAD"); cr_assert(messages_acked == 1); log_proto_client_free(fw); } Test(file_writer, batches_of_messages_should_be_flushed_to_the_output) { const gint BATCH_SIZE = 10; const gint MESSAGE_COUNT = BATCH_SIZE * 3; LogProtoClient *fw = log_proto_file_writer_new(transport, &options, BATCH_SIZE, FALSE); log_proto_client_set_client_flow_control(fw, &flow_control_funcs); for (gint i = 0; i < MESSAGE_COUNT; i++) { status = log_proto_client_post(fw, msg, (guchar *) g_strdup(payload), strlen(payload) + 1, &consumed); cr_assert(status == LPS_SUCCESS); cr_assert(consumed == TRUE); } status = log_proto_client_flush(fw); cr_assert(status == LPS_SUCCESS); count = log_transport_mock_read_from_write_buffer((LogTransportMock *) transport, output_buffer, sizeof(output_buffer)); cr_assert_eq(count, MESSAGE_COUNT * (strlen(payload) + 1)); for (gint i = 0; i < MESSAGE_COUNT; i++) { const gchar *output_element = output_buffer + i * (strlen(payload) + 1); cr_assert_str_eq(output_element, "PAYLOAD"); } cr_assert_eq(messages_acked, MESSAGE_COUNT); log_proto_client_free(fw); } Test(file_writer, messages_should_be_flushed_automatically_once_we_reach_batch_size) { const gint BATCH_SIZE = 10; LogProtoClient *fw = log_proto_file_writer_new(transport, &options, BATCH_SIZE, FALSE); log_proto_client_set_client_flow_control(fw, &flow_control_funcs); for (gint i = 0; i < BATCH_SIZE - 1; i++) { status = log_proto_client_post(fw, msg, (guchar *) g_strdup(payload), strlen(payload) + 1, &consumed); cr_assert(status == LPS_SUCCESS); cr_assert(consumed == TRUE); } count = log_transport_mock_read_from_write_buffer((LogTransportMock *) transport, output_buffer, sizeof(output_buffer)); cr_assert_eq(count, 0); /* Push an extra item, which causes the BATCH_SIZE limit to be reached. There's an automatic flush in this case. */ status = log_proto_client_post(fw, msg, (guchar *) g_strdup(payload), strlen(payload) + 1, &consumed); cr_assert(status == LPS_SUCCESS); cr_assert(consumed == TRUE); count = log_transport_mock_read_from_write_buffer((LogTransportMock *) transport, output_buffer, sizeof(output_buffer)); cr_assert_eq(count, BATCH_SIZE * (strlen(payload) + 1)); cr_assert_eq(messages_acked, BATCH_SIZE); log_proto_client_free(fw); } Test(file_writer, batches_of_messages_are_flushed_even_if_the_underlying_transport_is_accepting_a_few_bytes_per_write) { const gint BATCH_SIZE = 10; LogProtoClient *fw = log_proto_file_writer_new(transport, &options, BATCH_SIZE, FALSE); log_transport_mock_set_write_chunk_limit((LogTransportMock *) transport, 2); log_proto_client_set_client_flow_control(fw, &flow_control_funcs); for (gint i = 0; i < BATCH_SIZE; i++) { status = log_proto_client_post(fw, msg, (guchar *) g_strdup(payload), strlen(payload) + 1, &consumed); cr_assert(status == LPS_SUCCESS, "status=%d", status); cr_assert(consumed == TRUE); } while ((status = log_proto_client_flush(fw)) == LPS_PARTIAL) ; cr_assert(status == LPS_SUCCESS); count = log_transport_mock_read_from_write_buffer((LogTransportMock *) transport, output_buffer, sizeof(output_buffer)); cr_assert_eq(count, BATCH_SIZE * (strlen(payload) + 1)); for (gint i = 0; i < BATCH_SIZE; i++) { const gchar *output_element = output_buffer + i * (strlen(payload) + 1); cr_assert_str_eq(output_element, "PAYLOAD"); } cr_assert_eq(messages_acked, BATCH_SIZE); log_proto_client_free(fw); } static void startup(void) { app_startup(); msg = create_empty_message(); transport = log_transport_mock_stream_new(NULL, 0); } static void teardown(void) { log_msg_unref(msg); app_shutdown(); } TestSuite(file_writer, .init = startup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_wildcard_file_reader.c000066400000000000000000000112121450431004300267250ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "apphook.h" #include "wildcard-file-reader.h" #include "logpipe.h" #include "iv.h" #include #include #define TEST_FILE_NAME "TEST_FILE" typedef struct _TestFileStateEvent { gboolean deleted_eof_called; gboolean finished_called; } TestFileStateEvent; static void _eof(FileReader *reader, gpointer user_data) { TestFileStateEvent *test = (TestFileStateEvent *) user_data; test->deleted_eof_called = TRUE; } TestFileStateEvent * test_deleted_file_state_event_new(void) { TestFileStateEvent *self = g_new0(TestFileStateEvent, 1); return self; } TestFileStateEvent *test_event; WildcardFileReader *reader; LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; /* MOCKS */ gboolean file_reader_init_method(LogPipe *s) { return TRUE; } gboolean file_reader_deinit_method(LogPipe *s) { return TRUE; } void file_reader_queue_method(LogPipe *s, LogMessage *msg, const LogPathOptions *po) { return; } void file_reader_notify_method(LogPipe *s, gint notify_code, gpointer user_data) { return; } #if SYSLOG_NG_USE_CONST_IVYKIS_MOCK int iv_task_registered(const struct iv_task *_t) #else int iv_task_registered(struct iv_task *_t) #endif { return 0; } void iv_task_register(struct iv_task *_t) { _t->handler(_t->cookie); } void file_reader_init_instance(FileReader *self, const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg) { log_pipe_init_instance(&self->super, cfg); return; } static void _init(void) { app_startup(); test_event = test_deleted_file_state_event_new(); reader = (WildcardFileReader *)wildcard_file_reader_new(TEST_FILE_NAME, NULL, NULL, NULL, NULL); wildcard_file_reader_on_deleted_file_eof(reader, _eof, test_event); cr_assert_eq(log_pipe_init(&reader->super.super), TRUE); } static void _teardown(void) { log_pipe_deinit(&reader->super.super); log_pipe_unref(&reader->super.super); free(test_event); app_shutdown(); } TestSuite(test_wildcard_file_reader, .init = _init, .fini = _teardown); Test(test_wildcard_file_reader, constructor) { cr_assert_eq(reader->file_state.eof, FALSE); cr_assert_eq(reader->file_state.deleted, FALSE); } Test(test_wildcard_file_reader, msg_read) { reader->file_state.eof = TRUE; log_pipe_queue(&reader->super.super, NULL, &path_options); cr_assert_eq(reader->file_state.eof, FALSE); } Test(test_wildcard_file_reader, notif_deleted) { log_pipe_queue(&reader->super.super, NULL, &path_options); log_pipe_notify(&reader->super.super, NC_FILE_DELETED, NULL); cr_assert_eq(reader->file_state.deleted, TRUE); } Test(test_wildcard_file_reader, notif_eof) { log_pipe_queue(&reader->super.super, NULL, &path_options); log_pipe_notify(&reader->super.super, NC_FILE_EOF, NULL); cr_assert_eq(reader->file_state.eof, TRUE); } Test(test_wildcard_file_reader, status_change_deleted_not_eof) { log_pipe_queue(&reader->super.super, NULL, &path_options); log_pipe_notify(&reader->super.super, NC_FILE_DELETED, NULL); cr_assert_eq(test_event->deleted_eof_called, FALSE); } Test(test_wildcard_file_reader, status_change_deleted_eof) { log_pipe_queue(&reader->super.super, NULL, &path_options); log_pipe_notify(&reader->super.super, NC_FILE_DELETED, NULL); log_pipe_notify(&reader->super.super, NC_FILE_EOF, NULL); cr_assert_eq(test_event->deleted_eof_called, TRUE); } Test(test_wildcard_file_reader, status_finished_then_delete) { log_pipe_queue(&reader->super.super, NULL, &path_options); log_pipe_notify(&reader->super.super, NC_FILE_EOF, NULL); cr_assert_eq(test_event->deleted_eof_called, FALSE); log_pipe_notify(&reader->super.super, NC_FILE_DELETED, NULL); cr_assert_eq(test_event->deleted_eof_called, TRUE); } syslog-ng-syslog-ng-4.4.0/modules/affile/tests/test_wildcard_source.c000066400000000000000000000204741450431004300257760ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/config_parse_lib.h" #include "libtest/grab-logging.h" #include "cfg.h" #include "apphook.h" #include "cfg-grammar.h" #include "plugin.h" #include "wildcard-source.h" static void _init(void) { app_startup(); configuration = cfg_new_snippet(); cr_assert(cfg_load_module(configuration, "affile")); } static void _deinit(void) { cfg_deinit(configuration); cfg_free(configuration); } static gboolean _parse_config(const gchar *config) { gchar *raw_config = g_strdup_printf("source s_test { wildcard-file(%s); }; log { source(s_test); };", config); gboolean result = parse_config(raw_config, LL_CONTEXT_ROOT, NULL, NULL); g_free(raw_config); return result; } static WildcardSourceDriver * _create_wildcard_filesource(const gchar *wildcard_config) { cr_assert(_parse_config(wildcard_config), "Parsing the given configuration failed"); cr_assert(cfg_init(configuration), "Config initialization failed"); LogExprNode *expr_node = cfg_tree_get_object(&configuration->tree, ENC_SOURCE, "s_test"); cr_assert(expr_node != NULL); WildcardSourceDriver *driver = (WildcardSourceDriver *)expr_node->children->children->object; cr_assert(driver != NULL); return driver; } TestSuite(wildcard_source, .init = _init, .fini = _deinit); Test(wildcard_source, initial_test) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/test_non_existent_dir)" "filename-pattern(*.log)" "recursive(yes)" "max-files(100)" "monitor-method(poll)"); cr_assert_str_eq(driver->base_dir, "/test_non_existent_dir"); cr_assert_str_eq(driver->filename_pattern, "*.log"); cr_assert_eq(driver->max_files, 100); cr_assert_eq(driver->recursive, TRUE); cr_assert_eq(driver->monitor_method, MM_POLL); } Test(wildcard_source, test_option_inheritance_multiline) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/test_non_existent_dir)" "filename-pattern(*.log)" "recursive(yes)" "max-files(100)" "follow-freq(10)" "follow-freq(10.0)" "multi-line-mode(regexp)" "multi-line-prefix('\\d+')" "multi-line-garbage(garbage)"); cr_assert_eq(driver->file_reader_options.follow_freq, 10000); cr_assert_eq(file_reader_options_get_log_proto_options(&driver->file_reader_options)->multi_line_options.mode, MLM_REGEXP_PREFIX_GARBAGE); cr_assert(file_reader_options_get_log_proto_options(&driver->file_reader_options)->multi_line_options.regexp.prefix != NULL); cr_assert(file_reader_options_get_log_proto_options(&driver->file_reader_options)->multi_line_options.regexp.garbage != NULL); } Test(wildcard_source, test_option_inheritance_padded) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/test_non_existent_dir)" "filename-pattern(*.log)" "recursive(yes)" "max-files(100)" "pad-size(5)"); cr_assert_eq(file_reader_options_get_log_proto_options(&driver->file_reader_options)->pad_size, 5); } Test(wildcard_source, test_option_duplication) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/tmp)" "filename-pattern(*.txt)" "base-dir(/test_non_existent_dir)" "filename-pattern(*.log)"); cr_assert_str_eq(driver->base_dir, "/test_non_existent_dir"); cr_assert_str_eq(driver->filename_pattern, "*.log"); } Test(wildcard_source, test_filename_pattern_required_options) { start_grabbing_messages(); cr_assert(_parse_config("base-dir(/tmp)")); cr_assert(!cfg_init(configuration), "Config initialization should be failed"); stop_grabbing_messages(); assert_grabbed_log_contains("filename-pattern option is required"); reset_grabbed_messages(); } Test(wildcard_source, test_base_dir_required_options) { start_grabbing_messages(); cr_assert(_parse_config("filename-pattern(/tmp)")); cr_assert(!cfg_init(configuration), "Config initialization should be failed"); stop_grabbing_messages(); assert_grabbed_log_contains("base-dir option is required"); reset_grabbed_messages(); } Test(wildcard_source, test_invalid_monitor_method) { start_grabbing_messages(); cr_assert(!_parse_config("monitor-method(\"something else\"")); stop_grabbing_messages(); assert_grabbed_log_contains("Invalid monitor-method"); reset_grabbed_messages(); } Test(wildcard_source, test_minimum_window_size) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/test_non_existent_dir)" "filename-pattern(*.log)" "recursive(yes)" "max_files(100)" "log_iw_size(1000)"); cr_assert_eq(driver->file_reader_options.reader_options.super.init_window_size, 100); } Test(wildcard_source, test_window_size) { WildcardSourceDriver *driver = _create_wildcard_filesource("base-dir(/test_non_existent_dir)" "filename-pattern(*.log)" "recursive(yes)" "max_files(10)" "log_iw_size(10000)"); cr_assert_eq(driver->file_reader_options.reader_options.super.init_window_size, 1000); } struct LegacyWildcardTestParams { const gchar *path; const gchar *expected_base_dir; const gchar *expected_filename_pattern; }; ParameterizedTestParameters(wildcard_source, test_legacy_wildcard) { static struct LegacyWildcardTestParams params[] = { { "/a/b/c/d*", "/a/b/c", "d*" }, { "/a/b/c/d?", "/a/b/c", "d?" }, { "/*", "/", "*" }, { "*", ".", "*" }, { "/tmp/*", "/tmp", "*" }, { "tmp/?", "tmp", "?" }, { "tmp*", ".", "tmp*" }, { "/tmp*", "/", "tmp*" }, { "tmp/a*", "tmp", "a*" }, }; return cr_make_param_array(struct LegacyWildcardTestParams, params, G_N_ELEMENTS(params)); } ParameterizedTest(struct LegacyWildcardTestParams *params, wildcard_source, test_legacy_wildcard) { WildcardSourceDriver *driver = (WildcardSourceDriver *) wildcard_sd_legacy_new(params->path, configuration); cr_assert_str_eq(driver->base_dir, params->expected_base_dir); cr_assert_str_eq(driver->filename_pattern, params->expected_filename_pattern); log_pipe_unref(&driver->super.super.super); } syslog-ng-syslog-ng-4.4.0/modules/affile/transport-prockmsg.c000066400000000000000000000044131450431004300242760ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-prockmsg.h" #include "messages.h" #include "alarms.h" #include #include typedef struct _LogTransportDevice LogTransportDevice; struct _LogTransportDevice { LogTransport super; gint timeout; }; static gssize log_transport_prockmsg_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { LogTransportDevice *self = (LogTransportDevice *) s; gint rc; do { if (self->timeout) alarm_set(self->timeout); rc = read(self->super.fd, buf, buflen); if (self->timeout > 0 && rc == -1 && errno == EINTR && alarm_has_fired()) { msg_notice("Nonblocking read has blocked, returning with an error", evt_tag_int("fd", self->super.fd), evt_tag_int("timeout", self->timeout)); alarm_cancel(); break; } if (self->timeout) alarm_cancel(); } while (rc == -1 && errno == EINTR); return rc; } LogTransport * log_transport_prockmsg_new(gint fd, gint timeout) { LogTransportDevice *self = g_new0(LogTransportDevice, 1); log_transport_init_instance(&self->super, fd); self->timeout = timeout; self->super.read = log_transport_prockmsg_read_method; self->super.write = NULL; self->super.free_fn = log_transport_free_method; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/affile/transport-prockmsg.h000066400000000000000000000021631450431004300243030ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFFILE_PROCKMSG_H_INCLUDED #define AFFILE_PROCKMSG_H_INCLUDED 1 #include "transport/logtransport.h" LogTransport *log_transport_prockmsg_new(gint fd, gint timeout); #endif syslog-ng-syslog-ng-4.4.0/modules/affile/wildcard-file-reader.c000066400000000000000000000104551450431004300243700ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "wildcard-file-reader.h" #include "mainloop.h" static gboolean _init(LogPipe *s) { WildcardFileReader *self = (WildcardFileReader *)s; self->file_state.deleted = FALSE; self->file_state.eof = FALSE; return file_reader_init_method(s); } static gboolean _deinit(LogPipe *s) { WildcardFileReader *self = (WildcardFileReader *)s; if (iv_task_registered(&self->file_state_event_handler)) { iv_task_unregister(&self->file_state_event_handler); } return file_reader_deinit_method(s); } static void _queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { WildcardFileReader *self = (WildcardFileReader *)s; self->file_state.eof = FALSE; file_reader_queue_method(s, msg, path_options); } static void _deleted_file_eof(FileStateEvent *self, FileReader *reader) { if (self && self->deleted_file_eof) { self->deleted_file_eof(reader, self->deleted_file_eof_user_data); } } static void _schedule_state_change_handling(WildcardFileReader *self) { main_loop_assert_main_thread(); if (!iv_task_registered(&self->file_state_event_handler)) { iv_task_register(&self->file_state_event_handler); } } static void _set_eof(WildcardFileReader *self) { self->file_state.eof = TRUE; if (self->file_state.deleted) { _schedule_state_change_handling(self); } } static void _set_deleted(WildcardFileReader *self) { /* File can be deleted only once, * so there is no need for checking the state * before we set it */ self->file_state.deleted = TRUE; _schedule_state_change_handling(self); } static void _notify(LogPipe *s, gint notify_code, gpointer user_data) { WildcardFileReader *self = (WildcardFileReader *)s; switch(notify_code) { case NC_FILE_DELETED: _set_deleted(self); break; case NC_FILE_EOF: _set_eof(self); break; default: file_reader_notify_method(s, notify_code, user_data); break; } } static void _handle_file_state_event(gpointer s) { WildcardFileReader *self = (WildcardFileReader *)s; msg_debug("File status changed", evt_tag_int("EOF", self->file_state.eof), evt_tag_int("DELETED", self->file_state.deleted), evt_tag_str("Filename", self->super.filename->str)); if (self->file_state.deleted && self->file_state.eof) _deleted_file_eof(&self->file_state_event, &self->super); } void wildcard_file_reader_on_deleted_file_eof(WildcardFileReader *self, FileStateEventCallback cb, gpointer user_data) { self->file_state_event.deleted_file_eof = cb; self->file_state_event.deleted_file_eof_user_data = user_data; } gboolean wildcard_file_reader_is_deleted(WildcardFileReader *self) { return self->file_state.deleted; } WildcardFileReader * wildcard_file_reader_new(const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg) { WildcardFileReader *self = g_new0(WildcardFileReader, 1); file_reader_init_instance(&self->super, filename, options, opener, owner, cfg); self->super.super.init = _init; self->super.super.queue = _queue; self->super.super.notify = _notify; self->super.super.deinit = _deinit; IV_TASK_INIT(&self->file_state_event_handler); self->file_state_event_handler.cookie = self; self->file_state_event_handler.handler = _handle_file_state_event; return self; } syslog-ng-syslog-ng-4.4.0/modules/affile/wildcard-file-reader.h000066400000000000000000000037251450431004300243770ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_WILDCARD_FILE_READER_H_ #define MODULES_AFFILE_WILDCARD_FILE_READER_H_ #include "file-reader.h" #include typedef struct _WildcardFileReader WildcardFileReader; typedef void (*FileStateEventCallback)(FileReader *file_reader, gpointer user_data); typedef struct _FileStateEvent { FileStateEventCallback deleted_file_eof; gpointer deleted_file_eof_user_data; } FileStateEvent; typedef struct _FileState { gboolean deleted; gboolean eof; } FileState; struct _WildcardFileReader { FileReader super; FileState file_state; FileStateEvent file_state_event; struct iv_task file_state_event_handler; }; WildcardFileReader * wildcard_file_reader_new(const gchar *filename, FileReaderOptions *options, FileOpener *opener, LogSrcDriver *owner, GlobalConfig *cfg); void wildcard_file_reader_on_deleted_file_eof(WildcardFileReader *self, FileStateEventCallback cb, gpointer user_data); gboolean wildcard_file_reader_is_deleted(WildcardFileReader *self); #endif /* MODULES_AFFILE_WILDCARD_FILE_READER_H_ */ syslog-ng-syslog-ng-4.4.0/modules/affile/wildcard-source.c000066400000000000000000000360201450431004300235050ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "wildcard-source.h" #include "directory-monitor-factory.h" #include "messages.h" #include "file-specializations.h" #include "mainloop.h" #include #include #define DEFAULT_SD_OPEN_FLAGS (O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE) static DirectoryMonitor *_add_directory_monitor(WildcardSourceDriver *self, const gchar *directory); static void _create_file_reader(WildcardSourceDriver *self, const gchar *full_path); static gboolean _check_required_options(WildcardSourceDriver *self) { if (!self->base_dir) { msg_error("Error: base-dir option is required", evt_tag_str("driver", self->super.super.id)); return FALSE; } if (!self->filename_pattern) { msg_error("Error: filename-pattern option is required", evt_tag_str("driver", self->super.super.id)); return FALSE; } return TRUE; } static void _remove_file_reader(FileReader *reader, gpointer user_data) { WildcardSourceDriver *self = (WildcardSourceDriver *) user_data; msg_debug("Stop following file, because of deleted and eof", evt_tag_str("filename", reader->filename->str)); file_reader_stop_follow_file(reader); log_pipe_deinit(&reader->super); file_reader_remove_persist_state(reader); log_pipe_ref(&reader->super); if (g_hash_table_remove(self->file_readers, reader->filename->str)) { msg_debug("File is removed from the file list", evt_tag_str("Filename", reader->filename->str)); } else { msg_error("Can't remove the file reader", evt_tag_str("Filename", reader->filename->str)); } log_pipe_unref(&reader->super); for (GList *pending_iterator = pending_file_list_begin(self->waiting_list); pending_iterator != pending_file_list_end(self->waiting_list); pending_iterator = pending_file_list_next(pending_iterator)) { gchar *full_path = pending_iterator->data; if (g_hash_table_lookup_extended(self->file_readers, full_path, NULL, NULL)) { continue; } pending_file_list_steal(self->waiting_list, pending_iterator); _create_file_reader(self, full_path); g_list_free_1(pending_iterator); g_free(full_path); break; } } void _create_file_reader(WildcardSourceDriver *self, const gchar *full_path) { WildcardFileReader *reader = NULL; GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (g_hash_table_size(self->file_readers) >= self->max_files) { msg_warning("Number of allowed monitorod file is reached, rejecting read file", evt_tag_str("source", self->super.super.group), evt_tag_str("filename", full_path), evt_tag_int("max_files", self->max_files)); pending_file_list_add(self->waiting_list, full_path); return; } reader = wildcard_file_reader_new(full_path, &self->file_reader_options, self->file_opener, &self->super, cfg); log_pipe_set_options(&reader->super.super, &self->super.super.super.options); wildcard_file_reader_on_deleted_file_eof(reader, _remove_file_reader, self); log_pipe_append(&reader->super.super, &self->super.super.super); if (!log_pipe_init(&reader->super.super)) { msg_warning("File reader initialization failed", evt_tag_str("filename", full_path), evt_tag_str("source_driver", self->super.super.group)); log_pipe_unref(&reader->super.super); } else { g_hash_table_insert(self->file_readers, g_strdup(full_path), reader); } } static void _handle_file_created(WildcardSourceDriver *self, const DirectoryMonitorEvent *event) { if (g_pattern_match_string(self->compiled_pattern, event->name)) { WildcardFileReader *reader = g_hash_table_lookup(self->file_readers, event->full_path); if (!reader) { _create_file_reader(self, event->full_path); msg_debug("Wildcard: file created", evt_tag_str("filename", event->full_path)); } else { if (wildcard_file_reader_is_deleted(reader)) { msg_info("File is deleted, new file create with same name. " "While old file is reading, skip the new one", evt_tag_str("filename", event->full_path)); pending_file_list_add(self->waiting_list, event->full_path); } else if (!log_pipe_init(&reader->super.super)) { msg_error("Can not re-initialize reader for file", evt_tag_str("filename", event->full_path)); } else { msg_debug("Wildcard: file reader reinitialized", evt_tag_str("filename", event->full_path)); } } } } void _handle_directory_created(WildcardSourceDriver *self, const DirectoryMonitorEvent *event) { if (self->recursive) { msg_debug("Directory created", evt_tag_str("name", event->full_path)); DirectoryMonitor *monitor = g_hash_table_lookup(self->directory_monitors, event->full_path); if (!monitor) { _add_directory_monitor(self, event->full_path); } } } void _handle_file_deleted(WildcardSourceDriver *self, const DirectoryMonitorEvent *event) { FileReader *reader = g_hash_table_lookup(self->file_readers, event->full_path); if (reader) { msg_debug("Monitored file is deleted", evt_tag_str("filename", event->full_path)); log_pipe_notify(&reader->super, NC_FILE_DELETED, NULL); } if (pending_file_list_remove(self->waiting_list, event->full_path)) { msg_warning("Waiting file was deleted, it wasn't read at all", evt_tag_str("filename", event->full_path)); } } void _handler_directory_deleted(WildcardSourceDriver *self, const DirectoryMonitorEvent *event) { gchar *key; DirectoryMonitor *monitor; gboolean found = g_hash_table_lookup_extended(self->directory_monitors, event->full_path, (gpointer *)&key, (gpointer *)&monitor); if (found) { msg_debug("Monitored directory is deleted", evt_tag_str("dir", event->full_path)); g_hash_table_steal(self->directory_monitors, event->full_path); g_free(key); directory_monitor_schedule_destroy(monitor); } } static void _on_directory_monitor_changed(const DirectoryMonitorEvent *event, gpointer user_data) { main_loop_assert_main_thread(); WildcardSourceDriver *self = (WildcardSourceDriver *)user_data; if ((event->event_type == FILE_CREATED)) { _handle_file_created(self, event); } else if (event->event_type == DIRECTORY_CREATED) { _handle_directory_created(self, event); } else if (event->event_type == FILE_DELETED) { _handle_file_deleted(self, event); } else if (event->event_type == DIRECTORY_DELETED) { _handler_directory_deleted(self, event); } } static void _ensure_minimum_window_size(WildcardSourceDriver *self, GlobalConfig *cfg) { if (self->file_reader_options.reader_options.super.init_window_size < cfg->min_iw_size_per_reader) { msg_warning("log_iw_size configuration value was divided by the value of max-files()." " The result was too small, clamping to minimum entries." " Ensure you have a proper log_fifo_size setting to avoid message loss.", evt_tag_int("orig_log_iw_size", self->file_reader_options.reader_options.super.init_window_size), evt_tag_int("new_log_iw_size", cfg->min_iw_size_per_reader), evt_tag_int("min_iw_size_per_reader", cfg->min_iw_size_per_reader), evt_tag_int("min_log_fifo_size", cfg->min_iw_size_per_reader * self->max_files)); self->file_reader_options.reader_options.super.init_window_size = cfg->min_iw_size_per_reader; } } static gboolean _init_reader_options(WildcardSourceDriver *self, GlobalConfig *cfg) { if (!self->window_size_initialized) { self->file_reader_options.reader_options.super.init_window_size /= self->max_files; _ensure_minimum_window_size(self, cfg); self->window_size_initialized = TRUE; } return file_reader_options_init(&self->file_reader_options, cfg, self->super.super.group); } static void _init_opener_options(WildcardSourceDriver *self, GlobalConfig *cfg) { file_opener_options_init(&self->file_opener_options, cfg); file_opener_set_options(self->file_opener, &self->file_opener_options); } static gboolean _init_filename_pattern(WildcardSourceDriver *self) { self->compiled_pattern = g_pattern_spec_new(self->filename_pattern); if (!self->compiled_pattern) { msg_error("Invalid filename-pattern", evt_tag_str("filename-pattern", self->filename_pattern)); return FALSE; } return TRUE; } static DirectoryMonitor * _add_directory_monitor(WildcardSourceDriver *self, const gchar *directory) { DirectoryMonitorOptions options = { .dir = directory, .follow_freq = self->file_reader_options.follow_freq, .method = self->monitor_method }; DirectoryMonitor *monitor = create_directory_monitor(&options); if (!monitor) { msg_error("Wildcard source: could not create directory monitoring object! Possible message loss", evt_tag_str("dir", directory), log_pipe_location_tag(&self->super.super.super)); return NULL; } directory_monitor_set_callback(monitor, _on_directory_monitor_changed, self); directory_monitor_start(monitor); g_hash_table_insert(self->directory_monitors, g_strdup(directory), monitor); return monitor; } static gboolean _init(LogPipe *s) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_src_driver_init_method(s)) { return FALSE; } if (!_check_required_options(self)) { return FALSE; } if (!_init_filename_pattern(self)) { return FALSE; } if (!_init_reader_options(self, cfg)) return FALSE; _init_opener_options(self, cfg); if (!_add_directory_monitor(self, self->base_dir)) return FALSE; return TRUE; } static void _deinit_reader(gpointer key, gpointer value, gpointer user_data) { FileReader *reader = (FileReader *) value; log_pipe_deinit(&reader->super); } static gboolean _deinit(LogPipe *s) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; g_pattern_spec_free(self->compiled_pattern); g_hash_table_foreach(self->file_readers, _deinit_reader, NULL); return TRUE; } void wildcard_sd_set_base_dir(LogDriver *s, const gchar *base_dir) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; g_free(self->base_dir); self->base_dir = g_strdup(base_dir); } void wildcard_sd_set_filename_pattern(LogDriver *s, const gchar *filename_pattern) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; g_free(self->filename_pattern); self->filename_pattern = g_strdup(filename_pattern); } void wildcard_sd_set_recursive(LogDriver *s, gboolean recursive) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; self->recursive = recursive; } gboolean wildcard_sd_set_monitor_method(LogDriver *s, const gchar *method) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; MonitorMethod new_method = directory_monitor_factory_get_monitor_method(method); if (new_method == MM_UNKNOWN) { msg_error("Invalid monitor-method", evt_tag_str("monitor-method", method)); return FALSE; } self->monitor_method = new_method; return TRUE; } void wildcard_sd_set_max_files(LogDriver *s, guint32 max_files) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; self->max_files = max_files; } static void _free(LogPipe *s) { WildcardSourceDriver *self = (WildcardSourceDriver *)s; file_opener_free(self->file_opener); g_free(self->base_dir); g_free(self->filename_pattern); g_hash_table_unref(self->file_readers); g_hash_table_unref(self->directory_monitors); file_reader_options_deinit(&self->file_reader_options); file_opener_options_deinit(&self->file_opener_options); pending_file_list_free(self->waiting_list); log_src_driver_free(s); } LogDriver * wildcard_sd_new(GlobalConfig *cfg) { WildcardSourceDriver *self = g_new0(WildcardSourceDriver, 1); log_src_driver_init_instance(&self->super, cfg); self->super.super.super.free_fn = _free; self->super.super.super.init = _init; self->super.super.super.deinit = _deinit; self->file_readers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)log_pipe_unref); self->directory_monitors = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)directory_monitor_stop_and_destroy); self->monitor_method = MM_AUTO; file_reader_options_defaults(&self->file_reader_options); file_opener_options_defaults_dont_change_permissions(&self->file_opener_options); self->file_reader_options.follow_freq = 1000; self->file_reader_options.reader_options.super.init_window_size = cfg->min_iw_size_per_reader * DEFAULT_MAX_FILES; self->file_reader_options.reader_options.super.stats_source = stats_register_type("file"); self->file_reader_options.restore_state = TRUE; self->max_files = DEFAULT_MAX_FILES; self->file_opener = file_opener_for_regular_source_files_new(); self->waiting_list = pending_file_list_new(); return &self->super.super; } gboolean affile_is_legacy_wildcard_source(const gchar *filename) { return strchr(filename, '*') != NULL || strchr(filename, '?') != NULL; } LogDriver * wildcard_sd_legacy_new(const gchar *filename, GlobalConfig *cfg) { msg_warning_once("WARNING: Using wildcard characters in the file() source is deprecated, use wildcard-file() instead. " "The legacy wildcard file() source can only monitor up to " G_STRINGIFY(DEFAULT_MAX_FILES) " files, " "use wildcard-file(max-files()) to change this limit"); WildcardSourceDriver *self = (WildcardSourceDriver *) wildcard_sd_new(cfg); self->base_dir = g_path_get_dirname(filename); self->filename_pattern = g_path_get_basename(filename); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/affile/wildcard-source.h000066400000000000000000000043441450431004300235160ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef MODULES_AFFILE_WILDCARD_SOURCE_H_ #define MODULES_AFFILE_WILDCARD_SOURCE_H_ #include "syslog-ng.h" #include "driver.h" #include "wildcard-file-reader.h" #include "file-list.h" #include "directory-monitor.h" #include "directory-monitor-factory.h" #define DEFAULT_MAX_FILES 100 typedef struct _WildcardSourceDriver { LogSrcDriver super; gchar *base_dir; gchar *filename_pattern; MonitorMethod monitor_method; guint32 max_files; gboolean window_size_initialized; gboolean recursive; FileReaderOptions file_reader_options; FileOpenerOptions file_opener_options; GPatternSpec *compiled_pattern; GHashTable *file_readers; GHashTable *directory_monitors; FileOpener *file_opener; PendingFileList *waiting_list; } WildcardSourceDriver; LogDriver *wildcard_sd_new(GlobalConfig *cfg); void wildcard_sd_set_base_dir(LogDriver *s, const gchar *base_dir); void wildcard_sd_set_filename_pattern(LogDriver *s, const gchar *filename_pattern); void wildcard_sd_set_recursive(LogDriver *s, gboolean recursive); gboolean wildcard_sd_set_monitor_method(LogDriver *s, const gchar *method); void wildcard_sd_set_max_files(LogDriver *s, guint32 max_files); gboolean affile_is_legacy_wildcard_source(const gchar *filename); LogDriver *wildcard_sd_legacy_new(const gchar *filename, GlobalConfig *cfg); #endif /* MODULES_AFFILE_WILDCARD_SOURCE_H_ */ syslog-ng-syslog-ng-4.4.0/modules/afmongodb/000077500000000000000000000000001450431004300207575ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afmongodb/CMakeLists.txt000066400000000000000000000020171450431004300235170ustar00rootroot00000000000000if (ENABLE_MONGODB STREQUAL OFF) return() endif() find_package(libmongoc-1.0) find_package(libbson-1.0) module_switch(ENABLE_MONGODB "Enable mongodb destination driver" libmongoc-1.0_FOUND) if (ENABLE_MONGODB) set(CMAKE_REQUIRED_INCLUDES ${MONGOC_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${MONGOC_LIBRARY}) set(CMAKE_REQUIRED_LIBRARIES ${BSON_LIBRARY}) check_symbol_exists(mongoc_uri_set_option_as_int32 "mongoc.h" SYSLOG_NG_HAVE_DECL_MONGOC_URI_SET_OPTION_AS_INT32) check_symbol_exists(MONGOC_URI_SERVERSELECTIONTIMEOUTMS "mongoc.h" SYSLOG_NG_HAVE_DECL_MONGOC_URI_SERVERSELECTIONTIMEOUTMS) set(AFMONGODB_SOURCES "afmongodb.h" "afmongodb.c" "afmongodb-worker.h" "afmongodb-worker.c" "afmongodb-parser.h" "afmongodb-parser.c" "afmongodb-private.h" ) add_module( TARGET afmongodb GRAMMAR afmongodb-grammar INCLUDES ${MONGOC_INCLUDE_DIRS} DEPENDS ${MONGOC_LIBRARY} DEPENDS ${BSON_LIBRARY} SOURCES ${AFMONGODB_SOURCES} ) add_test_subdirectory(tests) endif() syslog-ng-syslog-ng-4.4.0/modules/afmongodb/Makefile.am000066400000000000000000000025521450431004300230170ustar00rootroot00000000000000 if ENABLE_MONGODB module_LTLIBRARIES += modules/afmongodb/libafmongodb.la modules_afmongodb_libafmongodb_la_CFLAGS = \ $(AM_CFLAGS) \ $(LIBMONGO_CFLAGS) \ -I$(top_srcdir)/modules/afmongodb \ -I$(top_builddir)/modules/afmongodb modules_afmongodb_libafmongodb_la_SOURCES = \ modules/afmongodb/afmongodb-grammar.y \ modules/afmongodb/afmongodb.c \ modules/afmongodb/afmongodb.h \ modules/afmongodb/afmongodb-worker.c \ modules/afmongodb/afmongodb-worker.h \ modules/afmongodb/afmongodb-private.h \ modules/afmongodb/afmongodb-parser.c \ modules/afmongodb/afmongodb-parser.h \ ${DUMMY_C} modules_afmongodb_libafmongodb_la_LIBADD = \ $(MODULE_DEPS_LIBS) $(LIBMONGO_LIBS) modules_afmongodb_libafmongodb_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afmongodb_libafmongodb_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) $(lmc_EXTRA_DEPS) modules/afmongodb modules/afmongodb/ mod-afmongodb mod-mongodb: \ modules/afmongodb/libafmongodb.la include modules/afmongodb/tests/Makefile.am else modules/afmongodb modules/afmongodb/ mod-afmongodb mod-mongodb: endif BUILT_SOURCES += \ modules/afmongodb/afmongodb-grammar.y \ modules/afmongodb/afmongodb-grammar.c \ modules/afmongodb/afmongodb-grammar.h EXTRA_DIST += \ modules/afmongodb/afmongodb-grammar.ym \ modules/afmongodb/CMakeLists.txt .PHONY: modules/afmongodb/ mod-afmongodb mod-mongodb syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-grammar.ym000066400000000000000000000061221450431004300247070ustar00rootroot00000000000000/* * Copyright (c) 2010-2015 Balabit * Copyright (c) 2010-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "afmongodb-parser.h" } %code { #include "cfg-grammar-internal.h" #include "plugin.h" #include "value-pairs/value-pairs.h" } %define api.prefix {afmongodb_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_MONGODB %token KW_URI %token KW_COLLECTION %token KW_BULK %token KW_BULK_UNORDERED %token KW_BULK_BYPASS_VALIDATION %token KW_WRITE_CONCERN %token KW_W_UNACKNOWLEDGED %token KW_W_DEFAULT %token KW_W_MAJORITY %type write_concern_strict %type write_concern %% start : LL_CONTEXT_DESTINATION KW_MONGODB { last_driver = *instance = afmongodb_dd_new(configuration); } '(' _inner_dest_context_push afmongodb_options _inner_dest_context_pop ')' { YYACCEPT; } ; write_concern_strict : KW_W_UNACKNOWLEDGED { $$ = 0; } /* MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED */ | KW_W_DEFAULT { $$ = -2; } /* MONGOC_WRITE_CONCERN_W_DEFAULT */ | KW_W_MAJORITY { $$ = -3; } /* MONGOC_WRITE_CONCERN_W_MAJORITY */ ; write_concern : write_concern_strict | positive_integer { $$ = $1; } ; afmongodb_options : afmongodb_option afmongodb_options | ; afmongodb_option : KW_URI '(' string ')' { afmongodb_dd_set_uri(last_driver, $3); free($3); } | KW_BULK '(' yesno ')' { afmongodb_dd_set_bulk(last_driver, $3); } | KW_BULK_UNORDERED '(' yesno ')' { afmongodb_dd_set_bulk_unordered(last_driver, $3); } | KW_BULK_BYPASS_VALIDATION '(' yesno ')' { afmongodb_dd_set_bulk_bypass_validation(last_driver, $3); } | KW_WRITE_CONCERN '(' write_concern ')' { afmongodb_dd_set_write_concern(last_driver, $3); } | KW_COLLECTION '(' template_content ')' { afmongodb_dd_set_collection(last_driver, $3); } | value_pair_option { afmongodb_dd_set_value_pairs(last_driver, $1); } | threaded_dest_driver_general_option | threaded_dest_driver_workers_option | threaded_dest_driver_batch_option | { last_template_options = afmongodb_dd_get_template_options(last_driver); } template_option ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-parser.c000066400000000000000000000036211450431004300243530ustar00rootroot00000000000000/* * Copyright (c) 2010-2015 Balabit * Copyright (c) 2010-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afmongodb.h" #include "cfg-parser.h" #include "afmongodb-grammar.h" extern int afmongodb_debug; int afmongodb_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afmongodb_keywords[] = { { "mongodb", KW_MONGODB }, { "uri", KW_URI }, { "collection", KW_COLLECTION }, { "bulk", KW_BULK }, { "bulk_unordered", KW_BULK_UNORDERED }, { "bulk_bypass_validation", KW_BULK_BYPASS_VALIDATION }, { "write_concern", KW_WRITE_CONCERN }, { "unacked", KW_W_UNACKNOWLEDGED }, { "acked", KW_W_DEFAULT }, { "majority", KW_W_MAJORITY }, { NULL } }; CfgParser afmongodb_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afmongodb_debug, #endif .name = "afmongodb", .keywords = afmongodb_keywords, .parse = (int (*)(CfgLexer *lexer, gpointer *instance, gpointer)) afmongodb_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afmongodb_, AFMONGODB_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-parser.h000066400000000000000000000023201450431004300243530ustar00rootroot00000000000000/* * Copyright (c) 2010-2012 Balabit * Copyright (c) 2010-2012 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFMONGODB_PARSER_H_INCLUDED #define AFMONGODB_PARSER_H_INCLUDED #include "syslog-ng.h" #include "cfg-parser.h" #include "afmongodb.h" extern CfgParser afmongodb_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afmongodb_, AFMONGODB_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-private.h000066400000000000000000000030421450431004300245330ustar00rootroot00000000000000/* * Copyright (c) 2010-2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFMONGODB_PRIVATE_H_ #define AFMONGODB_PRIVATE_H_ #include "syslog-ng.h" #include "mongoc.h" #include "logthrdest/logthrdestdrv.h" #include "template/templates.h" #include "value-pairs/value-pairs.h" typedef struct _MongoDBDestDriver { LogThreadedDestDriver super; GString *uri_str; LogTemplate *collection_template; gboolean collection_is_literal_string; LogTemplateOptions template_options; gboolean use_bulk; gboolean bulk_unordered; gboolean bulk_bypass_validation; int32_t write_concern_level; ValuePairs *vp; const gchar *const_db; mongoc_uri_t *uri_obj; mongoc_client_pool_t *pool; } MongoDBDestDriver; #endif syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-worker.c000066400000000000000000000414741450431004300244000ustar00rootroot00000000000000/* * Copyright (c) 2010-2021 One Identity * Copyright (c) 2010-2014 Gergely Nagy * Copyright (c) 2021 László Várady * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afmongodb-worker.h" #include "afmongodb-private.h" #include "messages.h" #include "scratch-buffers.h" #include "value-pairs/evttag.h" #include "value-pairs/value-pairs.h" #include "scanner/list-scanner/list-scanner.h" static LogThreadedResult _do_bulk_flush(MongoDBDestWorker *self); static void _compose_bulk_op_options(MongoDBDestWorker *self) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; if (owner->use_bulk) { self->bson_opts = bson_new(); bson_t def_opts = BSON_INITIALIZER; *self->bson_opts = def_opts; if (!BSON_APPEND_BOOL(self->bson_opts, "ordered", false == owner->bulk_unordered)) msg_error("Error setting bulk option", evt_tag_str("option", "ordered"), evt_tag_str("driver", owner->super.super.super.id)); if (!mongoc_write_concern_append(self->write_concern, self->bson_opts)) msg_error("Error setting bulk option", evt_tag_str("option", "write_concern"), evt_tag_str("driver", owner->super.super.super.id)); } } static void _destroy_bulk_op_options(MongoDBDestWorker *self) { if (self->bson_opts) { bson_destroy(self->bson_opts); self->bson_opts = NULL; } } static void _compose_write_concern(MongoDBDestWorker *self) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; self->write_concern = mongoc_write_concern_new(); mongoc_write_concern_set_w(self->write_concern, owner->write_concern_level); } static void _destroy_write_concern(MongoDBDestWorker *self) { if (self->write_concern) { mongoc_write_concern_destroy(self->write_concern); self->write_concern = NULL; } } static void _worker_disconnect(LogThreadedDestWorker *s) { MongoDBDestWorker *self = (MongoDBDestWorker *)s; MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; if (self->bulk_op) { mongoc_bulk_operation_destroy(self->bulk_op); self->bulk_op = NULL; } if (self->coll_obj) { mongoc_collection_destroy(self->coll_obj); self->coll_obj = NULL; } if (self->client) { mongoc_client_pool_push(owner->pool, self->client); self->client = NULL; } } static const gchar * _format_collection_template(MongoDBDestWorker *self, LogMessage *msg) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; LogTemplateEvalOptions options = { &owner->template_options, LTZ_SEND, self->super.seq_num, NULL, LM_VT_STRING }; log_template_format(owner->collection_template, msg, &options, self->collection); return self->collection->str; } static gboolean _switch_collection(MongoDBDestWorker *self, const gchar *collection) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; if (!self->client) return FALSE; if (self->bulk_op && _do_bulk_flush(self) != LTR_SUCCESS) return FALSE; if (self->coll_obj) mongoc_collection_destroy(self->coll_obj); self->coll_obj = mongoc_client_get_collection(self->client, owner->const_db, collection); if (!self->coll_obj) { msg_error("Error getting specified MongoDB collection", evt_tag_str("collection", collection), evt_tag_str("driver", owner->super.super.super.id)); return FALSE; } msg_debug("Switching MongoDB collection", evt_tag_str("new_collection", collection)); return TRUE; } static gboolean _check_server_status(MongoDBDestWorker *self, const mongoc_read_prefs_t *read_prefs) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; bson_t reply; bson_error_t error; if (!self->client) return FALSE; bson_t *cmd = BCON_NEW("serverStatus", "1"); gboolean ok = mongoc_client_command_simple(self->client, owner->const_db ? : "", cmd, read_prefs, &reply, &error); bson_destroy(&reply); bson_destroy(cmd); if (!ok) { msg_error("Error connecting to MongoDB", evt_tag_str("driver", owner->super.super.super.id), evt_tag_str("reason", error.message)); return FALSE; } return TRUE; } static gboolean _worker_connect(LogThreadedDestWorker *s) { MongoDBDestWorker *self = (MongoDBDestWorker *)s; MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; if (!self->client) { self->client = mongoc_client_pool_pop(owner->pool); if (!self->client) { msg_error("Error creating MongoDB URI", evt_tag_str("driver", owner->super.super.super.id)); return FALSE; } } const mongoc_read_prefs_t *read_prefs = NULL; if (owner->collection_is_literal_string && !self->coll_obj) { const gchar *collection = log_template_get_literal_value(owner->collection_template, NULL); if (!_switch_collection(self, collection)) { mongoc_client_pool_push(owner->pool, self->client); self->client = NULL; return FALSE; } g_string_assign(self->collection, collection); read_prefs = mongoc_collection_get_read_prefs(self->coll_obj); } if (!_check_server_status(self, read_prefs)) { _worker_disconnect(s); return FALSE; } return TRUE; } /* * Worker thread */ static gboolean _vp_obj_start(const gchar *name, const gchar *prefix, gpointer *prefix_data, const gchar *prev, gpointer *prev_data, gpointer user_data) { bson_t *o; if (prefix_data) { o = bson_new(); *prefix_data = o; } return FALSE; } static gboolean _vp_obj_end(const gchar *name, const gchar *prefix, gpointer *prefix_data, const gchar *prev, gpointer *prev_data, gpointer user_data) { MongoDBDestWorker *self = (MongoDBDestWorker *) user_data; bson_t *root; if (prev_data) root = (bson_t *)*prev_data; else root = self->bson; if (prefix_data) { bson_t *d = (bson_t *)*prefix_data; bson_append_document(root, name, -1, d); bson_destroy(d); } return FALSE; } static gboolean _vp_process_value(const gchar *name, const gchar *prefix, LogMessageValueType type, const gchar *value, gsize value_len, gpointer *prefix_data, gpointer user_data) { bson_t *o; MongoDBDestWorker *self = (MongoDBDestWorker *) user_data; MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; gboolean fallback = owner->template_options.on_error & ON_ERROR_FALLBACK_TO_STRING; if (prefix_data) o = (bson_t *)*prefix_data; else o = self->bson; switch (type) { case LM_VT_BOOLEAN: { gboolean b; if (type_cast_to_boolean(value, &b, NULL)) bson_append_bool(o, name, -1, b); else { gboolean r = type_cast_drop_helper(owner->template_options.on_error, value, "boolean"); if (fallback) bson_append_utf8(o, name, -1, value, value_len); else return r; } break; } case LM_VT_INTEGER: { gint64 i; if (type_cast_to_int64(value, &i, NULL)) { if (G_MININT32 <= i && i <= G_MAXINT32) bson_append_int32(o, name, -1, i); else bson_append_int64(o, name, -1, i); } else { gboolean r = type_cast_drop_helper(owner->template_options.on_error, value, "integer"); if (fallback) bson_append_utf8(o, name, -1, value, value_len); else return r; } break; } case LM_VT_DOUBLE: { gdouble d; if (type_cast_to_double(value, &d, NULL)) bson_append_double(o, name, -1, d); else { gboolean r = type_cast_drop_helper(owner->template_options.on_error, value, "double"); if (fallback) bson_append_utf8(o, name, -1, value, value_len); else return r; } break; } case LM_VT_DATETIME: { gint64 msec; if (type_cast_to_datetime_msec(value, &msec, NULL)) bson_append_date_time(o, name, -1, msec); else { gboolean r = type_cast_drop_helper(owner->template_options.on_error, value, "datetime"); if (fallback) bson_append_utf8(o, name, -1, value, value_len); else return r; } break; } case LM_VT_STRING: bson_append_utf8(o, name, -1, value, value_len); break; case LM_VT_LIST: { bson_t array; ListScanner scanner; gint i = 0; bson_append_array_begin(o, name, -1, &array); list_scanner_init(&scanner); list_scanner_input_string(&scanner, value, value_len); while (list_scanner_scan_next(&scanner)) { gchar buf[32]; const gchar *index_string; bson_uint32_to_string(i, &index_string, buf, sizeof(buf)); bson_append_utf8(&array, index_string, -1, list_scanner_get_current_value(&scanner), -1); i++; } list_scanner_deinit(&scanner); bson_append_array_end(o, &array); break; } case LM_VT_JSON: { bson_t embedded_bson; if (bson_init_from_json(&embedded_bson, value, value_len, NULL)) { bson_append_document(o, name, -1, &embedded_bson); bson_destroy(&embedded_bson); } else { gboolean r = type_cast_drop_helper(owner->template_options.on_error, value, "json"); if (fallback) bson_append_utf8(o, name, -1, value, value_len); else return r; } break; } case LM_VT_NULL: { bson_append_null(o, name, -1); break; } case LM_VT_BYTES: case LM_VT_PROTOBUF: { bson_append_binary(o, name, -1, BSON_SUBTYPE_BINARY, (const uint8_t *) value, value_len); break; } default: return TRUE; } return FALSE; } static LogThreadedResult _do_bulk_flush(MongoDBDestWorker *self) { /* Take care, _worker_batch_flush -> _do_bulk_flush is called at thread shutdown as well at that time not neccessarily we have an inprogress bulk operation */ if (self->bulk_op) { bson_error_t error; bson_t reply; int result = mongoc_bulk_operation_execute(self->bulk_op, &reply, &error); bson_destroy (&reply); mongoc_bulk_operation_destroy(self->bulk_op); self->bulk_op = NULL; if (result == 0) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; msg_error("Error while bulk inserting into MongoDB", evt_tag_int("time_reopen", self->super.time_reopen), evt_tag_str("reason", error.message), evt_tag_str("driver", owner->super.super.super.id)); return LTR_ERROR; } } return LTR_SUCCESS; } static LogThreadedResult _worker_batch_flush(LogThreadedDestWorker *s, LogThreadedFlushMode expedite) { MongoDBDestWorker *self = (MongoDBDestWorker *) s; return _do_bulk_flush(self); } static LogThreadedResult _bulk_insert(MongoDBDestWorker *self) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; if (self->bulk_op == NULL) self->bulk_op = mongoc_collection_create_bulk_operation_with_opts(self->coll_obj, self->bson_opts); if (self->bulk_op == NULL) { msg_error("Failed to create MongoDB bulk operation", evt_tag_int("time_reopen", self->super.time_reopen), evt_tag_str("driver", owner->super.super.super.id)); return LTR_ERROR; } mongoc_bulk_operation_set_bypass_document_validation(self->bulk_op, owner->bulk_bypass_validation); mongoc_bulk_operation_insert(self->bulk_op, (const bson_t *)self->bson); return LTR_QUEUED; } static LogThreadedResult _single_insert(MongoDBDestWorker *self) { MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; bson_error_t error; bool success = mongoc_collection_insert(self->coll_obj, MONGOC_INSERT_NONE, (const bson_t *)self->bson, self->write_concern, &error); if (!success) { if (error.domain == MONGOC_ERROR_STREAM) { msg_error("Network error while inserting into MongoDB", evt_tag_int("time_reopen", self->super.time_reopen), evt_tag_str("reason", error.message), evt_tag_str("driver", owner->super.super.super.id)); return LTR_NOT_CONNECTED; } else { msg_error("Failed to insert into MongoDB", evt_tag_int("time_reopen", self->super.time_reopen), evt_tag_str("reason", error.message), evt_tag_str("driver", owner->super.super.super.id)); return LTR_ERROR; } } return LTR_SUCCESS; } static LogThreadedResult _worker_insert(LogThreadedDestWorker *s, LogMessage *msg) { MongoDBDestWorker *self = (MongoDBDestWorker *) s; MongoDBDestDriver *owner = (MongoDBDestDriver *) self->super.owner; gboolean success; gboolean drop_silently = owner->template_options.on_error & ON_ERROR_SILENT; bson_reinit(self->bson); LogTemplateEvalOptions options = {&owner->template_options, LTZ_SEND, self->super.seq_num, NULL, LM_VT_STRING}; success = value_pairs_walk(owner->vp, _vp_obj_start, _vp_process_value, _vp_obj_end, msg, &options, 0, self); if (!success) { if (!drop_silently) { msg_error("Failed to format message for MongoDB, dropping message", evt_tag_value_pairs("message", owner->vp, msg, &options), evt_tag_str("driver", owner->super.super.super.id)); } return LTR_DROP; } msg_debug("Outgoing message to MongoDB destination", evt_tag_value_pairs("message", owner->vp, msg, &options), evt_tag_str("driver", owner->super.super.super.id)); if (!owner->collection_is_literal_string) { ScratchBuffersMarker mark; GString *last_collection = scratch_buffers_alloc_and_mark(&mark); g_string_assign(last_collection, self->collection->str); const gchar *new_collection = _format_collection_template(self, msg); bool should_switch_collection = (strcmp(last_collection->str, new_collection) != 0); scratch_buffers_reclaim_marked(mark); if (should_switch_collection && !_switch_collection(self, new_collection)) return LTR_ERROR; } if (owner->use_bulk) return _bulk_insert(self); else return _single_insert(self); } static gboolean _worker_init(LogThreadedDestWorker *s) { MongoDBDestWorker *self = (MongoDBDestWorker *) s; self->collection = g_string_sized_new(64); self->bson = bson_sized_new(4096); /* NOTE: write concern can be used by _compose_bulk_op_options too, keep the order! */ _compose_write_concern(self); _compose_bulk_op_options(self); return log_threaded_dest_worker_init_method(s); } static void _worker_deinit(LogThreadedDestWorker *s) { MongoDBDestWorker *self = (MongoDBDestWorker *) s; _destroy_write_concern(self); _destroy_bulk_op_options(self); if (self->bson) bson_destroy(self->bson); self->bson = NULL; g_string_free(self->collection, TRUE); self->collection = NULL; log_threaded_dest_worker_deinit_method(s); } LogThreadedDestWorker * afmongodb_dw_new(LogThreadedDestDriver *o, gint worker_index) { MongoDBDestWorker *self = g_new0(MongoDBDestWorker, 1); MongoDBDestDriver *owner = (MongoDBDestDriver *) o; log_threaded_dest_worker_init_instance(&self->super, o, worker_index); self->super.init = _worker_init; self->super.deinit = _worker_deinit; self->super.connect = _worker_connect; self->super.disconnect = _worker_disconnect; self->super.insert = _worker_insert; if (owner->use_bulk) self->super.flush = _worker_batch_flush; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb-worker.h000066400000000000000000000030261450431004300243740ustar00rootroot00000000000000/* * Copyright (c) 2010-2021 One Identity * Copyright (c) 2010-2014 Gergely Nagy * Copyright (c) 2021 László Várady * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFMONGODB_WORKER_H_INCLUDED #define AFMONGODB_WORKER_H_INCLUDED #include "syslog-ng.h" #include "mongoc.h" #include "logthrdest/logthrdestdrv.h" typedef struct MongoDBDestWorker { LogThreadedDestWorker super; mongoc_client_t *client; GString *collection; mongoc_collection_t *coll_obj; mongoc_bulk_operation_t *bulk_op; mongoc_write_concern_t *write_concern; bson_t *bson; bson_t *bson_opts; } MongoDBDestWorker; LogThreadedDestWorker *afmongodb_dw_new(LogThreadedDestDriver *owner, gint worker_index); #endif syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb.c000066400000000000000000000271701450431004300230660ustar00rootroot00000000000000/* * Copyright (c) 2010-2016 Balabit * Copyright (c) 2010-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afmongodb.h" #include "afmongodb-parser.h" #include "afmongodb-worker.h" #include "apphook.h" #include "messages.h" #include "stats/stats-registry.h" #include "plugin.h" #include "plugin-types.h" #include "syslog-ng.h" #include #include "afmongodb-private.h" #define DEFAULT_URI \ "mongodb://127.0.0.1:27017/syslog"\ "?wtimeoutMS=60000&socketTimeoutMS=60000&connectTimeoutMS=60000" #define DEFAULT_SERVER_SELECTION_TIMEOUT 3000 /* * Configuration */ LogTemplateOptions * afmongodb_dd_get_template_options(LogDriver *s) { MongoDBDestDriver *self = (MongoDBDestDriver *)s; return &self->template_options; } void afmongodb_dd_set_uri(LogDriver *d, const gchar *uri) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; if (self->uri_str) g_string_assign(self->uri_str, uri); else self->uri_str = g_string_new(uri); } void afmongodb_dd_set_collection(LogDriver *d, LogTemplate *collection_template) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; log_template_unref(self->collection_template); self->collection_template = collection_template; self->collection_is_literal_string = log_template_is_literal_string(self->collection_template); } void afmongodb_dd_set_value_pairs(LogDriver *d, ValuePairs *vp) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; value_pairs_unref(self->vp); self->vp = vp; } void afmongodb_dd_set_bulk(LogDriver *d, gboolean bulk) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; self->use_bulk = bulk; } void afmongodb_dd_set_bulk_unordered(LogDriver *d, gboolean unordered) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; self->bulk_unordered = unordered; } void afmongodb_dd_set_bulk_bypass_validation(LogDriver *d, gboolean bypass_validation) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; self->bulk_bypass_validation = bypass_validation; } void afmongodb_dd_set_write_concern(LogDriver *d, int32_t write_concern_level) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; self->write_concern_level = write_concern_level; } /* * Utilities */ static gchar * _format_instance_id(const LogThreadedDestDriver *d, const gchar *format, StatsClusterKeyBuilder *kb) { const MongoDBDestDriver *self = (const MongoDBDestDriver *)d; const gchar *first_host = ""; const gchar *db; const gchar *replica_set; const gchar *coll; if (kb || !((LogPipe *)d)->persist_name) { const mongoc_host_list_t *hosts = mongoc_uri_get_hosts(self->uri_obj); if (hosts) { if (hosts->family == AF_UNIX) first_host = hosts->host; else first_host = hosts->host_and_port; } db = self->const_db ? self->const_db : ""; replica_set = mongoc_uri_get_replica_set(self->uri_obj); if (!replica_set) replica_set = ""; coll = self->collection_template->template_str ? self->collection_template->template_str : ""; } if (kb) { stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "mongodb")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", first_host)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("database", db)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("replica_set", replica_set)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("collection", coll)); } static gchar args[1024]; static gchar id[1024]; if (((LogPipe *)d)->persist_name) { g_snprintf(args, sizeof(args), "%s", ((LogPipe *)d)->persist_name); } else { g_snprintf(args, sizeof(args), "%s,%s,%s,%s", first_host, db, replica_set, coll); } g_snprintf(id, sizeof(id), format, args); return id; } static const gchar * _format_stats_key(LogThreadedDestDriver *d, StatsClusterKeyBuilder *kb) { return _format_instance_id(d, "mongodb,%s", kb); } static const gchar * _format_persist_name(const LogPipe *s) { const LogThreadedDestDriver *self = (const LogThreadedDestDriver *)s; return s->persist_name ? _format_instance_id(self, "afmongodb.%s", NULL) : _format_instance_id(self, "afmongodb(%s)", NULL); } static inline void _uri_set_default_server_selection_timeout(mongoc_uri_t *uri_obj) { #if SYSLOG_NG_HAVE_DECL_MONGOC_URI_SET_OPTION_AS_INT32 && SYSLOG_NG_HAVE_DECL_MONGOC_URI_SERVERSELECTIONTIMEOUTMS gint32 server_selection_timeout = mongoc_uri_get_option_as_int32(uri_obj, MONGOC_URI_SERVERSELECTIONTIMEOUTMS, DEFAULT_SERVER_SELECTION_TIMEOUT); mongoc_uri_set_option_as_int32(uri_obj, MONGOC_URI_SERVERSELECTIONTIMEOUTMS, server_selection_timeout); #endif } gboolean afmongodb_dd_private_uri_init(LogDriver *d) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; if (!self->uri_str) self->uri_str = g_string_new(DEFAULT_URI); self->uri_obj = mongoc_uri_new(self->uri_str->str); if (!self->uri_obj) { msg_error("Error parsing MongoDB URI", evt_tag_str("uri", self->uri_str->str), evt_tag_str("driver", self->super.super.super.id)); return FALSE; } _uri_set_default_server_selection_timeout(self->uri_obj); self->const_db = mongoc_uri_get_database(self->uri_obj); if (!self->const_db || !strlen(self->const_db)) { msg_error("Missing DB name from MongoDB URI", evt_tag_str("uri", self->uri_str->str), evt_tag_str("driver", self->super.super.super.id)); return FALSE; } msg_verbose("Initializing MongoDB destination", evt_tag_str("uri", self->uri_str->str), evt_tag_str("db", self->const_db), evt_tag_str("collection", self->collection_template->template_str), evt_tag_str("driver", self->super.super.super.id)); return TRUE; } gboolean afmongodb_dd_client_pool_init(MongoDBDestDriver *self) { self->pool = mongoc_client_pool_new(self->uri_obj); if (!self->pool) return FALSE; mongoc_client_pool_max_size(self->pool, self->super.num_workers); return TRUE; } /* * Main thread */ static void _init_value_pairs_dot_to_underscore_transformation(MongoDBDestDriver *self) { ValuePairsTransformSet *vpts; /* Always replace a leading dot with an underscore. */ vpts = value_pairs_transform_set_new(".*"); value_pairs_transform_set_add_func(vpts, value_pairs_new_transform_replace_prefix(".", "_")); value_pairs_add_transforms(self->vp, vpts); } static gboolean _init(LogPipe *s) { MongoDBDestDriver *self = (MongoDBDestDriver *)s; GlobalConfig *cfg = log_pipe_get_config(s); log_template_options_init(&self->template_options, cfg); _init_value_pairs_dot_to_underscore_transformation(self); if (!afmongodb_dd_private_uri_init(&self->super.super.super)) return FALSE; if (!afmongodb_dd_client_pool_init(self)) return FALSE; if (!log_threaded_dest_driver_init_method(s)) return FALSE; if (cfg_is_config_version_older(cfg, VERSION_VALUE_4_0) && !value_pairs_is_cast_to_strings_explicit(self->vp)) { if (cfg_is_typing_feature_enabled(cfg)) { msg_warning("WARNING: the mongodb() destination starts using type information " "associated with name-value pairs in " VERSION_4_0 ". This can possibly cause fields in the BSON " "document to change types if no explicit type hint is " "specified. This change will cause the type in the output " "document match the original type that was parsed " "using json-parser(), add cast(yes) option to mongodb() " "to keep using strings instead of typed values", log_pipe_location_tag(s)); } value_pairs_set_cast_to_strings(self->vp, TRUE); } return TRUE; } static gboolean _deinit(LogPipe *s) { MongoDBDestDriver *self = (MongoDBDestDriver *)s; if(!log_threaded_dest_driver_deinit_method(s)) return FALSE; if (self->pool) mongoc_client_pool_destroy(self->pool); if (self->uri_obj) mongoc_uri_destroy(self->uri_obj); return TRUE; } static void _free(LogPipe *d) { MongoDBDestDriver *self = (MongoDBDestDriver *)d; log_template_options_destroy(&self->template_options); if (self->uri_str) { g_string_free(self->uri_str, TRUE); self->uri_str = NULL; } log_template_unref(self->collection_template); value_pairs_unref(self->vp); log_threaded_dest_driver_free(d); } /* * Plugin glue. */ static void afmongodb_global_init(void) { mongoc_init(); } static void afmongodb_global_deinit(void) { mongoc_cleanup(); } static void afmongodb_register_global_initializers(void) { static gboolean initialized = FALSE; if (!initialized) { register_application_hook(AH_STARTUP, (ApplicationHookFunc) afmongodb_global_init, NULL, AHM_RUN_ONCE); register_application_hook(AH_SHUTDOWN, (ApplicationHookFunc) afmongodb_global_deinit, NULL, AHM_RUN_ONCE); initialized = TRUE; } } LogDriver * afmongodb_dd_new(GlobalConfig *cfg) { MongoDBDestDriver *self = g_new0(MongoDBDestDriver, 1); afmongodb_register_global_initializers(); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = _init; self->super.super.super.super.deinit = _deinit; self->super.super.super.super.free_fn = _free; self->super.super.super.super.generate_persist_name = _format_persist_name; self->super.format_stats_key = _format_stats_key; self->super.stats_source = stats_register_type("mongodb"); self->super.worker.construct = afmongodb_dw_new; LogTemplate *template = log_template_new(cfg, NULL); log_template_compile_literal_string(template, "messages"); afmongodb_dd_set_collection(&self->super.super.super, template); log_template_options_defaults(&self->template_options); ValuePairs *vp = value_pairs_new_default(cfg); value_pairs_set_include_bytes(vp, TRUE); afmongodb_dd_set_value_pairs(&self->super.super.super, vp); self->use_bulk = TRUE; self->bulk_unordered = FALSE; self->bulk_bypass_validation = FALSE; self->write_concern_level = MONGOC_WRITE_CONCERN_W_DEFAULT; return &self->super.super.super; } extern CfgParser afmongodb_dd_parser; static Plugin afmongodb_plugin = { .type = LL_CONTEXT_DESTINATION, .name = "mongodb", .parser = &afmongodb_parser, }; gboolean afmongodb_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, &afmongodb_plugin, 1); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afmongodb", .version = SYSLOG_NG_VERSION, .description = "The afmongodb module provides MongoDB destination support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = &afmongodb_plugin, .plugins_len = 1, }; syslog-ng-syslog-ng-4.4.0/modules/afmongodb/afmongodb.h000066400000000000000000000034511450431004300230670ustar00rootroot00000000000000/* * Copyright (c) 2010-2016 Balabit * Copyright (c) 2010-2013 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFMONGODB_H_INCLUDED #define AFMONGODB_H_INCLUDED #include "syslog-ng.h" #include "driver.h" #include "template/templates.h" #include "value-pairs/value-pairs.h" LogDriver *afmongodb_dd_new(GlobalConfig *cfg); void afmongodb_dd_set_uri(LogDriver *d, const gchar *uri); void afmongodb_dd_set_collection(LogDriver *d, LogTemplate *collection_template); void afmongodb_dd_set_value_pairs(LogDriver *d, ValuePairs *vp); void afmongodb_dd_set_bulk(LogDriver *d, gboolean bulk); void afmongodb_dd_set_bulk_unordered(LogDriver *d, gboolean unordered); void afmongodb_dd_set_bulk_bypass_validation(LogDriver *d, gboolean bypass_validation); void afmongodb_dd_set_write_concern(LogDriver *d, int32_t write_concern_level); LogTemplateOptions *afmongodb_dd_get_template_options(LogDriver *s); gboolean afmongodb_dd_private_uri_init(LogDriver *self); #endif syslog-ng-syslog-ng-4.4.0/modules/afmongodb/tests/000077500000000000000000000000001450431004300221215ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afmongodb/tests/CMakeLists.txt000066400000000000000000000002171450431004300246610ustar00rootroot00000000000000add_unit_test(LIBTEST TARGET test-mongodb-config INCLUDES "${AFMONGODB_INCLUDE_DIR}" DEPENDS afmongodb SOURCES test-mongodb-config.c ) syslog-ng-syslog-ng-4.4.0/modules/afmongodb/tests/Makefile.am000066400000000000000000000006711450431004300241610ustar00rootroot00000000000000modules_afmongodb_tests_TESTS = \ modules/afmongodb/tests/test-mongodb-config check_PROGRAMS += ${modules_afmongodb_tests_TESTS} modules_afmongodb_tests_test_mongodb_config_CFLAGS = \ $(LIBMONGO_CFLAGS) \ $(TEST_CFLAGS) modules_afmongodb_tests_test_mongodb_config_LDADD = \ $(TEST_LDADD) \ -dlpreopen $(top_builddir)/modules/afmongodb/libafmongodb.la \ ${lmc_EXTRA_DEPS} syslog-ng-syslog-ng-4.4.0/modules/afmongodb/tests/test-mongodb-config.c000066400000000000000000000111531450431004300261330ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/cr_template.h" #include "libtest/grab-logging.h" #include "apphook.h" #include "logthrdest/logthrdestdrv.h" #include "../afmongodb-parser.h" #define SAFEOPTS "?wtimeoutMS=60000&socketTimeoutMS=60000&connectTimeoutMS=60000" static LogDriver *mongodb; static void assert_uri_present_in_log(const gchar *uri, const gchar *db, const gchar *coll) { GString *pattern = g_string_sized_new(0); g_string_append_printf(pattern, "Initializing MongoDB destination;" " uri='mongodb://%s', db='%s', collection='%s'", uri, db, coll); assert_grabbed_log_contains(pattern->str); g_string_free(pattern, TRUE); } Test(mongodb_config, test_persist_name) { afmongodb_dd_set_uri(mongodb, "mongodb://127.0.0.2:27018,localhost:1234/syslog" SAFEOPTS "&replicaSet=x"); cr_assert(afmongodb_dd_private_uri_init(mongodb)); cr_assert_str_eq(log_pipe_get_persist_name(&mongodb->super), "afmongodb(127.0.0.2:27018,syslog,x,messages)"); } Test(mongodb_config, test_stats_name) { afmongodb_dd_set_uri(mongodb, "mongodb://127.0.0.2:27018,localhost:1234/syslog" SAFEOPTS "&replicaSet=x"); cr_assert(afmongodb_dd_private_uri_init(mongodb)); LogThreadedDestDriver *self = (LogThreadedDestDriver *)mongodb; const gchar *name = self->format_stats_key(self, NULL); cr_assert(name, "mongodb,127.0.0.2:27018,syslog,x,messages"); } Test(mongodb_config, test_uri_components_are_parsed_and_reported_correctly) { reset_grabbed_messages(); cr_assert(afmongodb_dd_private_uri_init(mongodb)); assert_uri_present_in_log("127.0.0.1:27017/syslog" SAFEOPTS, "syslog", "messages"); reset_grabbed_messages(); afmongodb_dd_set_uri(mongodb, "mongodb://%2Ftmp%2Fmongo.sock/syslog"); cr_assert(afmongodb_dd_private_uri_init(mongodb)); assert_uri_present_in_log("%2Ftmp%2Fmongo.sock/syslog", "syslog", "messages"); reset_grabbed_messages(); afmongodb_dd_set_uri(mongodb, "mongodb://localhost:1234/syslog-ng"); cr_assert(afmongodb_dd_private_uri_init(mongodb)); assert_uri_present_in_log("localhost:1234/syslog-ng", "syslog-ng", "messages"); reset_grabbed_messages(); } Test(mongodb_config, test_collection_option_is_consumed_and_reported_correctly) { afmongodb_dd_set_collection(mongodb, compile_template("messages2")); cr_assert(afmongodb_dd_private_uri_init(mongodb)); assert_uri_present_in_log("127.0.0.1:27017/syslog" SAFEOPTS, "syslog", "messages2"); } Test(mongodb_config, test_invalid_uris_are_reported_as_errors) { afmongodb_dd_set_uri(mongodb, "INVALID-URI"); cr_assert_not(afmongodb_dd_private_uri_init(mongodb)); assert_grabbed_log_contains("Error parsing MongoDB URI; uri='INVALID-URI'"); reset_grabbed_messages(); afmongodb_dd_set_uri(mongodb, "mongodb://127.0.0.1:27017/"); cr_assert_not(afmongodb_dd_private_uri_init(mongodb)); assert_grabbed_log_contains("Missing DB name from MongoDB URI; uri='mongodb://127.0.0.1:27017/'"); } static void setup(void) { /* we are relying on verbose messages in tests */ verbose_flag = TRUE; app_startup(); configuration = cfg_new_snippet(); const gchar *persist_filename = ""; configuration->state = persist_state_new(persist_filename); start_grabbing_messages(); mongodb = afmongodb_dd_new(configuration); } static void teardown(void) { reset_grabbed_messages(); if (mongodb) { log_pipe_unref(&mongodb->super); mongodb = NULL; } if (configuration->persist) { persist_config_free(configuration->persist); configuration->persist = NULL; } cfg_free(configuration); app_shutdown(); } TestSuite(mongodb_config, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/afprog/000077500000000000000000000000001450431004300203015ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afprog/CMakeLists.txt000066400000000000000000000003121450431004300230350ustar00rootroot00000000000000set(AFPROG_SOURCES "afprog.h" "afprog-parser.h" "afprog.c" "afprog-parser.c" "afprog-plugin.c" ) add_module( TARGET afprog GRAMMAR afprog-grammar SOURCES ${AFPROG_SOURCES} ) syslog-ng-syslog-ng-4.4.0/modules/afprog/Makefile.am000066400000000000000000000016641450431004300223440ustar00rootroot00000000000000module_LTLIBRARIES += modules/afprog/libafprog.la modules_afprog_libafprog_la_SOURCES = \ modules/afprog/afprog.c \ modules/afprog/afprog.h \ modules/afprog/afprog-grammar.y \ modules/afprog/afprog-parser.c \ modules/afprog/afprog-parser.h \ modules/afprog/afprog-plugin.c BUILT_SOURCES += \ modules/afprog/afprog-grammar.y \ modules/afprog/afprog-grammar.c \ modules/afprog/afprog-grammar.h EXTRA_DIST += \ modules/afprog/afprog-grammar.ym \ modules/afprog/CMakeLists.txt modules_afprog_libafprog_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/afprog \ -I$(top_builddir)/modules/afprog modules_afprog_libafprog_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_afprog_libafprog_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afprog_libafprog_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) modules/afprog modules/afprog/ mod-afprog mod-prog: \ modules/afprog/libafprog.la .PHONY: modules/afprog/ mod-afprog mod-prog syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog-grammar.ym000066400000000000000000000063611450431004300235600ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "afprog-parser.h" } %code { #include "afprog.h" #include "cfg-parser.h" #include "syslog-names.h" #include "messages.h" #include "plugin.h" #include "cfg-grammar-internal.h" #include } %define api.prefix {afprog_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_PROGRAM %token KW_KEEP_ALIVE %token KW_INHERIT_ENVIRONMENT %type source_afprogram %type source_afprogram_params %type dest_afprogram %type dest_afprogram_params %% start : LL_CONTEXT_SOURCE source_afprogram { YYACCEPT; } | LL_CONTEXT_DESTINATION dest_afprogram { YYACCEPT; } ; source_afprogram : KW_PROGRAM '(' _inner_src_context_push source_afprogram_params _inner_src_context_pop ')' { $$ = $4; } ; source_afprogram_params : string { last_driver = *instance = afprogram_sd_new($1, configuration); last_reader_options = &((AFProgramSourceDriver *) last_driver)->reader_options; } source_afprogram_options { $$ = last_driver; free($1); } ; source_afprogram_options : source_afprogram_option source_afprogram_options | ; source_afprogram_option : source_reader_option | source_driver_option | KW_INHERIT_ENVIRONMENT '(' yesno ')' { afprogram_set_inherit_environment(&((AFProgramSourceDriver *)last_driver)->process_info, $3); } ; dest_afprogram : KW_PROGRAM '(' _inner_dest_context_push dest_afprogram_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_afprogram_params : string { last_driver = *instance = afprogram_dd_new($1, configuration); last_writer_options = &((AFProgramDestDriver *) last_driver)->writer_options; } dest_afprogram_options { $$ = last_driver; free($1); } ; dest_afprogram_options : dest_afprogram_option dest_afprogram_options | ; dest_afprogram_option : dest_writer_option | dest_driver_option | KW_KEEP_ALIVE '(' yesno ')' { afprogram_dd_set_keep_alive((AFProgramDestDriver *)last_driver, $3); } | KW_INHERIT_ENVIRONMENT '(' yesno ')' { afprogram_set_inherit_environment(&((AFProgramDestDriver *)last_driver)->process_info, $3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog-parser.c000066400000000000000000000032141450431004300232150ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afprog.h" #include "cfg-parser.h" #include "afprog-grammar.h" extern int afprog_debug; int afprog_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afprog_keywords[] = { { "program", KW_PROGRAM }, { "keep_alive", KW_KEEP_ALIVE }, { "inherit_environment", KW_INHERIT_ENVIRONMENT }, { NULL } }; CfgParser afprog_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afprog_debug, #endif .name = "afprog", .keywords = afprog_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer arg)) afprog_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afprog_, AFPROG_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog-parser.h000066400000000000000000000022261450431004300232240ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFPROG_PARSER_H_INCLUDED #define AFPROG_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser afprog_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afprog_, AFPROG_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog-plugin.c000066400000000000000000000033521450431004300232220ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afprog_parser; static Plugin afprog_plugins[] = { { .type = LL_CONTEXT_SOURCE, .name = "program", .parser = &afprog_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "program", .parser = &afprog_parser, }, }; gboolean afprog_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afprog_plugins, G_N_ELEMENTS(afprog_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afprog", .version = SYSLOG_NG_VERSION, .description = "The afprog module provides program source & destination drivers for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afprog_plugins, .plugins_len = G_N_ELEMENTS(afprog_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog.c000066400000000000000000000526021450431004300217300ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afprog.h" #include "driver.h" #include "messages.h" #include "logwriter.h" #include "children.h" #include "fdhelpers.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-key-builder.h" #include "transport/transport-pipe.h" #include "logproto/logproto-text-server.h" #include "logproto/logproto-text-client.h" #include "poll-fd-events.h" #include #include #include #include #include #include typedef struct _AFProgramReloadStoreItem { LogWriter *writer; pid_t pid; } AFProgramReloadStoreItem; static inline void _terminate_process_group_by_pid(const pid_t pid) { msg_verbose("Sending TERM signal to the process group", evt_tag_int("pid", pid)); pid_t pgid = getpgid(pid); if (pgid != -1 && pgid != getpgrp()) killpg(pgid, SIGTERM); } static inline void afprogram_reload_store_item_deinit(AFProgramReloadStoreItem *reload_info) { child_manager_unregister(reload_info->pid); _terminate_process_group_by_pid(reload_info->pid); } static inline void afprogram_reload_store_item_free(AFProgramReloadStoreItem *reload_info) { log_pipe_unref((LogPipe *)reload_info->writer); g_free(reload_info); } static inline void afprogram_reload_store_item_destroy_notify(gpointer data) { AFProgramReloadStoreItem *reload_info = (AFProgramReloadStoreItem *)data; afprogram_reload_store_item_deinit(reload_info); afprogram_reload_store_item_free(reload_info); } static inline void _exec_program_with_clean_environment(const gchar *cmdline) { execle("/bin/sh", "/bin/sh", "-c", cmdline, NULL, NULL); } static inline void _exec_program(const gchar *cmdline) { execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); } static void _close_all_fd(void) { const rlim_t min_range = 10000; struct rlimit rlp; if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) { /* * Failing to query max *fd*, still closing an arbitrary range might make sense, * trying with some arbitrary big number. The only issue could be that it cannot * close all of the needed *fd* and fail to bind to a socket (original issue). */ rlp.rlim_max = min_range; } else if (rlp.rlim_max == RLIM_INFINITY) { /* * Also could happen that the limits are RLIM_INFINITY. * Use the same logic as above, try to close as much as possible. */ rlp.rlim_max = (rlp.rlim_cur != RLIM_INFINITY ? rlp.rlim_cur : min_range); } for (rlim_t i = rlp.rlim_max; i > 2; --i) close(i); } static void _wait_for_child_closing_fds(int pipe[2]) { gchar buff[1]; while (read(pipe[0], buff, 1) != 0); } static gboolean afprogram_popen(AFProgramProcessInfo *process_info, GIOCondition cond, gint *fd) { int msg_pipe[2]; int sync_pipe[2]; g_return_val_if_fail(cond == G_IO_IN || cond == G_IO_OUT, FALSE); if (pipe(msg_pipe) == -1) { msg_error("Error creating program pipe", evt_tag_str("cmdline", process_info->cmdline->str), evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } if (pipe(sync_pipe) == -1) { msg_error("Error creating program pipe", evt_tag_str("cmdline", process_info->cmdline->str), evt_tag_error(EVT_TAG_OSERROR)); close(msg_pipe[0]); close(msg_pipe[1]); return FALSE; } if ((process_info->pid = fork()) < 0) { msg_error("Error in fork()", evt_tag_error(EVT_TAG_OSERROR)); close(msg_pipe[0]); close(msg_pipe[1]); close(sync_pipe[0]); close(sync_pipe[1]); return FALSE; } if (process_info->pid == 0) { /* child */ int devnull; setpgid(0, 0); devnull = open("/dev/null", O_WRONLY); if (devnull == -1) { _exit(127); } if (cond == G_IO_IN) { dup2(msg_pipe[1], 1); dup2(devnull, 0); dup2(devnull, 2); } else { dup2(msg_pipe[0], 0); dup2(devnull, 1); dup2(devnull, 2); } dup2(sync_pipe[1], 3); close(devnull); close(msg_pipe[0]); close(msg_pipe[1]); _close_all_fd(); if (process_info->inherit_environment) _exec_program(process_info->cmdline->str); else _exec_program_with_clean_environment(process_info->cmdline->str); _exit(127); } close(sync_pipe[1]); _wait_for_child_closing_fds(sync_pipe); close(sync_pipe[0]); if (cond == G_IO_IN) { *fd = msg_pipe[0]; close(msg_pipe[1]); } else { *fd = msg_pipe[1]; close(msg_pipe[0]); } msg_verbose(cond == G_IO_IN ? "Program source started" : "Program destination started", evt_tag_str("cmdline", process_info->cmdline->str), evt_tag_int("fd", *fd)); return TRUE; } /* source driver */ static void afprogram_sd_kill_child(AFProgramSourceDriver *self) { if (self->process_info.pid != -1) { msg_verbose("Sending source program a TERM signal", evt_tag_str("cmdline", self->process_info.cmdline->str), evt_tag_int("child_pid", self->process_info.pid)); _terminate_process_group_by_pid(self->process_info.pid); self->process_info.pid = -1; } } static void afprogram_sd_exit(pid_t pid, int status, gpointer s) { AFProgramSourceDriver *self = (AFProgramSourceDriver *) s; /* Note: self->process_info.pid being -1 means that deinit was called, thus we don't * need to restart the command. self->process_info.pid might change due to EPIPE * handling restarting the command before this handler is run. */ if (self->process_info.pid != -1 && self->process_info.pid == pid) { msg_verbose("Child program exited", evt_tag_str("cmdline", self->process_info.cmdline->str), evt_tag_int("status", status)); self->process_info.pid = -1; } } static gboolean afprogram_sd_init(LogPipe *s) { AFProgramSourceDriver *self = (AFProgramSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); gint fd; if (!log_src_driver_init_method(s)) return FALSE; log_reader_options_init(&self->reader_options, cfg, self->super.super.group); msg_verbose("Starting source program", evt_tag_str("cmdline", self->process_info.cmdline->str)); if (!afprogram_popen(&self->process_info, G_IO_IN, &fd)) return FALSE; /* parent */ child_manager_register(self->process_info.pid, afprogram_sd_exit, log_pipe_ref(&self->super.super.super), (GDestroyNotify) log_pipe_unref); g_fd_set_nonblock(fd, TRUE); g_fd_set_cloexec(fd, TRUE); if (!self->reader) { LogTransport *transport; LogProtoServer *proto; transport = log_transport_pipe_new(fd); proto = log_proto_text_server_new(transport, &self->reader_options.proto_options.super); self->reader = log_reader_new(s->cfg); log_pipe_set_options(&self->reader->super.super, &self->super.super.super.options); log_reader_open(self->reader, proto, poll_fd_events_new(fd)); StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(kb, stats_cluster_label("driver", "program")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("command", self->process_info.cmdline->str)); log_reader_set_options(self->reader, s, &self->reader_options, self->super.super.id, kb); } log_pipe_append((LogPipe *) self->reader, &self->super.super.super); if (!log_pipe_init((LogPipe *) self->reader)) { msg_error("Error initializing program source, closing fd", evt_tag_int("fd", fd)); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; close(fd); return FALSE; } return TRUE; } static gboolean afprogram_sd_deinit(LogPipe *s) { AFProgramSourceDriver *self = (AFProgramSourceDriver *) s; afprogram_sd_kill_child(self); if (self->reader) { log_pipe_deinit((LogPipe *) self->reader); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; } if (!log_src_driver_deinit_method(s)) return FALSE; return TRUE; } static void afprogram_sd_free(LogPipe *s) { AFProgramSourceDriver *self = (AFProgramSourceDriver *) s; log_reader_options_destroy(&self->reader_options); g_string_free(self->process_info.cmdline, TRUE); log_src_driver_free(s); } static void afprogram_sd_notify(LogPipe *s, gint notify_code, gpointer user_data) { switch (notify_code) { case NC_CLOSE: case NC_READ_ERROR: afprogram_sd_deinit(s); afprogram_sd_init(s); break; default: break; } } LogDriver * afprogram_sd_new(gchar *cmdline, GlobalConfig *cfg) { AFProgramSourceDriver *self = g_new0(AFProgramSourceDriver, 1); log_src_driver_init_instance(&self->super, cfg); self->super.super.super.init = afprogram_sd_init; self->super.super.super.deinit = afprogram_sd_deinit; self->super.super.super.free_fn = afprogram_sd_free; self->super.super.super.notify = afprogram_sd_notify; self->process_info.cmdline = g_string_new(cmdline); afprogram_set_inherit_environment(&self->process_info, TRUE); log_reader_options_defaults(&self->reader_options); self->reader_options.parse_options.flags |= LP_LOCAL; self->reader_options.super.stats_level = STATS_LEVEL0; self->reader_options.super.stats_source = stats_register_type("program"); return &self->super.super; } /* dest driver */ static void afprogram_dd_exit(pid_t pid, int status, gpointer s); static gchar * afprogram_dd_format_queue_persist_name(AFProgramDestDriver *self) { static gchar persist_name[256]; g_snprintf(persist_name, sizeof(persist_name), "afprogram_dd_qname(%s,%s)", self->process_info.cmdline->str, self->super.super.id); return persist_name; } static const gchar * afprogram_dd_format_persist_name(const LogPipe *s) { const AFProgramDestDriver *self = (const AFProgramDestDriver *)s; static gchar persist_name[256]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "afprogram_dd_name.%s", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "afprogram_dd_name(%s,%s)", self->process_info.cmdline->str, self->super.super.id); return persist_name; } static void afprogram_dd_kill_child(AFProgramDestDriver *self) { if (self->process_info.pid != -1) { msg_verbose("Sending destination program a TERM signal", evt_tag_str("cmdline", self->process_info.cmdline->str), evt_tag_int("child_pid", self->process_info.pid)); _terminate_process_group_by_pid(self->process_info.pid); self->process_info.pid = -1; } } static inline gboolean afprogram_dd_open_program(AFProgramDestDriver *self, int *fd) { if (self->process_info.pid == -1) { msg_verbose("Starting destination program", evt_tag_str("cmdline", self->process_info.cmdline->str)); if (!afprogram_popen(&self->process_info, G_IO_OUT, fd)) return FALSE; g_fd_set_nonblock(*fd, TRUE); } child_manager_register(self->process_info.pid, afprogram_dd_exit, log_pipe_ref(&self->super.super.super), (GDestroyNotify)log_pipe_unref); return TRUE; } static gboolean afprogram_dd_reopen(AFProgramDestDriver *self) { int fd; afprogram_dd_kill_child(self); if (!afprogram_dd_open_program(self, &fd)) return FALSE; log_writer_reopen(self->writer, log_proto_text_client_new(log_transport_pipe_new(fd), &self->writer_options.proto_options.super)); return TRUE; } static gboolean afprogram_dd_is_command_not_found(int status) { /* * Status here is a 16-bit int, the real exit status is the 8 least * significant bits of it, and an exit status of 127 from the shell is * supposed to signal a command-not-found case. The other 8 bits are one bit * to signal if the child dumped core, the other 7 the signal - if any - with * which it exited. * * In our case, we want to make sure that the other 8 bits are all empty (no * core dump; and normal exit, not one due to a signal), hence the second part * of the check. * * See wait(2) for more information. */ return (status >> 8) == 127 && ((status & 0x00ff) == 0); } static void afprogram_dd_exit(pid_t pid, int status, gpointer s) { AFProgramDestDriver *self = (AFProgramDestDriver *) s; /* Note: self->process_info.pid being -1 means that deinit was called, thus we don't * need to restart the command. self->process_info.pid might change due to EPIPE * handling restarting the command before this handler is run. */ if (self->process_info.pid != -1 && self->process_info.pid == pid) { if (afprogram_dd_is_command_not_found(status)) { msg_error("Child program exited with command not found, stopping the destination.", evt_tag_str("cmdline", self->process_info.cmdline->str), evt_tag_int("status", status)); self->process_info.pid = -1; } else { msg_info("Child program exited, restarting", evt_tag_str("cmdline", self->process_info.cmdline->str), evt_tag_int("status", status)); self->process_info.pid = -1; afprogram_dd_reopen(self); } } } static gboolean afprogram_dd_restore_reload_store_item(AFProgramDestDriver *self, GlobalConfig *cfg) { const gchar *persist_name = afprogram_dd_format_persist_name((const LogPipe *)self); AFProgramReloadStoreItem *restored_info = (AFProgramReloadStoreItem *)cfg_persist_config_fetch(cfg, persist_name); if (restored_info) { self->process_info.pid = restored_info->pid; self->writer = restored_info->writer; child_manager_register(self->process_info.pid, afprogram_dd_exit, log_pipe_ref(&self->super.super.super), (GDestroyNotify)log_pipe_unref); g_free(restored_info); } return !!(self->writer); } static void _init_stats_key_builders(AFProgramDestDriver *self, StatsClusterKeyBuilder **writer_sck_builder, StatsClusterKeyBuilder **driver_sck_builder, StatsClusterKeyBuilder **queue_sck_builder) { *writer_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*writer_sck_builder, stats_cluster_label("driver", "program")); stats_cluster_key_builder_add_legacy_label(*writer_sck_builder, stats_cluster_label("command", self->process_info.cmdline->str)); *driver_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("driver", "program")); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("id", self->super.super.id)); stats_cluster_key_builder_add_legacy_label(*driver_sck_builder, stats_cluster_label("command", self->process_info.cmdline->str)); stats_cluster_key_builder_set_legacy_alias(*driver_sck_builder, self->writer_options.stats_source | SCS_DESTINATION, self->super.super.id, self->process_info.cmdline->str); *queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("driver", "program")); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("id", self->super.super.id)); stats_cluster_key_builder_add_legacy_label(*queue_sck_builder, stats_cluster_label("command", self->process_info.cmdline->str)); } static gboolean afprogram_dd_init(LogPipe *s) { AFProgramDestDriver *self = (AFProgramDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_dest_driver_init_method(s)) return FALSE; log_writer_options_init(&self->writer_options, cfg, 0); const gboolean restore_successful = afprogram_dd_restore_reload_store_item(self, cfg); if (!self->writer) self->writer = log_writer_new(LW_FORMAT_FILE, s->cfg); StatsClusterKeyBuilder *writer_sck_builder; StatsClusterKeyBuilder *driver_sck_builder; StatsClusterKeyBuilder *queue_sck_builder; _init_stats_key_builders(self, &writer_sck_builder, &driver_sck_builder, &queue_sck_builder); log_pipe_set_options((LogPipe *) self->writer, &self->super.super.super.options); log_writer_set_options(self->writer, s, &self->writer_options, self->super.super.id, writer_sck_builder); gint stats_level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : self->writer_options.stats_level; LogQueue *queue = log_dest_driver_acquire_queue(&self->super, afprogram_dd_format_queue_persist_name(self), stats_level, driver_sck_builder, queue_sck_builder); log_writer_set_queue(self->writer, queue); stats_cluster_key_builder_free(queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); if (!log_pipe_init((LogPipe *) self->writer)) { log_pipe_unref((LogPipe *) self->writer); return FALSE; } log_pipe_append(&self->super.super.super, (LogPipe *) self->writer); if (restore_successful) { LogProtoClient *proto = log_writer_steal_proto(self->writer); log_writer_reopen(self->writer, proto); return TRUE; } return afprogram_dd_reopen(self); } static inline void afprogram_dd_store_reload_store_item(AFProgramDestDriver *self, GlobalConfig *cfg) { AFProgramReloadStoreItem *reload_info = g_new0(AFProgramReloadStoreItem, 1); reload_info->pid = self->process_info.pid; reload_info->writer = self->writer; cfg_persist_config_add(cfg, afprogram_dd_format_persist_name((const LogPipe *)self), reload_info, afprogram_reload_store_item_destroy_notify); } static gboolean afprogram_dd_deinit(LogPipe *s) { AFProgramDestDriver *self = (AFProgramDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (self->writer) log_pipe_deinit((LogPipe *) self->writer); child_manager_unregister(self->process_info.pid); if (self->keep_alive) { afprogram_dd_store_reload_store_item(self, cfg); } else { afprogram_dd_kill_child(self); if (self->writer) log_pipe_unref((LogPipe *) self->writer); } if (self->writer) { self->writer = NULL; } return log_dest_driver_deinit_method(s); } static void afprogram_dd_free(LogPipe *s) { AFProgramDestDriver *self = (AFProgramDestDriver *) s; log_pipe_unref((LogPipe *) self->writer); g_string_free(self->process_info.cmdline, TRUE); log_writer_options_destroy(&self->writer_options); log_dest_driver_free(s); } static void afprogram_dd_notify(LogPipe *s, gint notify_code, gpointer user_data) { AFProgramDestDriver *self = (AFProgramDestDriver *) s; switch (notify_code) { case NC_CLOSE: afprogram_dd_reopen(self); break; case NC_WRITE_ERROR: /* We let this fall through, to be handled by the child manager. We do this to have access to the exit status, and which we use to decide whether to restart immediately, or stop the destination. */ break; default: break; } } LogDriver * afprogram_dd_new(gchar *cmdline, GlobalConfig *cfg) { AFProgramDestDriver *self = g_new0(AFProgramDestDriver, 1); log_dest_driver_init_instance(&self->super, cfg); self->super.super.super.init = afprogram_dd_init; self->super.super.super.deinit = afprogram_dd_deinit; self->super.super.super.free_fn = afprogram_dd_free; self->super.super.super.notify = afprogram_dd_notify; self->super.super.super.generate_persist_name = afprogram_dd_format_persist_name; self->process_info.cmdline = g_string_new(cmdline); self->process_info.pid = -1; afprogram_set_inherit_environment(&self->process_info, TRUE); log_writer_options_defaults(&self->writer_options); self->writer_options.stats_level = STATS_LEVEL0; self->writer_options.stats_source = stats_register_type("program"); return &self->super.super; } void afprogram_dd_set_keep_alive(AFProgramDestDriver *self, gboolean keep_alive) { self->keep_alive = keep_alive; } void afprogram_set_inherit_environment(AFProgramProcessInfo *self, gboolean inherit_environment) { self->inherit_environment = inherit_environment; } syslog-ng-syslog-ng-4.4.0/modules/afprog/afprog.h000066400000000000000000000035601450431004300217340ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFPROG_H_INCLUDED #define AFPROG_H_INCLUDED #include "driver.h" #include "logwriter.h" #include "logreader.h" typedef struct _AFProgramProcessInfo { pid_t pid; GString *cmdline; gboolean inherit_environment; } AFProgramProcessInfo; typedef struct _AFProgramSourceDriver { LogSrcDriver super; AFProgramProcessInfo process_info; LogReader *reader; LogReaderOptions reader_options; } AFProgramSourceDriver; typedef struct _AFProgramDestDriver { LogDestDriver super; AFProgramProcessInfo process_info; LogWriter *writer; gboolean keep_alive; LogWriterOptions writer_options; } AFProgramDestDriver; LogDriver *afprogram_sd_new(gchar *cmdline, GlobalConfig *cfg); LogDriver *afprogram_dd_new(gchar *cmdline, GlobalConfig *cfg); void afprogram_dd_set_keep_alive(AFProgramDestDriver *self, gboolean keep_alive); void afprogram_set_inherit_environment(AFProgramProcessInfo *self, gboolean inherit_environment); #endif syslog-ng-syslog-ng-4.4.0/modules/afsmtp/000077500000000000000000000000001450431004300203155ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsmtp/CMakeLists.txt000066400000000000000000000006471450431004300230640ustar00rootroot00000000000000if (NOT DEFINED ENABLE_AFSMTP OR ENABLE_AFSMTP) find_package(ESMTP) endif() module_switch(ENABLE_AFSMTP "Enable SMTP destination" ESMTP_FOUND) if (NOT ENABLE_AFSMTP) return() endif() set(AFSMTP_SOURCES afsmtp.c afsmtp.h afsmtp-parser.c afsmtp-parser.h ) add_module( TARGET afsmtp GRAMMAR afsmtp-grammar INCLUDES ${ESMTP_INCLUDE_DIR} DEPENDS ${ESMTP_LIBRARIES} SOURCES ${AFSMTP_SOURCES} ) syslog-ng-syslog-ng-4.4.0/modules/afsmtp/Makefile.am000066400000000000000000000020031450431004300223440ustar00rootroot00000000000000if ENABLE_SMTP module_LTLIBRARIES += modules/afsmtp/libafsmtp.la modules_afsmtp_libafsmtp_la_CFLAGS = \ $(AM_CFLAGS) \ $(LIBESMTP_CFLAGS) \ -I$(top_srcdir)/modules/afsmtp \ -I$(top_builddir)/modules/afsmtp modules_afsmtp_libafsmtp_la_SOURCES = \ modules/afsmtp/afsmtp-grammar.y \ modules/afsmtp/afsmtp.c \ modules/afsmtp/afsmtp.h \ modules/afsmtp/afsmtp-parser.c \ modules/afsmtp/afsmtp-parser.h modules_afsmtp_libafsmtp_la_LIBADD = \ $(MODULE_DEPS_LIBS) $(LIBESMTP_LIBS) modules_afsmtp_libafsmtp_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afsmtp_libafsmtp_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) modules/afsmtp modules/afsmtp/ mod-afsmtp mod-smtp: \ modules/afsmtp/libafsmtp.la else modules/afsmtp modules/afsmtp/ mod-afsmtp mod-smtp: endif BUILT_SOURCES += \ modules/afsmtp/afsmtp-grammar.y \ modules/afsmtp/afsmtp-grammar.c \ modules/afsmtp/afsmtp-grammar.h EXTRA_DIST += \ modules/afsmtp/afsmtp-grammar.ym \ modules/afsmtp/CMakeLists.txt .PHONY: modules/afsmtp/ mod-afsmtp mod-smtp syslog-ng-syslog-ng-4.4.0/modules/afsmtp/afsmtp-grammar.ym000066400000000000000000000117411450431004300236060ustar00rootroot00000000000000/* * Copyright (c) 2011-2012 Balabit * Copyright (c) 2011-2012 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "afsmtp-parser.h" } %code { #include "cfg-parser.h" #include "cfg-grammar-internal.h" #include "plugin.h" extern LogDriver *last_driver; } %define api.prefix {afsmtp_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_SMTP %token KW_SUBJECT %token KW_FROM %token KW_TO %token KW_BODY %token KW_HEADER %token KW_CC %token KW_BCC %token KW_SENDER %token KW_REPLY_TO %% start : LL_CONTEXT_DESTINATION KW_SMTP { last_driver = *instance = afsmtp_dd_new(configuration); } '(' _inner_dest_context_push afsmtp_options _inner_dest_context_pop ')' { YYACCEPT; } ; afsmtp_options : afsmtp_option afsmtp_options | ; afsmtp_option : KW_HOST '(' string ')' { afsmtp_dd_set_host(last_driver, $3); free($3); } | KW_PORT '(' positive_integer ')' { afsmtp_dd_set_port(last_driver, $3); } | KW_SUBJECT '(' template_content ')' { afsmtp_dd_set_subject(last_driver, $3); log_template_unref($3); } | KW_BODY '(' template_content ')' { afsmtp_dd_set_body(last_driver, $3); log_template_unref($3); } | KW_HEADER '(' string template_content ')' { afsmtp_dd_add_header(last_driver, $3, $4); free($3); log_template_unref($4); } | KW_FROM '(' template_content ')' { afsmtp_dd_set_from(last_driver, $3, $3); log_template_unref($3); } | KW_FROM '(' template_content template_content ')' { afsmtp_dd_set_from(last_driver, $3, $4); log_template_unref($3); log_template_unref($4); } | KW_SENDER '(' template_content ')' { afsmtp_dd_set_from(last_driver, $3, $3); log_template_unref($3); } | KW_SENDER '(' template_content template_content ')' { afsmtp_dd_set_from(last_driver, $3, $4); log_template_unref($3); log_template_unref($4); } | KW_TO '(' template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_TO, $3, $3); log_template_unref($3); } | KW_TO '(' template_content template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_TO, $3, $4); log_template_unref($3); log_template_unref($4); } | KW_CC '(' template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_CC, $3, $3); log_template_unref($3); } | KW_CC '(' template_content template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_CC, $3, $4); log_template_unref($3); log_template_unref($4); } | KW_BCC '(' template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_BCC, $3, $3); log_template_unref($3); } | KW_BCC '(' template_content template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_BCC, $3, $4); log_template_unref($3); log_template_unref($4); } | KW_REPLY_TO '(' template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_REPLY_TO, $3, $3); log_template_unref($3); } | KW_REPLY_TO '(' template_content template_content ')' { afsmtp_dd_add_rcpt(last_driver, AFSMTP_RCPT_TYPE_REPLY_TO, $3, $4); log_template_unref($3); log_template_unref($4); } | threaded_dest_driver_general_option | { last_template_options = afsmtp_dd_get_template_options(last_driver); } template_option ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afsmtp/afsmtp-parser.c000066400000000000000000000035401450431004300232470ustar00rootroot00000000000000/* * Copyright (c) 2011-2014 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsmtp.h" #include "cfg-parser.h" #include "afsmtp-grammar.h" extern int afsmtp_debug; int afsmtp_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afsmtp_keywords[] = { { "smtp", KW_SMTP }, { "host", KW_HOST }, { "port", KW_PORT }, { "subject", KW_SUBJECT }, { "from", KW_FROM }, { "to", KW_TO }, { "cc", KW_CC }, { "bcc", KW_BCC }, { "reply_to", KW_REPLY_TO }, { "sender", KW_SENDER }, { "body", KW_BODY }, { "header", KW_HEADER }, { NULL } }; CfgParser afsmtp_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afsmtp_debug, #endif .name = "afsmtp", .keywords = afsmtp_keywords, .parse = (int (*)(CfgLexer *lexer, gpointer *instance, gpointer)) afsmtp_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afsmtp_, AFSMTP_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afsmtp/afsmtp-parser.h000066400000000000000000000022471450431004300232570ustar00rootroot00000000000000/* * Copyright (c) 2011-2012 Balabit * Copyright (c) 2011-2012 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSMTP_PARSER_H_INCLUDED #define AFSMTP_PARSER_H_INCLUDED #include "cfg-parser.h" #include "afsmtp.h" extern CfgParser afsmtp_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afsmtp_, AFSMTP_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afsmtp/afsmtp.c000066400000000000000000000456331450431004300217660ustar00rootroot00000000000000/* * Copyright (c) 2011-2014 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsmtp.h" #include "afsmtp-parser.h" #include "plugin.h" #include "messages.h" #include "stats/stats-registry.h" #include "logqueue.h" #include "plugin-types.h" #include "logthrdest/logthrdestdrv.h" #include #include typedef struct { gchar *name; LogTemplate *template_obj; } AFSMTPHeader; typedef struct { gchar *phrase; LogTemplate *template_obj; afsmtp_rcpt_type_t type; } AFSMTPRecipient; typedef struct { LogThreadedDestDriver super; /* Shared between main/writer; only read by the writer, never written */ gchar *host; gint port; AFSMTPRecipient *mail_from; GList *rcpt_tos; GList *headers; LogTemplate *subject_template; LogTemplate *body_template; /* Writer-only stuff */ GString *str; LogTemplateOptions template_options; } AFSMTPDriver; typedef struct { gboolean success; AFSMTPDriver *driver; } LogRcptStatusData; static gchar * afsmtp_wash_string (gchar *str) { gint i; for (i = 0; i < strlen (str); i++) if (str[i] == '\n' || str[i] == '\r') str[i] = ' '; return str; } LogTemplateOptions * afsmtp_dd_get_template_options(LogDriver *d) { AFSMTPDriver *self = (AFSMTPDriver *)d; return &self->template_options; } /* * Configuration */ void afsmtp_dd_set_host(LogDriver *d, const gchar *host) { AFSMTPDriver *self = (AFSMTPDriver *)d; g_free(self->host); self->host = g_strdup (host); } void afsmtp_dd_set_port(LogDriver *d, gint port) { AFSMTPDriver *self = (AFSMTPDriver *)d; self->port = (int)port; } void afsmtp_dd_set_subject(LogDriver *d, LogTemplate *subject) { AFSMTPDriver *self = (AFSMTPDriver *)d; log_template_unref(self->subject_template); self->subject_template = log_template_ref(subject); } void afsmtp_dd_set_from(LogDriver *d, LogTemplate *phrase, LogTemplate *mbox) { AFSMTPDriver *self = (AFSMTPDriver *)d; g_free(self->mail_from->phrase); self->mail_from->phrase = afsmtp_wash_string(g_strdup(phrase->template_str)); log_template_unref(self->mail_from->template_obj); self->mail_from->template_obj = log_template_ref(mbox); } void afsmtp_dd_add_rcpt(LogDriver *d, afsmtp_rcpt_type_t type, LogTemplate *phrase, LogTemplate *mbox) { AFSMTPDriver *self = (AFSMTPDriver *)d; AFSMTPRecipient *rcpt; rcpt = g_new0(AFSMTPRecipient, 1); rcpt->phrase = afsmtp_wash_string(g_strdup(phrase->template_str)); log_template_unref(rcpt->template_obj); rcpt->template_obj = log_template_ref(mbox); rcpt->type = type; self->rcpt_tos = g_list_append(self->rcpt_tos, rcpt); } void afsmtp_dd_set_body(LogDriver *d, LogTemplate *body) { AFSMTPDriver *self = (AFSMTPDriver *)d; log_template_unref(self->body_template); self->body_template = log_template_ref(body); } gboolean afsmtp_dd_add_header(LogDriver *d, const gchar *header, LogTemplate *value) { AFSMTPDriver *self = (AFSMTPDriver *)d; AFSMTPHeader *h; if (!g_ascii_strcasecmp(header, "to") || !g_ascii_strcasecmp(header, "cc") || !g_ascii_strcasecmp(header, "bcc") || !g_ascii_strcasecmp(header, "from") || !g_ascii_strcasecmp(header, "sender") || !g_ascii_strcasecmp(header, "reply-to") || !g_ascii_strcasecmp(header, "date")) return FALSE; h = g_new0(AFSMTPHeader, 1); h->name = g_strdup(header); log_template_unref(h->template_obj); h->template_obj = log_template_ref(value); self->headers = g_list_append(self->headers, h); return TRUE; } /* * Utilities */ void ignore_sigpipe (void) { struct sigaction sa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGPIPE, &sa, NULL); } static const gchar * afsmtp_dd_format_stats_key(LogThreadedDestDriver *d, StatsClusterKeyBuilder *kb) { AFSMTPDriver *self = (AFSMTPDriver *)d; stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "smtp")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", self->host)); gchar num[64]; g_snprintf(num, sizeof(num), "%u", self->port); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("port", num)); return NULL; } static const gchar * afsmtp_dd_format_persist_name(const LogPipe *s) { const AFSMTPDriver *self = (const AFSMTPDriver *)s; static gchar persist_name[1024]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "smtp.%s", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "smtp(%s,%u)", self->host, self->port); return persist_name; } /* * Worker thread */ static void _smtp_message_add_recipient_header(smtp_message_t self, AFSMTPRecipient *rcpt, AFSMTPDriver *driver) { const gchar *hdr; switch (rcpt->type) { case AFSMTP_RCPT_TYPE_TO: hdr = "To"; break; case AFSMTP_RCPT_TYPE_CC: hdr = "Cc"; break; case AFSMTP_RCPT_TYPE_REPLY_TO: hdr = "Reply-To"; break; default: return; } smtp_set_header(self, hdr, rcpt->phrase, afsmtp_wash_string (driver->str->str)); smtp_set_header_option(self, hdr, Hdr_OVERRIDE, 1); } static void _smtp_message_add_recipient_from_template(smtp_message_t self, AFSMTPDriver *driver, LogTemplate *template_obj, LogMessage *msg) { LogTemplateEvalOptions options = {&driver->template_options, LTZ_SEND, driver->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(template_obj, msg, &options, driver->str); smtp_add_recipient(self, afsmtp_wash_string (driver->str->str)); } static void afsmtp_dd_msg_add_recipient(AFSMTPRecipient *rcpt, gpointer user_data) { AFSMTPDriver *self = ((gpointer *)user_data)[0]; LogMessage *msg = ((gpointer *)user_data)[1]; smtp_message_t message = ((gpointer *)user_data)[2]; _smtp_message_add_recipient_from_template(message, self, rcpt->template_obj, msg); _smtp_message_add_recipient_header(message, rcpt, self); } static void afsmtp_dd_msg_add_header(AFSMTPHeader *hdr, gpointer user_data) { AFSMTPDriver *self = ((gpointer *)user_data)[0]; LogMessage *msg = ((gpointer *)user_data)[1]; smtp_message_t message = ((gpointer *)user_data)[2]; LogTemplateEvalOptions options = {&self->template_options, LTZ_LOCAL, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(hdr->template_obj, msg, &options, self->str); smtp_set_header(message, hdr->name, afsmtp_wash_string (self->str->str), NULL); smtp_set_header_option(message, hdr->name, Hdr_OVERRIDE, 1); } static void afsmtp_dd_log_rcpt_status(smtp_recipient_t rcpt, const char *mailbox, gpointer user_data) { const smtp_status_t *status; LogRcptStatusData *status_data = (LogRcptStatusData *)user_data; status = smtp_recipient_status(rcpt); if (status->code != 250) { status_data->success = FALSE; msg_error("SMTP recipient result", evt_tag_str("driver", status_data->driver->super.super.super.id), evt_tag_str("recipient", mailbox), evt_tag_int("code", status->code), evt_tag_str("text", status->text)); } else { msg_debug("SMTP recipient result", evt_tag_str("driver", status_data->driver->super.super.super.id), evt_tag_str("recipient", mailbox), evt_tag_int("code", status->code), evt_tag_str("text", status->text)); } } static void afsmtp_dd_cb_event(smtp_session_t session, int event, AFSMTPDriver *self) { switch (event) { case SMTP_EV_CONNECT: msg_verbose("Connected to SMTP server", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("host", self->host), evt_tag_int("port", self->port)); break; case SMTP_EV_MAILSTATUS: case SMTP_EV_RCPTSTATUS: case SMTP_EV_MESSAGEDATA: case SMTP_EV_MESSAGESENT: /* Ignore */ break; case SMTP_EV_DISCONNECT: msg_verbose("Disconnected from SMTP server", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("host", self->host), evt_tag_int("port", self->port)); break; default: msg_verbose("Unknown SMTP event", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("event_id", event)); break; } } static void afsmtp_dd_cb_monitor(const gchar *buf, gint buflen, gint writing, AFSMTPDriver *self) { switch (writing) { case SMTP_CB_READING: msg_debug ("SMTP Session: SERVER", evt_tag_str("driver", self->super.super.super.id), evt_tag_mem("message", buf, buflen)); break; case SMTP_CB_WRITING: msg_debug("SMTP Session: CLIENT", evt_tag_str("driver", self->super.super.super.id), evt_tag_mem("message", buf, buflen)); break; case SMTP_CB_HEADERS: msg_debug("SMTP Session: HEADERS", evt_tag_str("driver", self->super.super.super.id), evt_tag_mem("data", buf, buflen)); break; } } static smtp_session_t __build_session(AFSMTPDriver *self, LogMessage *msg) { smtp_session_t session; session = smtp_create_session(); g_string_printf(self->str, "%s:%d", self->host, self->port); smtp_set_server(session, self->str->str); smtp_set_eventcb(session, (smtp_eventcb_t) afsmtp_dd_cb_event, (void *) self); smtp_set_monitorcb(session, (smtp_monitorcb_t) afsmtp_dd_cb_monitor, (void *) self, 1); return session; } static smtp_message_t __build_message(AFSMTPDriver *self, LogMessage *msg, smtp_session_t session) { smtp_message_t message; gpointer args[] = { self, NULL, NULL }; message = smtp_add_message(session); LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(self->mail_from->template_obj, msg, &options, self->str); smtp_set_reverse_path(message, afsmtp_wash_string(self->str->str)); /* Defaults */ smtp_set_header(message, "To", NULL, NULL); smtp_set_header(message, "From", NULL, NULL); LogTemplateEvalOptions eval_options = {&self->template_options, LTZ_SEND, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(self->subject_template, msg, &eval_options, self->str); smtp_set_header(message, "Subject", afsmtp_wash_string(self->str->str)); smtp_set_header_option(message, "Subject", Hdr_OVERRIDE, 1); /* Add recipients */ args[1] = msg; args[2] = message; g_list_foreach(self->rcpt_tos, (GFunc) afsmtp_dd_msg_add_recipient, args); /* Add custom header (overrides anything set before, or in the body). */ g_list_foreach(self->headers, (GFunc) afsmtp_dd_msg_add_header, args); /* Set the body. * * We add a header to the body, otherwise libesmtp will not * recognise headers, and will append them to the end of the body. */ g_string_assign(self->str, "X-Mailer: syslog-ng " SYSLOG_NG_VERSION "\r\n\r\n"); log_template_append_format(self->body_template, msg, &eval_options, self->str); smtp_set_message_str(message, self->str->str); return message; } static gboolean __check_transfer_status(AFSMTPDriver *self, smtp_message_t message) { LogRcptStatusData status_data; const smtp_status_t *status = smtp_message_transfer_status(message); status_data.success = TRUE; status_data.driver = self; if (status->code != 250) { status_data.success = FALSE; msg_error("Failed to send message", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("code", status->code), evt_tag_str("text", status->text)); } else { msg_debug("SMTP result", evt_tag_str("driver", self->super.super.super.id), evt_tag_int("code", status->code), evt_tag_str("text", status->text)); smtp_enumerate_recipients(message, afsmtp_dd_log_rcpt_status, &status_data); } return status_data.success; } static gboolean __send_message(AFSMTPDriver *self, smtp_session_t session) { gboolean success = smtp_start_session(session); if (!(success)) { gchar error[1024] = {0}; smtp_strerror(smtp_errno(), error, sizeof (error) - 1); msg_error("SMTP server error, suspending", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("error", error), evt_tag_int("time_reopen", self->super.time_reopen)); success = FALSE; } return success; } static LogThreadedResult afsmtp_worker_insert(LogThreadedDestDriver *s, LogMessage *msg) { AFSMTPDriver *self = (AFSMTPDriver *)s; if (msg->flags & LF_MARK) { msg_debug("Mark messages are dropped by SMTP destination", evt_tag_str("driver", self->super.super.super.id)); return LTR_SUCCESS; } smtp_session_t session = __build_session(self, msg); smtp_message_t message = __build_message(self, msg, session); gboolean message_sent = __send_message(self, session); gboolean success = message_sent && __check_transfer_status(self, message); smtp_destroy_session(session); if (!success) { if (!message_sent) return LTR_NOT_CONNECTED; else return LTR_ERROR; } return LTR_SUCCESS; } static void afsmtp_worker_thread_init(LogThreadedDestDriver *d) { AFSMTPDriver *self = (AFSMTPDriver *)d; self->str = g_string_sized_new(1024); ignore_sigpipe(); } static void afsmtp_worker_thread_deinit(LogThreadedDestDriver *d) { AFSMTPDriver *self = (AFSMTPDriver *)d; g_string_free(self->str, TRUE); } /* * Main thread */ static gboolean __check_rcpt_tos(AFSMTPDriver *self) { gboolean result = FALSE; GList *l = self->rcpt_tos; while (l) { AFSMTPRecipient *rcpt = (AFSMTPRecipient *)l->data; gboolean rcpt_type_accepted = rcpt->type == AFSMTP_RCPT_TYPE_BCC || rcpt->type == AFSMTP_RCPT_TYPE_CC || rcpt->type == AFSMTP_RCPT_TYPE_TO; if (rcpt->template_obj && rcpt_type_accepted) { result = TRUE; break; } l = l->next; } return result; } static gboolean __check_required_options(AFSMTPDriver *self) { if (!self->mail_from->template_obj) { msg_error("Error: from or sender option is required", evt_tag_str("driver", self->super.super.super.id)); return FALSE; } if (!__check_rcpt_tos(self)) { msg_error("Error: to or bcc option is required", evt_tag_str("driver", self->super.super.super.id)); return FALSE; } if (!self->subject_template) { msg_error("Error: subject is required option", evt_tag_str("driver", self->super.super.super.id)); return FALSE; } if (!self->body_template) { msg_error("Error: body is required option", evt_tag_str("driver", self->super.super.super.id)); return FALSE; } return TRUE; } static gboolean afsmtp_dd_init(LogPipe *s) { AFSMTPDriver *self = (AFSMTPDriver *)s; GlobalConfig *cfg = log_pipe_get_config(s); msg_verbose("Initializing SMTP destination", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("host", self->host), evt_tag_int("port", self->port)); if (!__check_required_options(self)) return FALSE; if (!log_threaded_dest_driver_init_method(s)) return FALSE; log_template_options_init(&self->template_options, cfg); return TRUE; } static void afsmtp_dd_free(LogPipe *d) { AFSMTPDriver *self = (AFSMTPDriver *)d; GList *l; g_free(self->host); g_free(self->mail_from->phrase); log_template_unref(self->mail_from->template_obj); g_free(self->mail_from); log_template_unref(self->subject_template); log_template_unref(self->body_template); l = self->rcpt_tos; while (l) { AFSMTPRecipient *rcpt = (AFSMTPRecipient *)l->data; g_free(rcpt->phrase); log_template_unref(rcpt->template_obj); g_free(rcpt); l = g_list_delete_link(l, l); } l = self->headers; while (l) { AFSMTPHeader *hdr = (AFSMTPHeader *)l->data; g_free(hdr->name); log_template_unref(hdr->template_obj); g_free(hdr); l = g_list_delete_link(l, l); } log_template_options_destroy(&self->template_options); log_threaded_dest_driver_free(d); } /* * Plugin glue. */ LogDriver * afsmtp_dd_new(GlobalConfig *cfg) { AFSMTPDriver *self = g_new0(AFSMTPDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = afsmtp_dd_init; self->super.super.super.super.free_fn = afsmtp_dd_free; self->super.super.super.super.generate_persist_name = afsmtp_dd_format_persist_name; self->super.worker.thread_init = afsmtp_worker_thread_init; self->super.worker.thread_deinit = afsmtp_worker_thread_deinit; self->super.worker.insert = afsmtp_worker_insert; self->super.format_stats_key = afsmtp_dd_format_stats_key; self->super.stats_source = stats_register_type("smtp"); afsmtp_dd_set_host((LogDriver *)self, "127.0.0.1"); afsmtp_dd_set_port((LogDriver *)self, 25); self->mail_from = g_new0(AFSMTPRecipient, 1); log_template_options_defaults(&self->template_options); return (LogDriver *)self; } extern CfgParser afsmtp_dd_parser; static Plugin afsmtp_plugin = { .type = LL_CONTEXT_DESTINATION, .name = "smtp", .parser = &afsmtp_parser, }; gboolean afsmtp_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, &afsmtp_plugin, 1); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afsmtp", .version = SYSLOG_NG_VERSION, .description = "The afsmtp module provides SMTP destination support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = &afsmtp_plugin, .plugins_len = 1, }; syslog-ng-syslog-ng-4.4.0/modules/afsmtp/afsmtp.h000066400000000000000000000035661450431004300217720ustar00rootroot00000000000000/* * Copyright (c) 2011-2014 Balabit * Copyright (c) 2011-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSMTP_H_INCLUDED #define AFSMTP_H_INCLUDED #include "driver.h" typedef enum { AFSMTP_RCPT_TYPE_NONE, AFSMTP_RCPT_TYPE_TO, AFSMTP_RCPT_TYPE_CC, AFSMTP_RCPT_TYPE_BCC, AFSMTP_RCPT_TYPE_REPLY_TO, AFSMTP_RCPT_TYPE_SENDER, } afsmtp_rcpt_type_t; LogDriver *afsmtp_dd_new(GlobalConfig *cfg); void afsmtp_dd_set_host(LogDriver *d, const gchar *host); void afsmtp_dd_set_port(LogDriver *d, gint port); void afsmtp_dd_set_subject(LogDriver *d, LogTemplate *subject); void afsmtp_dd_set_from(LogDriver *d, LogTemplate *phrase, LogTemplate *mbox); void afsmtp_dd_add_rcpt(LogDriver *d, afsmtp_rcpt_type_t type, LogTemplate *phrase, LogTemplate *mbox); void afsmtp_dd_set_body(LogDriver *d, LogTemplate *body); gboolean afsmtp_dd_add_header(LogDriver *d, const gchar *header, LogTemplate *value); LogTemplateOptions *afsmtp_dd_get_template_options(LogDriver *d); #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/000077500000000000000000000000001450431004300203075ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsnmp/CMakeLists.txt000066400000000000000000000015001450431004300230430ustar00rootroot00000000000000if (NOT DEFINED ENABLE_AFSNMP OR ENABLE_AFSNMP) find_package(NETSNMP) endif() module_switch(ENABLE_AFSNMP "Enable afsnmp module" NETSNMP_FOUND) if (NOT ENABLE_AFSNMP) return () endif() if (NOT NETSNMP_FOUND) message(FATAL_ERROR "SNMP module enabled, but Net-SNMP not found") endif() set(afsnmp_SOURCES "afsnmpdest.h" "afsnmpdest.c" "afsnmp-parser.h" "afsnmp-parser.c" "afsnmp-plugin.c" "snmptrapd-header-parser.h" "snmptrapd-header-parser.c" "snmptrapd-nv-context.h" "snmptrapd-parser.h" "snmptrapd-parser.c" "varbindlist-scanner.h" "varbindlist-scanner.c" ) add_module( TARGET afsnmp GRAMMAR afsnmp-grammar DEPENDS ${NETSNMP_LIBS} SOURCES ${afsnmp_SOURCES} ) set_target_properties(afsnmp PROPERTIES COMPILE_FLAGS ${NETSNMP_CFLAGS}) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/afsnmp/Makefile.am000066400000000000000000000024731450431004300223510ustar00rootroot00000000000000if ENABLE_AFSNMP module_LTLIBRARIES += modules/afsnmp/libafsnmp.la modules_afsnmp_libafsnmp_la_SOURCES = \ modules/afsnmp/afsnmp-grammar.y \ modules/afsnmp/afsnmpdest.c \ modules/afsnmp/afsnmp-plugin.c \ modules/afsnmp/afsnmpdest.h \ modules/afsnmp/afsnmp-parser.c \ modules/afsnmp/afsnmp-parser.h \ modules/afsnmp/snmptrapd-header-parser.h \ modules/afsnmp/snmptrapd-header-parser.c \ modules/afsnmp/snmptrapd-nv-context.h \ modules/afsnmp/snmptrapd-parser.h \ modules/afsnmp/snmptrapd-parser.c \ modules/afsnmp/varbindlist-scanner.h \ modules/afsnmp/varbindlist-scanner.c modules_afsnmp_libafsnmp_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(NETSNMP_CFLAGS) \ -I$(top_srcdir)/modules/afsnmp \ -I$(top_builddir)/modules/afsnmp modules_afsnmp_libafsnmp_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_afsnmp_libafsnmp_la_LDFLAGS = \ $(MODULE_LDFLAGS) \ $(NETSNMP_LIBS) modules_afsnmp_libafsnmp_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) modules/afsnmp mod-afsnmp: modules/afsnmp/libafsnmp.la else modules/afsnmp mod-afsnmp: endif BUILT_SOURCES += \ modules/afsnmp/afsnmp-grammar.y \ modules/afsnmp/afsnmp-grammar.c \ modules/afsnmp/afsnmp-grammar.h EXTRA_DIST += \ modules/afsnmp/afsnmp-grammar.ym \ modules/afsnmp/CMakeLists.txt .PHONY: modules/afsnmp mod-afsnmp include modules/afsnmp/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmp-grammar.ym000066400000000000000000000143501450431004300235710ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "afsnmp-parser.h" } %code { #include #include "cfg-parser.h" #include "cfg-grammar-internal.h" #include "syslog-names.h" #include "messages.h" #include "plugin.h" #include "afsnmpdest.h" #include "snmptrapd-parser.h" } %define api.prefix {afsnmp_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {void **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_SNMPDEST %token KW_VERSION %token KW_SNMP_OBJ %token KW_TRAP_OBJ %token KW_COMMUNITY %token KW_ENGINE_ID %token KW_AUTH_USERNAME %token KW_AUTH_ALGORITHM %token KW_AUTH_PASSWORD %token KW_ENC_ALGORITHM %token KW_ENC_PASSWORD %token KW_TRANSPORT %token KW_SNMPTRAPD_PARSER %token KW_PREFIX %token KW_SET_MESSAGE_MACRO %type dest_snmpdest %type dest_snmpdest_params %type dest_snmpdest_option %type parser_expr_snmptrapd %% start : LL_CONTEXT_DESTINATION dest_snmpdest { YYACCEPT; } | LL_CONTEXT_PARSER parser_expr_snmptrapd { YYACCEPT; } ; dest_snmpdest : KW_SNMPDEST '(' _inner_dest_context_push dest_snmpdest_params _inner_dest_context_pop ')' ; dest_snmpdest_params : { last_driver= *instance = snmpdest_dd_new(configuration); } dest_snmpdest_options { gchar err_msg[256]; $$ = last_driver; CHECK_ERROR(snmpdest_check_required_params(last_driver, err_msg), @1, "SNMP: config error: %s", err_msg); } ; dest_snmpdest_options : dest_snmpdest_option dest_snmpdest_options | ; dest_snmpdest_option : KW_VERSION '(' string ')' { CHECK_ERROR(!strcmp($3, s_v2c) || !strcmp($3, s_v3), @1, "SNMP: invalid version: %s", $3); snmpdest_dd_set_version(last_driver, $3); free($3); } | KW_HOST '(' string ')' { snmpdest_dd_set_host(last_driver, $3); free($3); } | KW_PORT '(' positive_integer ')' { snmpdest_dd_set_port(last_driver, $3); } | KW_SNMP_OBJ '(' string string string ')' { CHECK_ERROR(snmpdest_dd_set_snmp_obj(last_driver, configuration, $3, $4, $5), @1, "SNMP: error set snmp object"); free($3); free($4); free($5); } | KW_TRAP_OBJ '(' string string string ')' { snmpdest_dd_set_trap_obj(last_driver, configuration, $3, $4, $5); free($3); free($4); free($5); } | KW_COMMUNITY '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v2c)) msg_warning("WARNING: SNMP: the 'community' is a v2c option"); snmpdest_dd_set_community(last_driver, $3); free($3); } | KW_ENGINE_ID '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) { msg_warning("WARNING: SNMP: the 'engine_id' is a v3 option"); } else { CHECK_ERROR(snmpdest_dd_set_engine_id(last_driver, $3), @1, "SNMP: engine id (%s) shall be a hexadecimal number with a length between 5 and 32 (plus the 0x prefix), see RFC5343 for further details", $3); free($3); } } | KW_AUTH_USERNAME '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) msg_warning("WARNING: SNMP: the 'auth_username' is a v3 option"); snmpdest_dd_set_auth_username(last_driver, $3); free($3); } | KW_AUTH_ALGORITHM '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) msg_warning("WARNING: SNMP: the 'auth_algorithm' is a v3 option"); CHECK_ERROR(snmpdest_dd_check_auth_algorithm($3), @1, "SNMP: wrong auth algorithm: %s", $3); snmpdest_dd_set_auth_algorithm(last_driver, $3); free($3); } | KW_AUTH_PASSWORD '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) msg_warning("WARNING: SNMP: the 'auth_password' is a v3 option"); snmpdest_dd_set_auth_password(last_driver, $3); free($3); } | KW_ENC_ALGORITHM '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) msg_warning("WARNING: SNMP: the 'enc_algorithm' is a v3 option"); CHECK_ERROR(snmpdest_dd_check_enc_algorithm($3), @1, "SNMP: wrong enc algorithm: %s", $3); snmpdest_dd_set_enc_algorithm(last_driver, $3); free($3); } | KW_ENC_PASSWORD '(' string ')' { if (strcmp(snmpdest_dd_get_version(last_driver), s_v3)) msg_warning("WARNING: SNMP: the 'enc_password' is a v3 option"); snmpdest_dd_set_enc_password(last_driver, $3); free($3); } | KW_LOCAL_TIME_ZONE '(' string ')' { snmpdest_dd_set_time_zone(last_driver, $3); free($3); } | dest_driver_option ; parser_expr_snmptrapd : KW_SNMPTRAPD_PARSER '(' { last_parser = *instance = (LogParser *) snmptrapd_parser_new(configuration); } snmptrapd_parser_options ')' { $$ = last_parser; } ; snmptrapd_parser_options : snmptrapd_parser_option snmptrapd_parser_options | ; snmptrapd_parser_option : KW_PREFIX '(' string ')' { snmptrapd_parser_set_prefix(last_parser, $3); free($3); } | KW_SET_MESSAGE_MACRO '(' yesno ')' { snmptrapd_parser_set_set_message_macro(last_parser, $3); } | parser_opt ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmp-parser.c000066400000000000000000000042741450431004300232400ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsnmpdest.h" #include "cfg-parser.h" #include "afsnmp-grammar.h" #include "afsnmp-parser.h" int afsnmp_parse(CfgLexer *lexer, void **instance, gpointer arg); static CfgLexerKeyword afsnmp_keywords[] = { { "snmp", KW_SNMPDEST }, { "version", KW_VERSION }, { "host", KW_HOST }, { "port", KW_PORT }, { "snmp_obj", KW_SNMP_OBJ }, { "trap_obj", KW_TRAP_OBJ }, { "community", KW_COMMUNITY }, { "engine_id", KW_ENGINE_ID }, { "auth_username", KW_AUTH_USERNAME }, { "auth_algorithm", KW_AUTH_ALGORITHM }, { "auth_password", KW_AUTH_PASSWORD }, { "enc_algorithm", KW_ENC_ALGORITHM }, { "enc_password", KW_ENC_PASSWORD }, { "transport", KW_TRANSPORT }, { "time_zone", KW_LOCAL_TIME_ZONE }, { "snmptrapd_parser", KW_SNMPTRAPD_PARSER }, { "prefix", KW_PREFIX }, { "set_message_macro", KW_SET_MESSAGE_MACRO }, { NULL } }; CfgParser afsnmp_parser = { .name = "afsnmp", .keywords = afsnmp_keywords, .parse = (int (*)(CfgLexer *lexer, gpointer *instance, gpointer)) afsnmp_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afsnmp_, AFSNMP_, void **) syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmp-parser.h000066400000000000000000000022671450431004300232450ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSNMP_PARSER_H_INCLUDED #define AFSNMP_PARSER_H_INCLUDED #include "cfg-parser.h" #include "cfg-lexer.h" #include "afsnmpdest.h" extern CfgParser afsnmp_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afsnmp_, AFSNMP_, void **) #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmp-plugin.c000066400000000000000000000033411450431004300232340ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afsnmp_parser; static Plugin afsnmp_plugins[] = { { .type = LL_CONTEXT_DESTINATION, .name = "snmp", .parser = &afsnmp_parser, }, { .type = LL_CONTEXT_PARSER, .name = "snmptrapd-parser", .parser = &afsnmp_parser, }, }; gboolean afsnmp_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afsnmp_plugins, G_N_ELEMENTS(afsnmp_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afsnmp", .version = SYSLOG_NG_VERSION, .description = "The snmp module provides SNMP support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afsnmp_plugins, .plugins_len = G_N_ELEMENTS(afsnmp_plugins) }; syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmpdest.c000066400000000000000000000523631450431004300226300ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include /* undef the PACKAGE_... symbols (from net-snmp) in order to avoid redefinition warnings */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #include "syslog-ng.h" #include "plugin.h" #include "cfg-parser.h" #include "plugin-types.h" #include "messages.h" #include "misc.h" #include "stats/stats.h" #include "logmsg/nvtable.h" #include "logqueue.h" #include "afsnmpdest.h" #include "afsnmp-parser.h" #include "logthrdest/logthrdestdrv.h" const gchar *s_v2c = "v2c"; const gchar *s_v3 = "v3"; const gchar *s_sha = "SHA"; const gchar *s_aes = "AES"; const gchar *s_snmp_name = "syslog-ng"; typedef struct _snmp_obj_type_list { const gchar *type; const gchar type_code; } SnmpObjTypeList; static SnmpObjTypeList snmp_obj_types[] = { { .type = "integer", .type_code = 'i' }, { .type = "timeticks", .type_code = 't' }, { .type = "octetstring", .type_code = 's' }, { .type = "counter32", .type_code = 'c' }, { .type = "ipaddress", .type_code = 'a' }, { .type = "objectid", .type_code = 'o' } }; static gboolean snmp_dd_find_object_type(const gchar *type, gint *type_index) { gint object_types_count = G_N_ELEMENTS(snmp_obj_types); gint index_; /* check the type */ for (index_ = 0; index_ < object_types_count; ++index_) if (!strcasecmp(type, snmp_obj_types[index_].type)) { *type_index = index_; return TRUE; } return FALSE; } static gchar snmp_dd_get_object_type_code(gint type_index) { if (type_index >= 0 && type_index < G_N_ELEMENTS(snmp_obj_types)) return snmp_obj_types[type_index].type_code; else return '?'; } void snmpdest_dd_set_version(LogDriver *d, const gchar *version) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->version); self->version = g_strdup(version); } void snmpdest_dd_set_host(LogDriver *d, const gchar *host) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->host); self->host = g_strdup(host); } void snmpdest_dd_set_port(LogDriver *d, gint port) { SNMPDestDriver *self = (SNMPDestDriver *)d; self->port = (int)port; } static gint snmp_dd_compare_object_ids(gconstpointer a, gconstpointer b) { return strcmp((gchar *) a, (gchar *) b); } gboolean snmpdest_dd_set_snmp_obj(LogDriver *d, GlobalConfig *cfg, const gchar *objectid, const gchar *type, const gchar *value) { SNMPDestDriver *self = (SNMPDestDriver *)d; LogTemplate *template = NULL; gint code; if (snmp_dd_find_object_type(type, &code) == FALSE) { msg_error("SNMP: invalid oid type", evt_tag_str("type", type)); return FALSE; } gchar *s_objectid = "objectid"; /* check the multiple 'objectid' types - only one type='objectid' is allowed */ if (!strcmp(type, s_objectid) && self->snmp_objs) { GList *item = g_list_find_custom(self->snmp_objs, (gconstpointer)s_objectid, snmp_dd_compare_object_ids); if (item != NULL) { msg_error("SNMP: multiple Objectid"); return FALSE; } } /* register the string values */ self->snmp_objs = g_list_append(self->snmp_objs, g_strdup(objectid)); self->snmp_objs = g_list_append(self->snmp_objs, g_strdup(type)); self->snmp_objs = g_list_append(self->snmp_objs, g_strdup(value)); /* register the type code, therefore we won't need to calculate it for each incoming message */ gint *pcode = g_new(gint, 1); *pcode = code; self->snmp_codes = g_list_append(self->snmp_codes, pcode); /* register the template */ template = log_template_new(cfg, NULL); if (log_template_compile(template, value, NULL) == FALSE) { msg_error("SNMP: invalid log template"); log_template_unref(template); return FALSE; } self->snmp_templates = g_list_append(self->snmp_templates, template); return TRUE; } void snmpdest_dd_set_trap_obj(LogDriver *d, GlobalConfig *cfg, const gchar *objectid, const gchar *type, const gchar *value) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->trap_oid); g_free(self->trap_type); g_free(self->trap_value); self->trap_oid = g_strdup(objectid); self->trap_type = g_strdup(type); self->trap_value = g_strdup(value); /* register the snmp trap as a simple snmp_obj */ snmpdest_dd_set_snmp_obj(&self->super.super.super, cfg, self->trap_oid, self->trap_type, self->trap_value); } void snmpdest_dd_set_community(LogDriver *d, const gchar *community) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->community); self->community = g_strdup(community); } static gboolean _has_hexadecimal_prefix(const gchar *s) { return (s[0] == '0') && (s[1] == 'x'); } static gboolean _is_hexadecimal(const gchar *s, gint length) { gint i; for (i = 0; i < length; ++i) { if (!g_ascii_isxdigit(s[i])) { return FALSE; } } return TRUE; } gboolean snmpdest_dd_set_engine_id(LogDriver *d, const gchar *eid) { SNMPDestDriver *self = (SNMPDestDriver *)d; gsize eidlength = strlen(eid); if (eidlength < ENGINE_ID_MIN_LENGTH) return FALSE; if (_has_hexadecimal_prefix(eid)) { eidlength = eidlength -2; eid = eid + 2; } if (eidlength < ENGINE_ID_MIN_LENGTH || eidlength > ENGINE_ID_MAX_LENGTH) return FALSE; if (!_is_hexadecimal(eid, eidlength)) return FALSE; g_free(self->engine_id); self->engine_id = g_strdup(eid); return TRUE; } void snmpdest_dd_set_auth_username(LogDriver *d, const gchar *auth_username) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->auth_username); self->auth_username = g_strdup(auth_username); } void snmpdest_dd_set_auth_algorithm(LogDriver *d, const gchar *auth_algo) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->auth_algorithm); self->auth_algorithm = g_strdup(auth_algo); } void snmpdest_dd_set_auth_password(LogDriver *d, const gchar *auth_pwd) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->auth_password); self->auth_password = g_strdup(auth_pwd); } void snmpdest_dd_set_enc_algorithm(LogDriver *d, const gchar *enc_algo) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->enc_algorithm); self->enc_algorithm = g_strdup(enc_algo); } void snmpdest_dd_set_enc_password(LogDriver *d, const gchar *epwd) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->enc_password); self->enc_password = g_strdup(epwd); } void snmpdest_dd_set_transport(LogDriver *d, const gchar *transport) { SNMPDestDriver *self = (SNMPDestDriver *)d; g_free(self->transport); self->transport = g_strdup(transport); } void snmpdest_dd_set_time_zone(LogDriver *s, const gchar *time_zone) { SNMPDestDriver *self = (SNMPDestDriver *) s; g_free(self->template_options.time_zone[LTZ_LOCAL]); self->template_options.time_zone[LTZ_LOCAL] = g_strdup(time_zone); } int snmp_input(int operation, netsnmp_session *session, int reqid, netsnmp_pdu *pdu, void *magic) { return 1; } /* dummy proc for snmp_parse_args */ static void optProc(int argc, char *const *argv, int opt) { } static void free_session(netsnmp_session *s) { free(s->securityEngineID); free(s->securityName); } static guint parse_oid_tokens(gchar *oid_str, oid *parsed_oids, guint max_oid_number) { if (oid_str[0] == '.') { /* skip the leading '.' in order not to parse an empty first token */ ++oid_str; } /* parse the oid string into oid values */ gchar **oid_tokens = g_strsplit(oid_str, ".", max_oid_number); guint oid_cnt = 0; while (oid_tokens[oid_cnt]) { gint val; if (sscanf(oid_tokens[oid_cnt], "%d", &val) != 1 ) { msg_warning("SNMP: invalid OID token", evt_tag_str("value", oid_tokens[oid_cnt])); } parsed_oids[oid_cnt] = val; oid_cnt += 1; } g_strfreev(oid_tokens); return oid_cnt; } static void sanitize_fs(GString *fs, gint code) { /* check the number format and replace it with zero if necessary */ if (code == 0 || code == 1 || code == 3) { gboolean replace = FALSE; gint i, len = fs->len; if (!len) replace = TRUE; else for (i = 0; i < len && !replace; ++i) if (fs->str[i] < '0' || fs->str[i] > '9') replace = TRUE; if (replace) { msg_warning("SNMP: invalid number replaced with '0'", evt_tag_str("value", fs->str)); g_string_assign(fs, "0"); } } } #define MAX_OIDS 128 static LogThreadedResult snmpdest_worker_insert(LogThreadedDestDriver *s, LogMessage *msg) { SNMPDestDriver *self = (SNMPDestDriver *) s; netsnmp_pdu *pdu; pdu = snmp_pdu_create(SNMP_MSG_TRAP2); if (!pdu) return LTR_ERROR; oid parsed_oids[MAX_OIDS]; guint oid_cnt; GList *snmp_obj = self->snmp_objs; GList *snmp_code = self->snmp_codes; GList *snmp_template = self->snmp_templates; GString *fs = g_string_sized_new(128); LogTemplateEvalOptions options = {&self->template_options, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; /* go through the snmp objects and add them to the message */ while (snmp_obj) { oid_cnt = parse_oid_tokens(snmp_obj->data, parsed_oids, MAX_OIDS); log_template_format(snmp_template->data, msg, &options, fs); gint code = *((gint *)snmp_code->data); sanitize_fs(fs, code); gchar type_code = snmp_dd_get_object_type_code(code); if (snmp_add_var(pdu, parsed_oids, oid_cnt, type_code, fs->str) != 0) { msg_warning("SNMP: error adding variable", evt_tag_str("value", fs->str)); log_msg_unref(msg); g_string_free(fs, TRUE); snmp_free_pdu(pdu); return LTR_ERROR; } snmp_obj = snmp_obj->next->next->next; /* go to the next triplet and the corresponding items */ snmp_code = snmp_code->next; snmp_template = snmp_template->next; } g_string_free(fs, TRUE); gint success = snmp_send(self->ss, pdu); if (success == 0) { msg_error("SNMP: send error", evt_tag_int("code", snmp_errno), evt_tag_str("message", snmp_api_errstring(snmp_errno))); snmp_free_pdu(pdu); return LTR_NOT_CONNECTED; } return LTR_SUCCESS; } static const gchar * snmpdest_dd_format_persist_name(const LogPipe *s) { SNMPDestDriver *self = (SNMPDestDriver *) s; static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "snmpdest(%s,%u)", self->host, self->port); return persist_name; } static const gchar * snmpdest_dd_format_stats_key(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb) { SNMPDestDriver *self = (SNMPDestDriver *)s; stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "snmpdest")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", self->host)); gchar num[64]; g_snprintf(num, sizeof(num), "%u", self->port); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("port", num)); return NULL; } static gboolean snmpdest_dd_session_init(SNMPDestDriver *self) { /* SNMP session setup */ memset(&self->session, 0, sizeof(self->session)); putenv("POSIXLY_CORRECT=1"); gchar *args[24]; gint argc = 0; gint i; /* add a new 'cmdline' argument to the array */ #define ADD_ARG(str) args[argc++] = str ? g_strdup(str) : g_strdup("") ADD_ARG("snmptrap"); ADD_ARG("-v"); if (!strcasecmp(self->version, s_v2c)) { /* v2c parameters */ ADD_ARG("2c"); ADD_ARG("-c"); ADD_ARG(self->community); } else { /* v3 parameters */ ADD_ARG("3"); ADD_ARG("-e"); ADD_ARG(self->engine_id); if (self->auth_username || self->auth_password) { ADD_ARG("-u"); ADD_ARG(self->auth_username); if (!self->auth_password) { ADD_ARG("-l"); ADD_ARG("noAuthNoPriv"); } else { ADD_ARG("-a"); ADD_ARG(self->auth_algorithm); ADD_ARG("-A"); ADD_ARG(self->auth_password); ADD_ARG("-l"); if (self->enc_password) { ADD_ARG("authPriv"); ADD_ARG("-x"); ADD_ARG(self->enc_algorithm); ADD_ARG("-X"); ADD_ARG(self->enc_password); } else ADD_ARG("authNoPriv"); } } } ADD_ARG("localhost"); ADD_ARG("42"); ADD_ARG("coldStart.0"); gint arg = snmp_parse_args(argc, args, &self->session, "C:", optProc); if (arg == NETSNMP_PARSE_ARGS_ERROR_USAGE || arg == NETSNMP_PARSE_ARGS_SUCCESS_EXIT) { goto error; } /* set our own address - the parse_args uses 'localhost' */ self->session.peername = self->host_port->str; self->session.callback = snmp_input; self->session.callback_magic = NULL; /* this block is copied from the snmptrap.c - necessary? */ if (self->session.version == SNMP_VERSION_3) { /* * for traps, we use ourselves as the authoritative engine * which is really stupid since command line apps don't have a * notion of a persistent engine. Hence, our boots and time * values are probably always really wacked with respect to what * a manager would like to see. * * The following should be enough to: * * 1) prevent the library from doing discovery for engineid & time. * 2) use our engineid instead of the remote engineid for * authoritative & privacy related operations. * 3) The remote engine must be configured with users for our engineID. * * -- Wes */ /* * setup the engineID based on IP addr. Need a different * algorithm here. This will cause problems with agents on the * same machine sending traps. */ setup_engineID(NULL, NULL); /* * pick our own engineID */ if (self->session.securityEngineIDLen == 0 || self->session.securityEngineID == NULL) { self->session.securityEngineID = snmpv3_generate_engineID(&self->session.securityEngineIDLen); } if (self->session.contextEngineIDLen == 0 || self->session.contextEngineID == NULL) { self->session.contextEngineID = snmpv3_generate_engineID(&self->session.contextEngineIDLen); } /* * set boots and time, which will cause problems if this * machine ever reboots and a remote trap receiver has cached our * boots and time... I'll cause a not-in-time-window report to * be sent back to this machine. */ if (self->session.engineBoots == 0) self->session.engineBoots = 1; if (self->session.engineTime == 0) /* not really correct, */ self->session.engineTime = get_uptime(); /* but it'll work. Sort of. */ } self->ss = snmp_add(&self->session, netsnmp_transport_open_client("snmptrap", self->session.peername), NULL, NULL); if (self->ss == NULL) { goto error; } self->session_initialized = TRUE; return TRUE; error: for (i = 0; i < argc; ++i) g_free(args[i]); free_session(&self->session); return FALSE; } static gboolean snmpdest_dd_init(LogPipe *s) { SNMPDestDriver *self = (SNMPDestDriver *)s; GlobalConfig *cfg = log_pipe_get_config(s); msg_verbose("Initializing SNMP destination", evt_tag_str("driver", self->super.super.super.id), evt_tag_str("host", self->host), evt_tag_int("port", self->port)); gchar err_msg[128]; if (!snmpdest_check_required_params(&self->super.super.super, err_msg)) { msg_error(err_msg); return FALSE; } if (!log_threaded_dest_driver_init_method(s)) return FALSE; log_template_options_init(&self->template_options, cfg); return TRUE; } static void snmpdest_worker_thread_deinit(LogThreadedDestDriver *d) { SNMPDestDriver *self = (SNMPDestDriver *)d; /* SNMP deinit */ if (self->session_initialized) { snmp_close(self->ss); free_session(&self->session); } } static gint snmp_dest_counter = 0; static void snmpdest_dd_free(LogPipe *d) { SNMPDestDriver *self = (SNMPDestDriver *)d; if (snmp_dest_counter == 1) { /* this is the last snmp driver, close the snmp */ SOCK_CLEANUP; snmp_shutdown(s_snmp_name); } --snmp_dest_counter; g_free(self->version); g_free(self->host); if (self->host_port) g_string_free(self->host_port, TRUE); g_list_free_full(self->snmp_objs, g_free); g_list_free_full(self->snmp_codes, g_free); g_list_free_full(self->snmp_templates, (GDestroyNotify)log_template_unref); g_free(self->trap_oid); g_free(self->trap_type); g_free(self->trap_value); g_free(self->community); g_free(self->engine_id); g_free(self->auth_username); g_free(self->auth_algorithm); g_free(self->auth_password); g_free(self->enc_algorithm); g_free(self->enc_password); g_free(self->transport); log_template_options_destroy(&self->template_options); log_threaded_dest_driver_free(d); } static void snmpdest_worker_thread_init(LogThreadedDestDriver *d) { SNMPDestDriver *self = (SNMPDestDriver *)d; GlobalConfig *cfg = log_pipe_get_config((LogPipe *)d); if (!self->host_port) { /* prepare the host:port format - the session.remote_port doesn't work */ self->host_port = g_string_sized_new(64); if (self->transport) g_string_append_printf(self->host_port, "%s:", self->transport); g_string_append_printf(self->host_port, "%s:%d", self->host, self->port); } gchar *tz = self->template_options.time_zone[LTZ_LOCAL]; gchar *time_zone = cfg->template_options.time_zone[LTZ_SEND]; /* inherit the global set_time_zone if the local one hasn't been set */ if (!tz && time_zone) snmpdest_dd_set_time_zone((LogDriver *)self, time_zone); snmpdest_dd_session_init(self); } LogDriver * snmpdest_dd_new(GlobalConfig *cfg) { SNMPDestDriver *self = g_new0(SNMPDestDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = snmpdest_dd_init; self->super.super.super.super.free_fn = snmpdest_dd_free; self->super.super.super.super.generate_persist_name = snmpdest_dd_format_persist_name; self->super.worker.thread_init = snmpdest_worker_thread_init; self->super.worker.thread_deinit = snmpdest_worker_thread_deinit; self->super.worker.insert = snmpdest_worker_insert; self->super.format_stats_key = snmpdest_dd_format_stats_key; self->super.stats_source = stats_register_type("snmp"); if (snmp_dest_counter == 0) { /* initialize the SNMP only once */ init_snmp(s_snmp_name); SOCK_STARTUP; } ++snmp_dest_counter; /* default values */ self->version = g_strdup(s_v2c); self->port = 162; self->community = g_strdup("public"); self->auth_algorithm = g_strdup(s_sha); self->enc_algorithm = g_strdup(s_aes); self->transport = g_strdup("UDP"); log_template_options_defaults(&self->template_options); return (LogDriver *)self; } gboolean snmpdest_check_required_params(LogDriver *d, gchar *err_msg) { SNMPDestDriver *self = (SNMPDestDriver *)d; /* required parameters */ if (!self->snmp_objs) { sprintf(err_msg, "missing SNMP object"); return FALSE; } if (!self->host) { sprintf(err_msg, "missing host"); return FALSE; } if (!self->trap_oid || !self->trap_type || !self->trap_value) { sprintf(err_msg, "missing trap_obj"); return FALSE; } if (strcasecmp(self->trap_type, "objectid")) { sprintf(err_msg, "wrong trap object type: %s", self->trap_type); return FALSE; } /* v3-specific parameters */ if (!strcmp(self->version, s_v3) && !self->engine_id) { sprintf(err_msg, "missing engine id"); return FALSE; } return TRUE; } gchar *snmpdest_dd_get_version(LogDriver *d) { SNMPDestDriver *self = (SNMPDestDriver *)d; return self->version; } const LogTemplateOptions * snmpdest_dd_get_template_options(LogDriver *d) { SNMPDestDriver *self = (SNMPDestDriver *) d; return &self->template_options; } gboolean snmpdest_dd_check_auth_algorithm(gchar *algo) { if (strcasecmp(algo, s_sha) == 0) return TRUE; return FALSE; } gboolean snmpdest_dd_check_enc_algorithm(gchar *algo) { if (strcasecmp(algo, s_aes) == 0) return TRUE; return FALSE; } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/afsnmpdest.h000066400000000000000000000066731450431004300226400ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSNMPDEST_H_INCLUDED #define AFSNMPDEST_H_INCLUDED #include #include #include "driver.h" #include "mainloop-worker.h" #include "logthrdest/logthrdestdrv.h" #define ENGINE_ID_MAX_LENGTH 32 #define ENGINE_ID_MIN_LENGTH 5 extern const gchar *s_v2c, *s_v3; typedef struct { LogThreadedDestDriver super; gchar *version; gchar *host; GString *host_port; gint port; GList *snmp_objs; /* the values are stored as string triplets (oid, type, value) - the list size is always dividable by 3 */ GList *snmp_templates; GList *snmp_codes; gchar *trap_oid, *trap_type, *trap_value; gchar *community; gchar *engine_id; gchar *auth_username; gchar *auth_algorithm; gchar *auth_password; gchar *enc_algorithm; gchar *enc_password; gchar *transport; netsnmp_session session, *ss; gboolean session_initialized; LogQueue *queue; LogTemplate *message; LogTemplateOptions template_options; } SNMPDestDriver; LogDriver *snmpdest_dd_new(GlobalConfig *cfg); void snmpdest_dd_set_version(LogDriver *d, const gchar *version); void snmpdest_dd_set_host(LogDriver *d, const gchar *host); void snmpdest_dd_set_port(LogDriver *d, gint port); gboolean snmpdest_dd_set_snmp_obj(LogDriver *d, GlobalConfig *cfg, const gchar *objectid, const gchar *type, const gchar *value); void snmpdest_dd_set_trap_obj(LogDriver *d, GlobalConfig *cfg, const gchar *objectid, const gchar *type, const gchar *value); void snmpdest_dd_set_community(LogDriver *d, const gchar *community); gboolean snmpdest_dd_set_engine_id(LogDriver *d, const gchar *eid); void snmpdest_dd_set_auth_username(LogDriver *d, const gchar *auth_username); void snmpdest_dd_set_auth_algorithm(LogDriver *d, const gchar *auth_algo); void snmpdest_dd_set_auth_password(LogDriver *d, const gchar *auth_pwd); void snmpdest_dd_set_enc_algorithm(LogDriver *d, const gchar *enc_algo); void snmpdest_dd_set_enc_password(LogDriver *d, const gchar *epwd); void snmpdest_dd_set_transport(LogDriver *d, const gchar *transport); void snmpdest_dd_set_time_zone(LogDriver *d, const gchar *Time_zone); gboolean snmpdest_check_required_params(LogDriver *, gchar *err_msg); gchar *snmpdest_dd_get_version(LogDriver *); const LogTemplateOptions *snmpdest_dd_get_template_options(LogDriver *d); gboolean snmpdest_dd_check_auth_algorithm(gchar *algo); gboolean snmpdest_dd_check_enc_algorithm(gchar *algo); #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/snmptrapd-header-parser.c000066400000000000000000000205071450431004300252070ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "snmptrapd-header-parser.h" #include "str-format.h" #include "timeutils/cache.h" #include "timeutils/conv.h" #include #include typedef struct { SnmpTrapdNVContext *nv_context; const gchar **input; gsize *input_len; } SnmpTrapdHeaderParser; typedef gboolean (*SnmpTrapdHeaderParserStep)(SnmpTrapdHeaderParser *self); static inline void _skip_spaces(SnmpTrapdHeaderParser *self) { const gchar *current_char = *self->input; while (*self->input_len > 0 && *current_char == ' ') { ++current_char; --(*self->input_len); } *self->input = current_char; } static gboolean _run_header_parser(SnmpTrapdHeaderParser *self, SnmpTrapdHeaderParserStep *parser_steps, gsize parser_steps_size) { SnmpTrapdHeaderParserStep parser_step; for (gsize step_index = 0; step_index < parser_steps_size; ++step_index) { _skip_spaces(self); parser_step = parser_steps[step_index]; if (!parser_step(self)) return FALSE; } return TRUE; } static inline gboolean _expect_char(SnmpTrapdHeaderParser *self, gchar c) { return scan_expect_char(self->input, (gint *) self->input_len, c); } static inline gboolean _expect_newline(SnmpTrapdHeaderParser *self) { return _expect_char(self, '\n'); } static inline gboolean _expect_newline_or_eom(SnmpTrapdHeaderParser *self) { return _expect_newline(self) || *self->input_len == 0; } static inline gboolean _expect_colon(SnmpTrapdHeaderParser *self) { return _expect_char(self, ':'); } static inline gboolean _expect_tab(SnmpTrapdHeaderParser *self) { return _expect_char(self, '\t'); } static inline void _scroll_to_eom(SnmpTrapdHeaderParser *self) { while (*self->input_len > 0 || **self->input) { ++(*self->input); --(*self->input_len); } } static gboolean _parse_v1_uptime(SnmpTrapdHeaderParser *self) { if (!scan_expect_str(self->input, (gint *) self->input_len, "Uptime:")) return FALSE; _skip_spaces(self); const gchar *uptime_start = *self->input; const gchar *uptime_end = strchr(uptime_start, '\n'); if (!uptime_end) { _scroll_to_eom(self); snmptrapd_nv_context_add_name_value(self->nv_context, "uptime", uptime_start, *self->input - uptime_start); return TRUE; } snmptrapd_nv_context_add_name_value(self->nv_context, "uptime", uptime_start, uptime_end - uptime_start); *self->input_len -= uptime_end - *self->input; *self->input = uptime_end; return TRUE; } static gboolean _parse_v1_trap_type_and_subtype(SnmpTrapdHeaderParser *self) { const gchar *type_start = *self->input; const gchar *type_end = strpbrk(type_start, "(\n"); gboolean type_exists = type_end && *type_end == '('; if (!type_exists) return FALSE; const gchar *subtype_start = type_end + 1; if (*(type_end - 1) == ' ') --type_end; snmptrapd_nv_context_add_name_value(self->nv_context, "type", type_start, type_end - type_start); const gchar *subtype_end = strpbrk(subtype_start, ")\n"); gboolean subtype_exists = subtype_end && *subtype_end == ')'; if (!subtype_exists) return FALSE; snmptrapd_nv_context_add_name_value(self->nv_context, "subtype", subtype_start, subtype_end - subtype_start); *self->input_len -= (subtype_end + 1) - *self->input; *self->input = subtype_end + 1; return TRUE; } static gboolean _parse_v1_enterprise_oid(SnmpTrapdHeaderParser *self) { const gchar *enterprise_string_start = *self->input; gsize input_left = *self->input_len; while (*self->input_len > 0 && !g_ascii_isspace(**self->input)) { ++(*self->input); --(*self->input_len); } gsize enterprise_string_length = input_left - *self->input_len; /* enterprise_string is optional */ if (enterprise_string_length == 0) return TRUE; snmptrapd_nv_context_add_name_value(self->nv_context, "enterprise_oid", enterprise_string_start, enterprise_string_length); return TRUE; } static gboolean _parse_transport_info(SnmpTrapdHeaderParser *self) { if(!scan_expect_char(self->input, (gint *) self->input_len, '[')) return FALSE; _skip_spaces(self); const gchar *transport_info_start = *self->input; const gchar *transport_info_end = strchr(transport_info_start, '\n'); if (!transport_info_end) return FALSE; while(*transport_info_end != ']') { --transport_info_end; if(transport_info_end == transport_info_start) return FALSE; } gsize transport_info_len = transport_info_end - transport_info_start; snmptrapd_nv_context_add_name_value(self->nv_context, "transport_info", transport_info_start, transport_info_len); *self->input_len -= (transport_info_end + 1) - *self->input; *self->input = transport_info_end + 1; return TRUE; } static gboolean _parse_hostname(SnmpTrapdHeaderParser *self) { const gchar *hostname_start = *self->input; gsize input_left = *self->input_len; while (*self->input_len > 0 && !g_ascii_isspace(**self->input)) { ++(*self->input); --(*self->input_len); } gsize hostname_length = input_left - *self->input_len; if (hostname_length == 0) return FALSE; snmptrapd_nv_context_add_name_value(self->nv_context, "hostname", hostname_start, hostname_length); return TRUE; } static gboolean scan_snmptrapd_timestamp(const gchar **buf, gint *left, WallClockTime *wct) { /* YYYY-MM-DD HH:MM:SS */ if (!scan_positive_int(buf, left, 4, &wct->wct_year) || !scan_expect_char(buf, left, '-') || !scan_positive_int(buf, left, 2, &wct->wct_mon) || !scan_expect_char(buf, left, '-') || !scan_positive_int(buf, left, 2, &wct->wct_mday) || !scan_expect_char(buf, left, ' ') || !scan_positive_int(buf, left, 2, &wct->wct_hour) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_min) || !scan_expect_char(buf, left, ':') || !scan_positive_int(buf, left, 2, &wct->wct_sec)) return FALSE; wct->wct_year -= 1900; wct->wct_mon -= 1; return TRUE; } static gboolean _parse_timestamp(SnmpTrapdHeaderParser *self) { WallClockTime wct = WALL_CLOCK_TIME_INIT; if (!scan_snmptrapd_timestamp(self->input, (gint *)self->input_len, &wct)) return FALSE; convert_and_normalize_wall_clock_time_to_unix_time(&wct, &self->nv_context->msg->timestamps[LM_TS_STAMP]); return TRUE; } static gboolean _try_parse_v1_info(SnmpTrapdHeaderParser *self) { /* detect v1 format */ const gchar *new_line = strchr(*self->input, '\n'); if (new_line && new_line[1] != '\t') return TRUE; SnmpTrapdHeaderParserStep v1_info_parser_steps[] = { _parse_v1_enterprise_oid, _expect_newline, _expect_tab, _parse_v1_trap_type_and_subtype, _parse_v1_uptime }; return _run_header_parser(self, v1_info_parser_steps, sizeof(v1_info_parser_steps) / sizeof(SnmpTrapdHeaderParserStep)); } gboolean snmptrapd_header_parser_parse(SnmpTrapdNVContext *nv_context, const gchar **input, gsize *input_len) { /* * DATE HOST [TRANSPORT_INFO]: V1_ENTERPRISE_OID * V1_TRAP_TYPE (V1_TRAP_SUBTYPE) "Uptime:" UPTIME */ SnmpTrapdHeaderParser self = { .nv_context = nv_context, .input = input, .input_len = input_len }; SnmpTrapdHeaderParserStep parser_steps[] = { _parse_timestamp, _parse_hostname, _parse_transport_info, _expect_colon, _try_parse_v1_info, _expect_newline_or_eom }; return _run_header_parser(&self, parser_steps, sizeof(parser_steps) / sizeof(SnmpTrapdHeaderParserStep)); } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/snmptrapd-header-parser.h000066400000000000000000000022531450431004300252120ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef SNMPTRAPD_HEADER_PARSER_H_INCLUDED #define SNMPTRAPD_HEADER_PARSER_H_INCLUDED #include "syslog-ng.h" #include "logmsg/logmsg.h" #include "snmptrapd-nv-context.h" gboolean snmptrapd_header_parser_parse(SnmpTrapdNVContext *nv_context, const gchar **input, gsize *input_len); #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/snmptrapd-nv-context.h000066400000000000000000000027631450431004300246030ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef SNMPTRAPD_NV_CONTEXT_H_INCLUDED #define SNMPTRAPD_NV_CONTEXT_H_INCLUDED typedef struct _SnmpTrapdNVContext SnmpTrapdNVContext; struct _SnmpTrapdNVContext { GString *key_prefix; LogMessage *msg; GString *generated_message; void (*add_name_value)(SnmpTrapdNVContext *nv_context, const gchar *key, const gchar *value, gsize value_length); }; static inline void snmptrapd_nv_context_add_name_value(SnmpTrapdNVContext *nv_context, const gchar *key, const gchar *value, gsize value_length) { nv_context->add_name_value(nv_context, key, value, value_length); } #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/snmptrapd-parser.c000066400000000000000000000171041450431004300237600ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "snmptrapd-parser.h" #include "snmptrapd-header-parser.h" #include "snmptrapd-nv-context.h" #include "varbindlist-scanner.h" #include "scratch-buffers.h" #include "utf8utils.h" #include "str-utils.h" typedef struct _SnmpTrapdParser { LogParser super; GString *prefix; gboolean set_message_macro; } SnmpTrapdParser; void snmptrapd_parser_set_prefix(LogParser *s, const gchar *prefix) { SnmpTrapdParser *self = (SnmpTrapdParser *) s; if (!prefix) g_string_truncate(self->prefix, 0); else g_string_assign(self->prefix, prefix); } void snmptrapd_parser_set_set_message_macro(LogParser *s, gboolean set_message_macro) { SnmpTrapdParser *self = (SnmpTrapdParser *) s; self->set_message_macro = set_message_macro; } static inline gboolean _is_unwanted_key_char(gchar c) { return (c == ':'); } static inline void _move_and_replace_unwanted_key_chars(GString *key, gsize unwanted_key_count, gchar **curr_char_addr) { gsize number_of_removed_chars = unwanted_key_count - 1; gchar *curr_pos = *curr_char_addr; gchar *end_of_str = key->str + key->len; gchar *replace_pos = curr_pos - unwanted_key_count; if (unwanted_key_count > 1) { memmove(replace_pos, curr_pos - 1, end_of_str - (curr_pos - 1)); g_string_truncate(key, key->len - number_of_removed_chars); } *replace_pos = '_'; *curr_char_addr -= unwanted_key_count; } static const gchar * _normalize_key(GString *key) { gsize unwanted_key_count = 0; gchar *curr_char = key->str; while (*curr_char) { if (_is_unwanted_key_char(*curr_char)) { unwanted_key_count++; } else if (unwanted_key_count > 0) { _move_and_replace_unwanted_key_chars(key, unwanted_key_count, &curr_char); unwanted_key_count = 0; } curr_char++; } if (unwanted_key_count) _move_and_replace_unwanted_key_chars(key, unwanted_key_count, &curr_char); return key->str; } static const gchar * _get_formatted_key(const gchar *key, const GString *prefix, GString *formatted_key) { g_string_truncate(formatted_key, 0); if (prefix->len > 0) g_string_assign(formatted_key, prefix->str); g_string_append(formatted_key, key); _normalize_key(formatted_key); return formatted_key->str; } static void _append_name_value_to_generated_message(GString *generated_message, const gchar *key, const gchar *value, gsize value_length) { ScratchBuffersMarker marker; GString *escaped_value = scratch_buffers_alloc_and_mark(&marker); if (generated_message->len > 0) g_string_append(generated_message, ", "); append_unsafe_utf8_as_escaped_text(escaped_value, value, value_length, "'"); g_string_append_printf(generated_message, "%s='%s'", key, escaped_value->str); scratch_buffers_reclaim_marked(marker); } static void _add_name_value(SnmpTrapdNVContext *nv_context, const gchar *key, const gchar *value, gsize value_length) { ScratchBuffersMarker marker; GString *formatted_key = scratch_buffers_alloc_and_mark(&marker); const gchar *prefixed_key = _get_formatted_key(key, nv_context->key_prefix, formatted_key); log_msg_set_value_by_name(nv_context->msg, prefixed_key, value, value_length); if (nv_context->generated_message) _append_name_value_to_generated_message(nv_context->generated_message, key, value, value_length); scratch_buffers_reclaim_marked(marker); } static gboolean _parse_varbindlist(SnmpTrapdNVContext *nv_context, const gchar **input, gsize *input_len) { VarBindListScanner varbindlist_scanner; const gchar *key, *value; varbindlist_scanner_init(&varbindlist_scanner); varbindlist_scanner_input(&varbindlist_scanner, *input); while (varbindlist_scanner_scan_next(&varbindlist_scanner)) { key = varbindlist_scanner_get_current_key(&varbindlist_scanner); value = varbindlist_scanner_get_current_value(&varbindlist_scanner); snmptrapd_nv_context_add_name_value(nv_context, key, value, -1); } varbindlist_scanner_deinit(&varbindlist_scanner); return TRUE; } static gboolean snmptrapd_parser_process(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const gchar *input, gsize input_len) { SnmpTrapdParser *self = (SnmpTrapdParser *) s; ScratchBuffersMarker marker; log_msg_make_writable(pmsg, path_options); msg_trace("snmptrapd-parser message processing started", evt_tag_str ("input", input), evt_tag_str ("prefix", self->prefix->str), evt_tag_msg_reference(*pmsg)); APPEND_ZERO(input, input, input_len); GString *generated_message = NULL; if (self->set_message_macro) generated_message = scratch_buffers_alloc_and_mark(&marker); SnmpTrapdNVContext nv_context = { .key_prefix = self->prefix, .msg = *pmsg, .generated_message = generated_message, .add_name_value = _add_name_value }; log_msg_set_value(nv_context.msg, LM_V_PROGRAM, "snmptrapd", -1); if (!snmptrapd_header_parser_parse(&nv_context, &input, &input_len)) { msg_debug("snmptrapd-parser failed", evt_tag_str ("error", "cannot parse snmptrapd header"), evt_tag_str ("input", input)); return FALSE; }; if (!_parse_varbindlist(&nv_context, &input, &input_len)) { msg_debug("snmptrapd-parser failed", evt_tag_str ("error", "can not parse name-value pairs in the input"), evt_tag_str ("input", input)); return FALSE; }; if (self->set_message_macro) { log_msg_set_value(nv_context.msg, LM_V_MESSAGE, nv_context.generated_message->str, -1); scratch_buffers_reclaim_marked(marker); } else { log_msg_unset_value(nv_context.msg, LM_V_MESSAGE); } return TRUE; } static LogPipe * snmptrapd_parser_clone(LogPipe *s) { SnmpTrapdParser *self = (SnmpTrapdParser *) s; SnmpTrapdParser *cloned = (SnmpTrapdParser *) snmptrapd_parser_new(s->cfg); snmptrapd_parser_set_prefix(&cloned->super, self->prefix->str); snmptrapd_parser_set_set_message_macro(&cloned->super, self->set_message_macro); log_parser_clone_settings(&self->super, &cloned->super); return &cloned->super.super; } static void snmptrapd_parser_free(LogPipe *s) { SnmpTrapdParser *self = (SnmpTrapdParser *) s; g_string_free(self->prefix, TRUE); log_parser_free_method(s); } LogParser * snmptrapd_parser_new(GlobalConfig *cfg) { SnmpTrapdParser *self = g_new0(SnmpTrapdParser, 1); log_parser_init_instance(&self->super, cfg); self->super.super.free_fn = snmptrapd_parser_free; self->super.super.clone = snmptrapd_parser_clone; self->super.process = snmptrapd_parser_process; self->prefix = g_string_new(".snmp."); self->set_message_macro = TRUE; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/snmptrapd-parser.h000066400000000000000000000023111450431004300237570ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef SNMPTRAPD_PARSER_H_INCLUDED #define SNMPTRAPD_PARSER_H_INCLUDED #include "parser/parser-expr.h" LogParser *snmptrapd_parser_new(GlobalConfig *cfg); void snmptrapd_parser_set_prefix(LogParser *s, const gchar *prefix); void snmptrapd_parser_set_set_message_macro(LogParser *s, gboolean set_message_macro); #endif syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/000077500000000000000000000000001450431004300214515ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/CMakeLists.txt000066400000000000000000000003251450431004300242110ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test_afsnmp_dest DEPENDS afsnmp) add_unit_test(CRITERION TARGET test_varbindlist_scanner DEPENDS afsnmp) add_unit_test(LIBTEST CRITERION TARGET test_snmptrapd_parser DEPENDS afsnmp) syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/Makefile.am000066400000000000000000000023371450431004300235120ustar00rootroot00000000000000if ENABLE_AFSNMP modules_afsnmp_tests_TESTS = \ modules/afsnmp/tests/test_afsnmp_dest \ modules/afsnmp/tests/test_varbindlist_scanner \ modules/afsnmp/tests/test_snmptrapd_parser check_PROGRAMS += \ ${modules_afsnmp_tests_TESTS} modules_afsnmp_tests_test_afsnmp_dest_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/afsnmp modules_afsnmp_tests_test_afsnmp_dest_LDADD = $(TEST_LDADD) modules_afsnmp_tests_test_afsnmp_dest_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsnmp/libafsnmp.la modules_afsnmp_tests_test_afsnmp_dest_DEPENDENCIES = \ $(top_builddir)/modules/afsnmp/libafsnmp.la modules_afsnmp_tests_test_varbindlist_scanner_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/afsnmp modules_afsnmp_tests_test_varbindlist_scanner_LDADD = $(TEST_LDADD) modules_afsnmp_tests_test_varbindlist_scanner_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsnmp/libafsnmp.la modules_afsnmp_tests_test_snmptrapd_parser_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/afsnmp modules_afsnmp_tests_test_snmptrapd_parser_LDADD = $(TEST_LDADD) modules_afsnmp_tests_test_snmptrapd_parser_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsnmp/libafsnmp.la endif EXTRA_DIST += modules/afsnmp/tests/CMakeLists.txt syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/test_afsnmp_dest.c000066400000000000000000000162001450431004300251560ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "apphook.h" #include "afsnmpdest.h" #include "logpipe.h" #include #include static SNMPDestDriver *snmp_driver; static GlobalConfig *cfg; static void _init(void) { app_startup(); cfg = cfg_new_snippet(); snmp_driver = (SNMPDestDriver *)snmpdest_dd_new(cfg); } static void _teardown(void) { log_pipe_unref((LogPipe *)&snmp_driver->super.super); app_shutdown(); cfg_free(cfg); } TestSuite(test_snmp_dest, .init = _init, .fini = _teardown); Test(test_snmp_dest, set_version) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_version(driver, "v2c"); cr_assert_str_eq(snmpdest_dd_get_version(driver), "v2c"); } Test(test_snmp_dest, set_host) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_host(driver, "127.0.0.1"); cr_assert_str_eq(snmp_driver->host, "127.0.0.1"); } Test(test_snmp_dest, set_port) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_port(driver, 161); cr_assert_eq(snmp_driver->port, 161); } Test(test_snmp_dest, set_community) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_community(driver, "my_community"); cr_assert_str_eq(snmp_driver->community, "my_community"); } Test(test_snmp_dest, set_engine_id) { LogDriver *driver = (LogDriver *)snmp_driver; cr_assert_not(snmpdest_dd_set_engine_id(driver, "bar")); // not number cr_assert_not(snmpdest_dd_set_engine_id(driver, "0x42")); // too short cr_assert_not(snmpdest_dd_set_engine_id(driver, "0x0123456789abcdef0123456789abcdef0")); // too long cr_assert(snmpdest_dd_set_engine_id(driver, "123abc")); // missing prefix cr_assert_str_eq(snmp_driver->engine_id, "123abc"); cr_assert(snmpdest_dd_set_engine_id(driver, "0x12345")); cr_assert_str_eq(snmp_driver->engine_id, "12345"); } Test(test_snmp_dest, set_auth_username) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_auth_username(driver, "auth_username"); cr_assert_str_eq(snmp_driver->auth_username, "auth_username"); } Test(test_snmp_dest, set_auth_algo) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_auth_algorithm(driver, "auth_algorithm"); cr_assert_str_eq(snmp_driver->auth_algorithm, "auth_algorithm"); cr_assert_not(snmpdest_dd_check_auth_algorithm(snmp_driver->auth_algorithm)); snmpdest_dd_set_auth_algorithm(driver, "SHA"); cr_assert(snmpdest_dd_check_auth_algorithm(snmp_driver->auth_algorithm)); } Test(test_snmp_dest, set_auth_password) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_auth_password(driver, "password"); cr_assert_str_eq(snmp_driver->auth_password, "password"); } Test(test_snmp_dest, set_enc_algo) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_enc_algorithm(driver, "enc_algorithm"); cr_assert_str_eq(snmp_driver->enc_algorithm, "enc_algorithm"); cr_assert_not(snmpdest_dd_check_enc_algorithm(snmp_driver->enc_algorithm)); snmpdest_dd_set_enc_algorithm(driver, "AES"); cr_assert(snmpdest_dd_check_enc_algorithm(snmp_driver->enc_algorithm)); } Test(test_snmp_dest, set_enc_password) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_enc_password(driver, "enc_password"); cr_assert_str_eq(snmp_driver->enc_password, "enc_password"); } Test(test_snmp_dest, set_transport) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_transport(driver, "transport"); cr_assert_str_eq(snmp_driver->transport, "transport"); } Test(test_snmp_dest, set_time_zone) { LogDriver *driver = (LogDriver *)snmp_driver; snmpdest_dd_set_time_zone(driver, "time_zone"); cr_assert_str_eq(snmpdest_dd_get_template_options(driver)->time_zone[LTZ_LOCAL], "time_zone"); } Test(test_snmp_dest, check_required_params) { LogDriver *driver = (LogDriver *)snmp_driver; gchar err_msg[128]; /* check parameters of an empty driver struct */ cr_assert_not(snmpdest_check_required_params(driver, err_msg)); /* setup snmp driver with valid parameters */ snmpdest_dd_set_snmp_obj(driver, cfg, ".1.3.6.1.4.1.18372.3.1.1.1.1.1.0", "Octetstring", "admin"); snmpdest_dd_set_trap_obj(driver, cfg, ".1.3.6.1.6.3.1.1.4.1.0", "Objectid", ".1.3.6.1.4.1.18372.3.1.1.1.2.1"); snmpdest_dd_set_host(driver, "127.0.0.1"); snmpdest_dd_set_version(driver, "v2c"); cr_assert(snmpdest_check_required_params(driver, err_msg), "check required param failed %s", err_msg); /* for v3 version the engine_id shall be set as well*/ snmpdest_dd_set_version(driver, "v3"); snmpdest_dd_set_engine_id(driver, "0x12345"); cr_assert(snmpdest_check_required_params(driver, err_msg)); } typedef struct _snmp_obj_test_param { const gchar *objectid; const gchar *type; const gchar *value; gboolean expected_result; } SnmpObjTestParam; ParameterizedTestParameters(test_snmp_dest, test_set_snmp_obj) { static SnmpObjTestParam parser_params[] = { { .objectid = ".1.3.6.1.4.1.18372.3.1.1.1.1.3.0", .type = "integer", .value = "123", .expected_result = TRUE }, { .objectid = ".1.3.6.1.4.1.18372.3.1.1.1.1.3.0", .type = "timeticks", .value = "0", .expected_result = TRUE }, { .objectid = ".1.3.6.1.4.1.18372.3.1.1.1.1.1.0", .type = "octetstring", .value = "Test SNMP trap", .expected_result = TRUE }, { .objectid = ".1.3.6.1.4.1.18372.3.1.1.1.1.3.0", .type = "counter32", .value = "1234567", .expected_result = TRUE }, { .objectid = ".1.3.6.1.4.1.18372.3.1.1.1.1.3.0", .type = "ipaddress", .value = "127.0.0.1", .expected_result = TRUE }, { .objectid = ".1.3.6.1.6.3.1.1.4.1.0", .type = "objectid", .value = ".1.3.6.1.4.1.18372.3.1.1.1.2.1", .expected_result = TRUE }, { .objectid = "my_object_id", .type = "pacalporkolt", .value = "krumpli", .expected_result = FALSE }, }; return cr_make_param_array(SnmpObjTestParam, parser_params, G_N_ELEMENTS(parser_params)); } ParameterizedTest(SnmpObjTestParam *param, test_snmp_dest, test_set_snmp_obj) { LogDriver *driver = (LogDriver *)snmp_driver; gboolean result = snmpdest_dd_set_snmp_obj(driver, cfg, param->objectid, param->type, param->value); cr_assert_eq(result, param->expected_result); } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/test_snmptrapd_parser.c000066400000000000000000000306061450431004300262450ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include #include "libtest/msg_parse_lib.h" #include "snmptrapd-parser.h" #include "apphook.h" #define SIZE_OF_ARRAY(array) (sizeof(array) / sizeof((array)[0])) typedef struct { const gchar *name; const gchar *value; } TestNameValue; typedef struct { const gchar *key_prefix; gboolean set_message_macro; } TestParserOptions; static LogParser * create_parser(TestParserOptions *options) { LogParser *snmptrapd_parser = snmptrapd_parser_new(configuration); if (options) { if (options->key_prefix) snmptrapd_parser_set_prefix(snmptrapd_parser, options->key_prefix); snmptrapd_parser_set_set_message_macro(snmptrapd_parser, options->set_message_macro); } log_pipe_init((LogPipe *)snmptrapd_parser); return snmptrapd_parser; } static void destroy_parser(LogParser *snmptrapd_parser) { log_pipe_deinit((LogPipe *)snmptrapd_parser); log_pipe_unref((LogPipe *)snmptrapd_parser); } static LogMessage * copy_str_into_log_message(const gchar *message) { LogMessage *msg = log_msg_new_empty(); log_msg_set_value(msg, LM_V_MESSAGE, message, -1); return msg; } static gboolean _process_log_message(LogParser *parser, LogMessage *msg) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; return log_parser_process_message(parser, &msg, &path_options); } static LogMessage * parse_str_into_log_message(LogParser *parser, const gchar *message) { LogMessage *msg = copy_str_into_log_message(message); cr_assert(_process_log_message(parser, msg)); return msg; } static void assert_log_message_dropped(const gchar *input) { LogParser *parser = create_parser(NULL); LogMessage *msg = copy_str_into_log_message(input); cr_assert_not(_process_log_message(parser, msg)); log_msg_unref(msg); destroy_parser(parser); } static void assert_log_message_name_values_with_options(TestParserOptions *options, const gchar *input, TestNameValue *expected, gsize number_of_expected) { LogParser *parser = create_parser(options); LogMessage *msg = parse_str_into_log_message(parser, input); for (int i=0; i < number_of_expected; i++) assert_log_message_value_by_name(msg, expected[i].name, expected[i].value); log_msg_unref(msg); destroy_parser(parser); } static void assert_log_message_name_values(const gchar *input, TestNameValue *expected, gsize number_of_expected) { assert_log_message_name_values_with_options(NULL, input, expected, number_of_expected); } void setup(void) { configuration = cfg_new_snippet(); app_startup(); } void teardown(void) { app_shutdown(); cfg_free(configuration); } TestSuite(snmptrapd_parser, .init = setup, .fini = teardown); Test(snmptrapd_parser, test_general_v2_message_with_oids) { const gchar *input = "2017-05-10 12:46:14 web2-kukorica.syslog_ng.balabit [UDP: [127.0.0.1]:34257->[127.0.0.1]:162]:\n" "iso.3.6.1.2.1.1.3.0 = Timeticks: (875496867) 101 days, 7:56:08.67\t" "iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.8072.2.3.0.1 " "iso.3.6.1.4.1.8072.2.3.2.1 = INTEGER: 60 \t " "iso.3.6.1.4.1.8072.2.1.3 = \"\""; TestNameValue expected[] = { { ".snmp.hostname", "web2-kukorica.syslog_ng.balabit" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:34257->[127.0.0.1]:162" }, { ".snmp.iso.3.6.1.2.1.1.3.0", "(875496867) 101 days, 7:56:08.67" }, { ".snmp.iso.3.6.1.6.3.1.1.4.1.0", "iso.3.6.1.4.1.8072.2.3.0.1" }, { ".snmp.iso.3.6.1.4.1.8072.2.3.2.1", "60" }, { ".snmp.iso.3.6.1.4.1.8072.2.1.3", "" }, { "DATE", "May 10 12:46:14" }, }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_general_v1_message_with_oids) { const gchar *input = "2017-11-10 13:23:16 localhost [UDP: [127.0.0.1]:53831->[127.0.0.1]:162]: iso.3.6.1.4.1.8072.2.3.1\n" "\t Enterprise Specific Trap (.17) Uptime: 18:41:07.83\n" "iso.3.6.1.4.1.8072.2.1.1 = INTEGER: 123456"; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:53831->[127.0.0.1]:162" }, { ".snmp.enterprise_oid", "iso.3.6.1.4.1.8072.2.3.1" }, { ".snmp.type", "Enterprise Specific Trap" }, { ".snmp.subtype", ".17" }, { ".snmp.uptime", "18:41:07.83" }, { ".snmp.iso.3.6.1.4.1.8072.2.1.1", "123456" }, { "DATE", "Nov 10 13:23:16" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v2_with_symbolic_names_and_various_types) { const gchar *input = "2017-05-13 12:17:32 localhost [UDP: [127.0.0.1]:52407->[127.0.0.1]:162]: \n " "mib-2.1.3.0 = Timeticks: (875496867) 101 days, 7:56:08.67 \t" "snmpModules.1.1.4.1.0 = OID: netSnmpExampleHeartbeatNotification " "netSnmpExampleHeartbeatRate = INTEGER: 60\t" "netSnmpExampleString = STRING: \"string innerkey='innervalue'\"\t" "org.2.2 = Gauge32: 22\t" "org.1.1 = Counter32: 11123123 " "org.5.3 = Hex-STRING: A0 BB CC DD EF \t" "org.8.8 = NULL\t" "dod.7 = IpAddress: 192.168.1.0\t " "org.5.9 = STRING: \"@\""; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:52407->[127.0.0.1]:162" }, { ".snmp.snmpModules.1.1.4.1.0", "netSnmpExampleHeartbeatNotification" }, { ".snmp.netSnmpExampleHeartbeatRate", "60" }, { ".snmp.netSnmpExampleString", "string innerkey='innervalue'" }, { ".snmp.org.2.2", "22" }, { ".snmp.org.1.1", "11123123" }, { ".snmp.org.5.3", "A0 BB CC DD EF" }, { ".snmp.org.8.8", "NULL" }, { ".snmp.dod.7", "192.168.1.0" }, { ".snmp.org.5.9", "@" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v1_with_symbolic_names) { const gchar *input = "2017-05-13 12:18:30 localhost [UDP: [127.0.0.1]:58143->[127.0.0.1]:162] : netSnmpExampleNotification \n" "\t Warm Start Trap (1) Uptime: 27 days, 2:39:02.34\n " "netSnmpExampleInteger = INTEGER: 123456 \t netSnmpExampleString = STRING: random string"; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:58143->[127.0.0.1]:162" }, { ".snmp.enterprise_oid", "netSnmpExampleNotification" }, { ".snmp.type", "Warm Start Trap" }, { ".snmp.subtype", "1" }, { ".snmp.uptime", "27 days, 2:39:02.34" }, { ".snmp.netSnmpExampleInteger", "123456" }, { ".snmp.netSnmpExampleString", "random string" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v2_with_generated_message) { TestParserOptions options = { .set_message_macro = TRUE }; const gchar *input = "2017-05-17 13:26:04 localhost [UDP: [127.0.0.1]:34257->[127.0.0.1]:162]:\n" "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = STRING: \"test\""; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:34257->[127.0.0.1]:162" }, { ".snmp.iso.3.6.1.4.1.18372.3.2.1.1.1.6", "test" }, { "MESSAGE", "hostname='localhost', transport_info='UDP: [127.0.0.1]:34257->[127.0.0.1]:162', " "iso.3.6.1.4.1.18372.3.2.1.1.1.6='test'" } }; assert_log_message_name_values_with_options(&options, input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v2_with_generated_message_escaped) { TestParserOptions options = { .set_message_macro = TRUE }; const gchar *input = "2017-05-17 13:26:04 localhost [UDP: [127.0.0.1]:34257->[127.0.0.1]:162]:\n" "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = STRING: \"test 'escaped'\""; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:34257->[127.0.0.1]:162" }, { ".snmp.iso.3.6.1.4.1.18372.3.2.1.1.1.6", "test 'escaped'" }, { "MESSAGE", "hostname='localhost', transport_info='UDP: [127.0.0.1]:34257->[127.0.0.1]:162', " "iso.3.6.1.4.1.18372.3.2.1.1.1.6='test \\'escaped\\''" } }; assert_log_message_name_values_with_options(&options, input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v2_without_prefix) { TestParserOptions options = { .key_prefix = "" }; const gchar *input = "2017-05-17 13:26:04 localhost [UDP: [127.0.0.1]:34257->[127.0.0.1]:162]:\n" "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = test"; TestNameValue expected[] = { { "hostname", "localhost" }, { "transport_info", "UDP: [127.0.0.1]:34257->[127.0.0.1]:162" }, { "iso.3.6.1.4.1.18372.3.2.1.1.1.6", "test" } }; assert_log_message_name_values_with_options(&options, input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_v2_key_normalization) { const gchar *input = "2017-05-13 12:17:32 localhost [UDP: [127.0.0.1]:52407->[127.0.0.1]:162]: \n " "mib-2.1.3.0 = Timeticks: (875496867) 101 days, 7:56:08.67 \t" "NET-SNMP-EXAMPLES-MIB:netSnmpExampleString = STRING: \"random fact\" \t" "NET-SNMP-EXAMPLES-MIB::netSnmpColons = STRING: \"Colossus colons\" \t" "NET-SNMP-EXAMPLES-MIB::::::::::::::::::::::::::Trail = STRING: \"Gary Indiana\" \t" ":NET-SNMP-EXAMPLES::::::::::::::::::::::::::::::MIB: = INTEGER: 1234 \t"; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:52407->[127.0.0.1]:162" }, { ".snmp.NET-SNMP-EXAMPLES-MIB_netSnmpExampleString", "random fact" }, { ".snmp.NET-SNMP-EXAMPLES-MIB_netSnmpColons", "Colossus colons" }, { ".snmp.NET-SNMP-EXAMPLES-MIB_Trail", "Gary Indiana" }, { ".snmp._NET-SNMP-EXAMPLES_MIB_", "1234" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_general_v1_message_without_varbindlist) { const gchar *input = "2017-05-10 13:23:16 localhost [UDP: [127.0.0.1]:53831->[127.0.0.1]:162]: iso.3.6.1.4.1.8072.2.3.1\n" "\t Enterprise Specific Trap (.17) Uptime: 18:41:07.83"; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:53831->[127.0.0.1]:162" }, { ".snmp.enterprise_oid", "iso.3.6.1.4.1.8072.2.3.1" }, { ".snmp.type", "Enterprise Specific Trap" }, { ".snmp.subtype", ".17" }, { ".snmp.uptime", "18:41:07.83" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } Test(snmptrapd_parser, test_snmptrapd_debug_message_with_timestamp) { const gchar *input = "2017-05-19 10:00:00 NET-SNMP version 5.7.3 Stopped.\nStopping snmptrapd"; assert_log_message_dropped(input); } Test(snmptrapd_parser, test_v2_varbindlist_starts_with_tab) { const gchar *input = "2017-05-19 13:37:00 localhost [UDP: [127.0.0.1]:36324->[127.0.0.1]:162]:\n" "\tiso.3.6.1.2.1.1.3.0 = Timeticks: (875496867) 101 days, 7:56:08.67 \t" "iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.8072.2.3.0.1 \t" "iso.3.6.1.4.1.8072.2.3.2.1 = INTEGER: 60"; assert_log_message_dropped(input); } Test(snmptrapd_parser, test_v2_message_with_garbage) { const gchar *input = "2017-05-10 12:46:14 localhost [UDP: [127.0.0.1]:34257->[127.0.0.1]:162]:\n" "iso.3.6.1.2.1.1.3.0 = Timeticks: (875496867) 101 days, 7:56:08.67\t" "iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.8072.2.3.0.1\n" "garbage = stop here"; TestNameValue expected[] = { { ".snmp.hostname", "localhost" }, { ".snmp.transport_info", "UDP: [127.0.0.1]:34257->[127.0.0.1]:162" }, { ".snmp.iso.3.6.1.2.1.1.3.0", "(875496867) 101 days, 7:56:08.67" }, { ".snmp.iso.3.6.1.6.3.1.1.4.1.0", "iso.3.6.1.4.1.8072.2.3.0.1" } }; assert_log_message_name_values(input, expected, SIZE_OF_ARRAY(expected)); } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/tests/test_varbindlist_scanner.c000066400000000000000000000153401450431004300267110ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include #include "varbindlist-scanner.h" #include "apphook.h" #include "scratch-buffers.h" #define SIZE_OF_ARRAY(array) (sizeof(array) / sizeof((array)[0])) typedef struct { const gchar *key; const gchar *type; const gchar *value; } TestVarBind; static void _expect_no_more_tokens(VarBindListScanner *scanner) { cr_expect_not(varbindlist_scanner_scan_next(scanner)); } static void _expect_next_key_type_value(VarBindListScanner *scanner, const gchar *key, const gchar *type, const gchar *value) { cr_expect(varbindlist_scanner_scan_next(scanner)); cr_expect_str_eq(varbindlist_scanner_get_current_key(scanner), key); cr_expect_str_eq(varbindlist_scanner_get_current_type(scanner), type); cr_expect_str_eq(varbindlist_scanner_get_current_value(scanner), value); } static VarBindListScanner * create_scanner(void) { VarBindListScanner *scanner = varbindlist_scanner_new(); return scanner; } static void expect_varbindlist(const gchar *input, TestVarBind *expected, gsize number_of_expected) { VarBindListScanner *scanner = create_scanner(); varbindlist_scanner_input(scanner, input); for (int i=0; i < number_of_expected; i++) _expect_next_key_type_value(scanner, expected[i].key, expected[i].type, expected[i].value); _expect_no_more_tokens(scanner); varbindlist_scanner_free(scanner); } Test(varbindlist_scanner, test_spaces_as_separator) { const gchar *input = "iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.18372.3.2.1.1.2.2 " "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = STRING: \"svc/w4joHeFNzpFNrC8u9umJhc/ssh_4eyes_user_subjects:3/ssh\""; TestVarBind expected[] = { {"iso.3.6.1.6.3.1.1.4.1.0", "OID", "iso.3.6.1.4.1.18372.3.2.1.1.2.2"}, {"iso.3.6.1.4.1.18372.3.2.1.1.1.6", "STRING", "svc/w4joHeFNzpFNrC8u9umJhc/ssh_4eyes_user_subjects:3/ssh"} }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } Test(varbindlist_scanner, test_tabs_and_spaces_as_separator) { const gchar *input = "\t iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.18372.3.2.1.1.2.2\t" "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = STRING: \"svc/w4joHeFNzpFNrC8u9umJhc/ssh_4eyes_user_subjects:3/ssh\"\t\t" "iso.1.2 = INTEGER: 40 \t" "iso.3.4 = INTEGER: 30\t " "iso.5.6 = INTEGER: 20 \t\t " "iso.7.8 = INTEGER: 10"; TestVarBind expected[] = { {"iso.3.6.1.6.3.1.1.4.1.0", "OID", "iso.3.6.1.4.1.18372.3.2.1.1.2.2"}, {"iso.3.6.1.4.1.18372.3.2.1.1.1.6", "STRING", "svc/w4joHeFNzpFNrC8u9umJhc/ssh_4eyes_user_subjects:3/ssh"}, {"iso.1.2", "INTEGER", "40"}, {"iso.3.4", "INTEGER", "30"}, {"iso.5.6", "INTEGER", "20"}, {"iso.7.8", "INTEGER", "10"} }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } Test(varbindlist_scanner, test_key_representations) { const gchar *input = ".1.3.6.1.2.1.1.3.0 = STRING: \"\"\t" "IP-MIB::ipForwarding.0 = INTEGER: 0\t" "sysUpTime.0 = Timeticks: 1:15:09:27.63\t" "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.3.119.101.115 = xxx"; TestVarBind expected[] = { { ".1.3.6.1.2.1.1.3.0", "STRING", "" }, { "IP-MIB::ipForwarding.0", "INTEGER", "0" }, { "sysUpTime.0", "Timeticks", "1:15:09:27.63" }, { "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.3.119.101.115", "", "xxx" } }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } Test(varbindlist_scanner, test_all_varbind_type) { const gchar *input = ".iso.org.dod.internet.mgmt.mib-2.system.sysUpTime.0 = Timeticks: (875496867) 101 days, 7:56:08.67\t" "iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.8072.2.3.0.1\t" "iso.3.6.1.4.1.8072.2.3.2.1 = INTEGER: 60\t" "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.3.119.101.115 = STRING: \"random string\"\t" "iso.3.2.2 = Gauge32: 22\t" "iso.3.1.1 = Counter32: 11123123 \t" "iso.3.5.3 = Hex-STRING: A0 BB CC DD EF\t" "iso.3.8.8 = NULL \t" "iso.2.1.1 = Timeticks: (34234234) 3 days, 23:05:42.34\t" "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.wes = IpAddress: 192.168.1.0"; TestVarBind expected[] = { { ".iso.org.dod.internet.mgmt.mib-2.system.sysUpTime.0", "Timeticks", "(875496867) 101 days, 7:56:08.67" }, { "iso.3.6.1.6.3.1.1.4.1.0", "OID", "iso.3.6.1.4.1.8072.2.3.0.1" }, { "iso.3.6.1.4.1.8072.2.3.2.1", "INTEGER", "60" }, { "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.3.119.101.115", "STRING", "random string" }, { "iso.3.2.2", "Gauge32", "22" }, { "iso.3.1.1", "Counter32", "11123123" }, { "iso.3.5.3", "Hex-STRING", "A0 BB CC DD EF" }, { "iso.3.8.8", "", "NULL" }, { "iso.2.1.1", "Timeticks", "(34234234) 3 days, 23:05:42.34" }, { "SNMP-VIEW-BASED-ACM-MIB::vacmSecurityModel.0.wes", "IpAddress", "192.168.1.0" } }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } Test(varbindlist_scanner, test_separator_inside_of_quoted_value) { const gchar *input = "iso.1.2.3 = STRING: \"quoted = string \t innerkey='innervalue'\" \t" "iso.3.8.8 = NULL\t"; TestVarBind expected[] = { { "iso.1.2.3", "STRING", "quoted = string \t innerkey='innervalue'" }, { "iso.3.8.8", "", "NULL" } }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } Test(varbindlist_scanner, test_multiline_quouted_value) { const gchar *input = "iso.3.6.1.4.1.18372.3.2.1.1.1.6 = STRING: \"multi \n line\r\nvalue\" \t" "iso.3.8.8 = NULL"; TestVarBind expected[] = { { "iso.3.6.1.4.1.18372.3.2.1.1.1.6", "STRING", "multi \n line\r\nvalue" }, { "iso.3.8.8", "", "NULL" } }; expect_varbindlist(input, expected, SIZE_OF_ARRAY(expected)); } static void setup(void) { app_startup(); } static void teardown(void) { scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(varbindlist_scanner, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/afsnmp/varbindlist-scanner.c000066400000000000000000000054231450431004300244270ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "varbindlist-scanner.h" #include "str-utils.h" static inline gboolean _is_valid_key_character(gchar c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '-') || (c == ':'); } static inline void _skip_whitespaces(const gchar **input) { const gchar *current_char = *input; while (*current_char == ' ' || *current_char == '\t') ++current_char; *input = current_char; } static void _extract_type(KVScanner *scanner) { VarBindListScanner *self = (VarBindListScanner *) scanner; const gchar *type_start = &scanner->input[scanner->input_pos]; _skip_whitespaces(&type_start); const gchar *type_end = strpbrk(type_start, ": \t"); gboolean type_exists = type_end && *type_end == ':'; if (!type_exists) { g_string_truncate(self->varbind_type, 0); return; } gsize type_len = type_end - type_start; g_string_assign_len(self->varbind_type, type_start, type_len); scanner->input_pos = type_end - scanner->input + 1; } void varbindlist_scanner_init(VarBindListScanner *self) { memset(self, 0, sizeof(VarBindListScanner)); kv_scanner_init(&self->super, '=', "\t", FALSE); kv_scanner_set_extract_annotation_func(&self->super, _extract_type); kv_scanner_set_valid_key_character_func(&self->super, _is_valid_key_character); kv_scanner_set_stop_character(&self->super, '\n'); self->varbind_type = g_string_sized_new(16); } void varbindlist_scanner_deinit(VarBindListScanner *self) { g_string_free(self->varbind_type, TRUE); kv_scanner_deinit(&self->super); } gboolean varbindlist_scanner_scan_next(VarBindListScanner *self) { return kv_scanner_scan_next(&self->super); } VarBindListScanner * varbindlist_scanner_new(void) { VarBindListScanner *self = g_new(VarBindListScanner, 1); varbindlist_scanner_init(self); return self; } syslog-ng-syslog-ng-4.4.0/modules/afsnmp/varbindlist-scanner.h000066400000000000000000000040561450431004300244350ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef VARBINDLIST_SCANNER_H_INCLUDED #define VARBINDLIST_SCANNER_H_INCLUDED #include "scanner/kv-scanner/kv-scanner.h" typedef struct _VarBindListScanner VarBindListScanner; struct _VarBindListScanner { KVScanner super; GString *varbind_type; }; static inline void varbindlist_scanner_input(VarBindListScanner *self, const gchar *input) { kv_scanner_input(&self->super, input); } static inline const gchar * varbindlist_scanner_get_current_key(VarBindListScanner *self) { return kv_scanner_get_current_key(&self->super); } static inline const gchar * varbindlist_scanner_get_current_type(VarBindListScanner *self) { return self->varbind_type->str; } static inline const gchar * varbindlist_scanner_get_current_value(VarBindListScanner *self) { return kv_scanner_get_current_value(&self->super); } gboolean varbindlist_scanner_scan_next(VarBindListScanner *self); VarBindListScanner *varbindlist_scanner_new(void); void varbindlist_scanner_init(VarBindListScanner *self); void varbindlist_scanner_deinit(VarBindListScanner *self); static inline void varbindlist_scanner_free(VarBindListScanner *self) { varbindlist_scanner_deinit(self); g_free(self); } #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/000077500000000000000000000000001450431004300206225ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsocket/CMakeLists.txt000066400000000000000000000025761450431004300233740ustar00rootroot00000000000000set(AFSOCKET_SOURCES afsocket.c afsocket.h afsocket-source.c afsocket-source.h afsocket-dest.c afsocket-dest.h afsocket-signals.h socket-options.c socket-options.h transport-mapper.c transport-mapper.h afinet.c afinet.h afinet-source.c afinet-source.h afinet-dest-failover.c afinet-dest-failover.h afinet-dest.c afinet-dest.h socket-options-inet.c socket-options-inet.h transport-mapper-inet.c transport-mapper-inet.h afunix-source.c afunix-source.h afunix-dest.c afunix-dest.h transport-mapper-unix.c transport-mapper-unix.h socket-options-unix.c socket-options-unix.h transport-unix-socket.c transport-unix-socket.h compat-unix-creds.c compat-unix-creds.h afsocket-grammar.y afsocket-parser.c afsocket-parser.h afsocket-plugin.c systemd-syslog-source.h systemd-syslog-source.c afsocket-systemd-override.h ) find_package(ZLIB REQUIRED) find_package(systemd) add_module( TARGET afsocket GRAMMAR afsocket-grammar INCLUDES ${ZLIB_INCLUDE_DIRS} ${WRAP_INCLUDE_DIRS} ${Libsystemd_INCLUDE_DIRS} DEPENDS ${WRAP_LIBRARIES} ${ZLIB_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto libnet ${Libsystemd_LIBRARIES} SOURCES ${AFSOCKET_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/afsocket/Makefile.am000066400000000000000000000052271450431004300226640ustar00rootroot00000000000000modules_afsocket_libafsocket_la_SOURCES = \ modules/afsocket/afsocket.c \ modules/afsocket/afsocket.h \ modules/afsocket/afsocket-source.c \ modules/afsocket/afsocket-source.h \ modules/afsocket/afsocket-dest.c \ modules/afsocket/afsocket-dest.h \ modules/afsocket/afsocket-signals.h \ modules/afsocket/socket-options.c \ modules/afsocket/socket-options.h \ modules/afsocket/transport-mapper.c \ modules/afsocket/transport-mapper.h \ modules/afsocket/afinet.c \ modules/afsocket/afinet.h \ modules/afsocket/afinet-source.c \ modules/afsocket/afinet-source.h \ modules/afsocket/afinet-dest.c \ modules/afsocket/afinet-dest.h \ modules/afsocket/afinet-dest-failover.c \ modules/afsocket/afinet-dest-failover.h \ modules/afsocket/socket-options-inet.c \ modules/afsocket/socket-options-inet.h \ modules/afsocket/socket-options-unix.c \ modules/afsocket/socket-options-unix.h \ modules/afsocket/transport-mapper-inet.c \ modules/afsocket/transport-mapper-inet.h \ modules/afsocket/afunix-source.c \ modules/afsocket/afunix-source.h \ modules/afsocket/afunix-dest.c \ modules/afsocket/afunix-dest.h \ modules/afsocket/transport-mapper-unix.c \ modules/afsocket/transport-mapper-unix.h \ modules/afsocket/transport-unix-socket.c \ modules/afsocket/transport-unix-socket.h \ modules/afsocket/compat-unix-creds.c \ modules/afsocket/compat-unix-creds.h \ modules/afsocket/afsocket-grammar.y \ modules/afsocket/afsocket-parser.c \ modules/afsocket/afsocket-parser.h \ modules/afsocket/afsocket-plugin.c \ modules/afsocket/systemd-syslog-source.h \ modules/afsocket/systemd-syslog-source.c \ modules/afsocket/afsocket-systemd-override.h module_LTLIBRARIES += modules/afsocket/libafsocket.la modules_afsocket_libafsocket_la_CPPFLAGS = \ $(AM_CPPFLAGS) $(libsystemd_CFLAGS) \ -I${top_srcdir}/modules/afsocket \ -I${top_builddir}/modules/afsocket modules_afsocket_libafsocket_la_LIBADD = \ $(MODULE_DEPS_LIBS) $(OPENSSL_LIBS) \ $(ZLIB_LIBS) $(LIBNET_LIBS) \ $(LIBWRAP_LIBS) $(libsystemd_LIBS) modules_afsocket_libafsocket_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) modules_afsocket_libafsocket_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules/afsocket modules/afsocket/ mod-afsocket mod-socket: \ modules/afsocket/libafsocket.la BUILT_SOURCES += \ modules/afsocket/afsocket-grammar.y \ modules/afsocket/afsocket-grammar.c \ modules/afsocket/afsocket-grammar.h EXTRA_DIST += \ modules/afsocket/afsocket-grammar.ym \ modules/afsocket/CMakeLists.txt CLEANFILES += \ modules/afsocket/libafsocket.la .PHONY: modules/afsocket/ mod-afsocket mod-socket include modules/afsocket/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-dest-failover.c000066400000000000000000000306101450431004300247760ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinet-dest-failover.h" #include "messages.h" #include "afinet.h" #include "timeutils/misc.h" #include struct _AFInetDestDriverFailover { gboolean initialized; GList *servers; GList *current_server; GSockAddr *primary_addr; GSockAddr *bind_addr; guint probe_interval; guint probes_required; guint probes_received; struct iv_timer timer; struct iv_fd fd; LogExprNode *owner_expression; FailoverTransportMapper failover_transport_mapper; gpointer on_primary_available_cookie; AFInetOnPrimaryAvailable on_primary_available_func; }; static const int TCP_PROBE_INTERVAL_DEFAULT = 60; static const int SUCCESSFUL_PROBES_REQUIRED_DEFAULT = 3; void afinet_dd_failover_set_tcp_probe_interval(AFInetDestDriverFailover *self, gint tcp_probe_interval) { self->probe_interval = tcp_probe_interval; } void afinet_dd_failover_set_successful_probes_required(AFInetDestDriverFailover *self, gint successful_probes_required) { self->probes_required = successful_probes_required; } static GList * _primary(AFInetDestDriverFailover *self) { return g_list_first(self->servers); } static void _hand_over_connection_to_afsocket(AFInetDestDriverFailover *self) { self->probes_received = 0; self->current_server = _primary(self); self->on_primary_available_func(self->on_primary_available_cookie, self->fd.fd, self->primary_addr); self->primary_addr = NULL; self->fd.fd = -1; } static void _start_failback_timer(AFInetDestDriverFailover *self) { glong elapsed_time; iv_validate_now(); elapsed_time = timespec_diff_msec(&iv_now, &(self->timer.expires)); self->timer.expires = iv_now; if (elapsed_time < (self->probe_interval*1000L)) { timespec_add_msec(&self->timer.expires, (self->probe_interval*1000L - elapsed_time)); } iv_timer_register(&self->timer); } static void _tcp_probe_succeeded(AFInetDestDriverFailover *self) { self->probes_received++; msg_notice("Probing primary server successful", evt_tag_int("successful-probes-received", self->probes_received), evt_tag_int("successful-probes-required", self->probes_required)); if (self->probes_received >= self->probes_required) { msg_notice("Primary server seems to be stable, reconnecting to primary server"); _hand_over_connection_to_afsocket(self); } else { close(self->fd.fd); _start_failback_timer(self); } } static void _tcp_probe_failed(AFInetDestDriverFailover *self) { self->probes_received = 0; _start_failback_timer(self); } static gboolean _socket_succeeded(AFInetDestDriverFailover *self) { int error = 0; socklen_t errorlen = sizeof(error); gchar buf[MAX_SOCKADDR_STRING]; if (getsockopt(self->fd.fd, SOL_SOCKET, SO_ERROR, &error, &errorlen) == -1) { msg_error("getsockopt(SOL_SOCKET, SO_ERROR) failed for connecting socket", evt_tag_int("fd", self->fd.fd), evt_tag_str("server", g_sockaddr_format(self->primary_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } if (error) { msg_error("Connection towards primary server failed", evt_tag_int("fd", self->fd.fd), evt_tag_str("server", g_sockaddr_format(self->primary_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_errno(EVT_TAG_OSERROR, error)); close(self->fd.fd); return FALSE; } return TRUE; } static void _handle_tcp_probe_socket(gpointer s) { AFInetDestDriverFailover *self = (AFInetDestDriverFailover *) s; if (iv_fd_registered(&self->fd)) iv_fd_unregister(&self->fd); if (_socket_succeeded(self)) _tcp_probe_succeeded(self); else _tcp_probe_failed(self); } static gboolean _connect_normal(GIOStatus iostatus) { return G_IO_STATUS_NORMAL == iostatus; } static gboolean _connect_in_progress(GIOStatus iostatus) { return G_IO_STATUS_ERROR == iostatus && EINPROGRESS == errno; } static void _tcp_probe_primary_server(AFInetDestDriverFailover *self) { GIOStatus iostatus = g_connect(self->fd.fd, self->primary_addr); if (_connect_normal(iostatus)) { msg_notice("Successfully connected to primary"); _tcp_probe_succeeded(self); return; } if (_connect_in_progress(iostatus)) { iv_fd_register(&self->fd); return; } gchar buf[MAX_SOCKADDR_STRING]; msg_error("Connection towards primary server failed", evt_tag_int("fd", self->fd.fd), evt_tag_str("server", g_sockaddr_format(self->primary_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_error(EVT_TAG_OSERROR)); close(self->fd.fd); _tcp_probe_failed(self); } static const gchar * _get_hostname(GList *l) { return (const gchar *)(l->data); } static GSockAddr * _resolve_hostname_with_transport_mapper(TransportMapper *transport_mapper, const gchar *hostname, const gchar *service) { GSockAddr *addr = NULL; if (!resolve_hostname_to_sockaddr(&addr, transport_mapper->address_family, hostname)) { msg_warning("Unable to resolve the address of the primary server", evt_tag_str("address", hostname)); return NULL; } if (service) g_sockaddr_set_port(addr, afinet_determine_port(transport_mapper, service)); return addr; } static gboolean _resolve_bind_addr(AFInetDestDriverFailover *self) { g_sockaddr_unref(self->bind_addr); self->bind_addr = _resolve_hostname_with_transport_mapper(self->failover_transport_mapper.transport_mapper, self->failover_transport_mapper.bind_ip, self->failover_transport_mapper.bind_port); return self->bind_addr != NULL; } static gboolean _resolve_primary_address(AFInetDestDriverFailover *self) { g_sockaddr_unref(self->primary_addr); self->primary_addr = _resolve_hostname_with_transport_mapper(self->failover_transport_mapper.transport_mapper, _get_hostname(_primary(self)), self->failover_transport_mapper.dest_port); return self->primary_addr != NULL; } static gboolean _setup_failback_fd(AFInetDestDriverFailover *self) { if (!transport_mapper_open_socket(self->failover_transport_mapper.transport_mapper, self->failover_transport_mapper.socket_options, self->bind_addr, self->primary_addr, AFSOCKET_DIR_SEND, &self->fd.fd)) { msg_error("Error creating socket for tcp-probe the primary server", evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } return TRUE; } static void _failback_timer_elapsed(void *cookie) { AFInetDestDriverFailover *self = (AFInetDestDriverFailover *) cookie; msg_notice("Probing the primary server.", evt_tag_int("tcp-probe-interval", self->probe_interval)); iv_validate_now(); self->timer.expires = iv_now; // register starting time, required for "elapsed_time" if (!_resolve_bind_addr(self)) { _tcp_probe_failed(self); return; } if (!_resolve_primary_address(self)) { _tcp_probe_failed(self); return; } if (!_setup_failback_fd(self)) { _tcp_probe_failed(self); return; } _tcp_probe_primary_server(self); } static gboolean _is_failback_enabled(AFInetDestDriverFailover *self) { return self->on_primary_available_func != NULL; } static void _init_current_server(AFInetDestDriverFailover *self ) { self->current_server = _is_failback_enabled(self) ? g_list_next(_primary(self)) : _primary(self); if (_primary(self) == self->current_server) { msg_warning("Last failover server reached, trying the original host again", evt_tag_str("host", _get_hostname(self->current_server)), log_expr_node_location_tag(self->owner_expression)); } else { msg_warning("Last failover server reached, trying the first failover again", evt_tag_str("next_failover_server", _get_hostname(self->current_server)), log_expr_node_location_tag(self->owner_expression)); } } static void _step_current_server_iterator(AFInetDestDriverFailover *self) { GList *previous = self->current_server; self->current_server = g_list_next(self->current_server); if (!self->current_server) { _init_current_server(self); return; } if (_is_failback_enabled(self) && _primary(self) == previous) { _start_failback_timer(self); msg_warning("Current primary server is inaccessible, sending the messages to the next failover server", evt_tag_str("next_failover_server", _get_hostname(self->current_server)), log_expr_node_location_tag(self->owner_expression)); return; } msg_warning("Current failover server is inaccessible, sending the messages to the next failover server", evt_tag_str("next_failover_server", _get_hostname(self->current_server)), log_expr_node_location_tag(self->owner_expression)); } const gchar * afinet_dd_failover_get_hostname(AFInetDestDriverFailover *self) { if (self->current_server == NULL) { return _get_hostname(_primary(self)); } return _get_hostname(self->current_server); } void afinet_dd_failover_next(AFInetDestDriverFailover *self) { if (!self->initialized) return; if (!self->current_server) { self->current_server = _primary(self); return; } _step_current_server_iterator(self); } void afinet_dd_failover_add_servers(AFInetDestDriverFailover *self, GList *failovers) { self->servers = g_list_concat(self->servers, failovers); } void afinet_dd_failover_enable_failback(AFInetDestDriverFailover *self, gpointer cookie, AFInetOnPrimaryAvailable callback_function) { self->on_primary_available_cookie = cookie; self->on_primary_available_func = callback_function; } static void _init_failback_handlers(AFInetDestDriverFailover *self) { IV_TIMER_INIT(&self->timer); self->timer.cookie = self; self->timer.handler = _failback_timer_elapsed; IV_FD_INIT(&self->fd); self->fd.cookie = self; self->fd.handler_out = (void (*)(void *)) _handle_tcp_probe_socket; } static void _deinit_failback_handlers(AFInetDestDriverFailover *self) { if (iv_timer_registered(&self->timer)) iv_timer_unregister(&self->timer); if (iv_fd_registered(&self->fd)) { iv_fd_unregister(&self->fd); close(self->fd.fd); } } void afinet_dd_failover_deinit(AFInetDestDriverFailover *self) { _deinit_failback_handlers(self); } void afinet_dd_failover_init(AFInetDestDriverFailover *self, LogExprNode *owner_expr, FailoverTransportMapper *failover_transport_mapper) { self->owner_expression = owner_expr; self->failover_transport_mapper = *failover_transport_mapper; self->current_server = NULL; _init_failback_handlers(self); self->initialized = TRUE; } AFInetDestDriverFailover * afinet_dd_failover_new(const gchar *primary) { AFInetDestDriverFailover *self = g_new0(AFInetDestDriverFailover, 1); self->probe_interval = TCP_PROBE_INTERVAL_DEFAULT; self->probes_required = SUCCESSFUL_PROBES_REQUIRED_DEFAULT; self->servers = g_list_append(NULL, g_strdup(primary)); self->current_server = g_list_first(self->servers); return self; } void afinet_dd_failover_free(AFInetDestDriverFailover *self) { if (!self) return; g_list_free_full(self->servers, g_free); g_sockaddr_unref(self->primary_addr); g_sockaddr_unref(self->bind_addr); g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-dest-failover.h000066400000000000000000000046261450431004300250130ustar00rootroot00000000000000/* * Copyright (c) 2002-2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFINET_DEST_FAILOVER_H_INCLUDED #define AFINET_DEST_FAILOVER_H_INCLUDED #include "syslog-ng.h" #include "gsocket.h" #include "transport-mapper-inet.h" #include "cfg.h" typedef struct _AFInetDestDriverFailover AFInetDestDriverFailover; typedef void (*AFInetOnPrimaryAvailable)(gpointer cookie, gint fd, GSockAddr *addr); typedef struct _FailoverTransportMapper { TransportMapper *transport_mapper; SocketOptions *socket_options; const gchar *dest_port; const gchar *bind_ip; const gchar *bind_port; } FailoverTransportMapper; AFInetDestDriverFailover *afinet_dd_failover_new(const gchar *primary); void afinet_dd_failover_init(AFInetDestDriverFailover *self, LogExprNode *owner_expr, FailoverTransportMapper *failover_transport_mapper); void afinet_dd_failover_deinit(AFInetDestDriverFailover *self); void afinet_dd_failover_free(AFInetDestDriverFailover *self); void afinet_dd_failover_enable_failback(AFInetDestDriverFailover *self, gpointer cookie, AFInetOnPrimaryAvailable callback); void afinet_dd_failover_add_servers(AFInetDestDriverFailover *self, GList *failovers); void afinet_dd_failover_set_tcp_probe_interval(AFInetDestDriverFailover *self, gint tcp_probe_interval); void afinet_dd_failover_set_successful_probes_required(AFInetDestDriverFailover *self, gint successful_probes_required); void afinet_dd_failover_next(AFInetDestDriverFailover *self); const gchar *afinet_dd_failover_get_hostname(AFInetDestDriverFailover *self); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-dest.c000066400000000000000000000527701450431004300232040ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinet-dest.h" #include "transport-mapper-inet.h" #include "socket-options-inet.h" #include "messages.h" #include "gprocess.h" #include "compat/openssl_support.h" #include "afsocket-signals.h" #include #include #include #include #include #include #include #ifdef _GNU_SOURCE # define _GNU_SOURCE_DEFINED 1 # undef _GNU_SOURCE #endif #if SYSLOG_NG_ENABLE_SPOOF_SOURCE #include #endif #if _GNU_SOURCE_DEFINED # undef _GNU_SOURCE # define _GNU_SOURCE 1 #endif static const gint MAX_UDP_PAYLOAD_SIZE = 65507; typedef struct _AFInetDestDriverTLSVerifyData { TLSContext *tls_context; gchar *hostname; SignalSlotConnector *signal_connector; } AFInetDestDriverTLSVerifyData; void afinet_dd_set_localip(LogDriver *s, gchar *ip) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (self->bind_ip) g_free(self->bind_ip); self->bind_ip = g_strdup(ip); } void afinet_dd_set_localport(LogDriver *s, gchar *service) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (self->bind_port) g_free(self->bind_port); self->bind_port = g_strdup(service); } void afinet_dd_set_destport(LogDriver *s, gchar *service) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (self->dest_port) g_free(self->dest_port); self->dest_port = g_strdup(service); } void afinet_dd_set_spoof_source(LogDriver *s, gboolean enable) { #if SYSLOG_NG_ENABLE_SPOOF_SOURCE AFInetDestDriver *self = (AFInetDestDriver *) s; self->spoof_source = enable; #else msg_error("Error enabling spoof-source, you need to compile syslog-ng with --enable-spoof-source"); #endif } void afinet_dd_set_spoof_source_max_msglen(LogDriver *s, guint max_msglen) { #if SYSLOG_NG_ENABLE_SPOOF_SOURCE AFInetDestDriver *self = (AFInetDestDriver *) s; gint af_max_dgram_size = 0; /* maximum ip datagram is 65535, minus IP + UDP header */ switch (self->super.transport_mapper->address_family) { case AF_INET6: af_max_dgram_size = 65535 - 40 - 8; break; case AF_INET: af_max_dgram_size = 65535 - 20 - 8; break; default: g_assert_not_reached(); } if (max_msglen > af_max_dgram_size) { msg_warning("spoof-source-max-msglen() value is too large, limiting to the maximum value", evt_tag_int("value", max_msglen), evt_tag_int("maximum", af_max_dgram_size)); max_msglen = af_max_dgram_size; } self->spoof_source_max_msglen = max_msglen; #endif } static gint afinet_dd_verify_callback(gint ok, X509_STORE_CTX *ctx, gpointer user_data) { AFInetDestDriverTLSVerifyData *self G_GNUC_UNUSED = (AFInetDestDriverTLSVerifyData *) user_data; X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx); X509 *cert = X509_STORE_CTX_get0_cert(ctx); if (ok && current_cert == cert) { ok = tls_context_verify_peer(self->tls_context, cert, self->hostname); if (ok) { AFSocketTLSCertificateValidationSignalData signal_data = {0}; signal_data.ctx = ctx; signal_data.tls_context = self->tls_context; EMIT(self->signal_connector, signal_afsocket_tls_certificate_validation, &signal_data); ok = !signal_data.failure; } } return ok; } static AFInetDestDriverTLSVerifyData * afinet_dd_tls_verify_data_new(TLSContext *ctx, const gchar *hostname, SignalSlotConnector *signal_connector) { AFInetDestDriverTLSVerifyData *self = g_new0(AFInetDestDriverTLSVerifyData, 1); self->tls_context = tls_context_ref(ctx); self->hostname = g_strdup(hostname); self->signal_connector = signal_connector; return self; } static void afinet_dd_tls_verify_data_free(gpointer s) { AFInetDestDriverTLSVerifyData *self = (AFInetDestDriverTLSVerifyData *)s; g_assert(self); if (self) { tls_context_unref(self->tls_context); g_free(self->hostname); g_free(self); } } static gboolean _is_tls_used(const AFInetDestDriver *self) { TransportMapperInet *transport_mapper_inet = (TransportMapperInet *) self->super.transport_mapper; return transport_mapper_inet->tls_context != NULL; } static gboolean _is_failover_used(const AFInetDestDriver *self) { return self->failover != NULL; } static const gchar * _afinet_dd_get_hostname(const AFInetDestDriver *self) { if (!_is_failover_used(self)) return self->primary; return afinet_dd_failover_get_hostname(self->failover); } void afinet_dd_set_tls_context(LogDriver *s, TLSContext *tls_context) { AFInetDestDriver *self = (AFInetDestDriver *) s; transport_mapper_inet_set_tls_context((TransportMapperInet *) self->super.transport_mapper, tls_context); } void afinet_dd_setup_tls_verifier(AFInetDestDriver *self) { TransportMapperInet *transport_mapper_inet = (TransportMapperInet *) self->super.transport_mapper; AFInetDestDriverTLSVerifyData *verify_data; verify_data = afinet_dd_tls_verify_data_new(transport_mapper_inet->tls_context, _afinet_dd_get_hostname(self), self->super.super.super.super.signal_slot_connector); TLSVerifier *verifier = tls_verifier_new(afinet_dd_verify_callback, verify_data, afinet_dd_tls_verify_data_free); transport_mapper_inet_set_tls_verifier(transport_mapper_inet, verifier); } void afinet_dd_enable_failover(LogDriver *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (self->failover) return; self->failover = afinet_dd_failover_new(self->primary); } void afinet_dd_add_failovers(LogDriver *s, GList *failovers) { AFInetDestDriver *self = (AFInetDestDriver *)s; g_assert(self->failover != NULL); afinet_dd_failover_add_servers(self->failover, failovers); } void afinet_dd_fail_back_to_primary(gpointer s, gint fd, GSockAddr *saddr) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (_is_tls_used(self)) afinet_dd_setup_tls_verifier(self); afsocket_dd_connected_with_fd(s, fd, saddr); } void afinet_dd_enable_failback(LogDriver *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; g_assert(self->failover != NULL); afinet_dd_failover_enable_failback(self->failover, &self->super, afinet_dd_fail_back_to_primary); } void afinet_dd_set_failback_tcp_probe_interval(LogDriver *s, gint tcp_probe_interval) { AFInetDestDriver *self = (AFInetDestDriver *) s; afinet_dd_failover_set_tcp_probe_interval(self->failover, tcp_probe_interval); } void afinet_dd_set_failback_successful_probes_required(LogDriver *s, gint successful_probes_required) { AFInetDestDriver *self = (AFInetDestDriver *) s; afinet_dd_failover_set_successful_probes_required(self->failover, successful_probes_required); } static void _disable_connection_closure_on_input(LogWriter *writer) { /* SSL is duplex, so we can certainly expect input from the server, which * would cause the LogWriter to close this connection. In a better world * LW_DETECT_EOF would be implemented by the LogProto class and would * inherently work w/o mockery in LogWriter. Defer that change for now * (and possibly for all eternity :) */ log_writer_set_flags(writer, log_writer_get_flags(writer) & ~LW_DETECT_EOF); } static LogWriter * afinet_dd_construct_writer(AFSocketDestDriver *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; TransportMapperInet *transport_mapper_inet = ((TransportMapperInet *) (self->super.transport_mapper)); LogWriter *writer = afsocket_dd_construct_writer_method(s); if (((self->super.transport_mapper->sock_type == SOCK_STREAM) && transport_mapper_inet->tls_context)) _disable_connection_closure_on_input(writer); return writer; } static gint _determine_port(const AFInetDestDriver *self) { return afinet_determine_port(self->super.transport_mapper, self->dest_port); } static gboolean _setup_bind_addr(AFInetDestDriver *self) { g_sockaddr_unref(self->super.bind_addr); self->super.bind_addr = NULL; if (!resolve_hostname_to_sockaddr(&self->super.bind_addr, self->super.transport_mapper->address_family, self->bind_ip)) return FALSE; if (self->bind_port) g_sockaddr_set_port(self->super.bind_addr, afinet_lookup_service(self->super.transport_mapper, self->bind_port)); return TRUE; } static gboolean _already_connected_to_destination(AFInetDestDriver *self) { return log_writer_opened(self->super.writer); } static gboolean _setup_dest_addr(AFInetDestDriver *self) { if (_already_connected_to_destination(self)) return TRUE; g_sockaddr_unref(self->super.dest_addr); self->super.dest_addr = NULL; if (!resolve_hostname_to_sockaddr(&self->super.dest_addr, self->super.transport_mapper->address_family, _afinet_dd_get_hostname(self))) return FALSE; if (!self->dest_port) { const gchar *port_change_warning = transport_mapper_inet_get_port_change_warning(self->super.transport_mapper); if (port_change_warning) { msg_warning(port_change_warning, evt_tag_str("id", self->super.super.super.id)); } } g_sockaddr_set_port(self->super.dest_addr, _determine_port(self)); return TRUE; } static gboolean afinet_dd_setup_addresses(AFSocketDestDriver *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (!afsocket_dd_setup_addresses_method(s)) return FALSE; if (self->super.proto_factory->default_inet_port) transport_mapper_inet_set_server_port(self->super.transport_mapper, self->super.proto_factory->default_inet_port); if (!_setup_bind_addr(self)) return FALSE; if (_is_failover_used(self)) afinet_dd_failover_next(self->failover); if (_is_tls_used(self)) afinet_dd_setup_tls_verifier(self); if (!_setup_dest_addr(self)) return FALSE; iv_invalidate_now(); return TRUE; } static const gchar * afinet_dd_get_dest_name(const AFSocketDestDriver *s) { const AFInetDestDriver *self = (const AFInetDestDriver *)s; static gchar buf[256]; const gchar *hostname = _afinet_dd_get_hostname(self); if (strchr(hostname, ':') != NULL) g_snprintf(buf, sizeof(buf), "[%s]:%d", hostname, _determine_port(self)); else g_snprintf(buf, sizeof(buf), "%s:%d", hostname, _determine_port(self)); return buf; } static inline void _libnet_destroy_when_spoof_source_enabled(AFInetDestDriver *self) { #if SYSLOG_NG_ENABLE_SPOOF_SOURCE if (self->lnet_ctx) libnet_destroy(self->lnet_ctx); #endif } static gboolean afinet_dd_deinit(LogPipe *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; if (_is_failover_used(self)) afinet_dd_failover_deinit(self->failover); _libnet_destroy_when_spoof_source_enabled(self); return afsocket_dd_deinit(s); } static gboolean afinet_dd_init(LogPipe *s) { AFInetDestDriver *self G_GNUC_UNUSED = (AFInetDestDriver *) s; #if SYSLOG_NG_ENABLE_SPOOF_SOURCE if (self->spoof_source) self->super.connections_kept_alive_across_reloads = TRUE; #endif if (!afsocket_dd_init(s)) return FALSE; #if SYSLOG_NG_ENABLE_SPOOF_SOURCE if (self->super.transport_mapper->sock_type == SOCK_DGRAM) { if (self->spoof_source && !self->lnet_ctx) { gchar error[LIBNET_ERRBUF_SIZE]; cap_t saved_caps; saved_caps = g_process_cap_save(); g_process_enable_cap("cap_net_raw"); self->lnet_ctx = libnet_init(self->super.bind_addr->sa.sa_family == AF_INET ? LIBNET_RAW4 : LIBNET_RAW6, NULL, error); g_process_cap_restore(saved_caps); if (!self->lnet_ctx) { msg_error("Error initializing raw socket, spoof-source support disabled", evt_tag_str("error", error)); } } } #endif if (self->super.transport_mapper->sock_type == SOCK_DGRAM) { if (self->super.writer_options.truncate_size == -1) { self->super.writer_options.truncate_size = MAX_UDP_PAYLOAD_SIZE; } } if (_is_failover_used(self)) { FailoverTransportMapper ftm = { .transport_mapper = self->super.transport_mapper, .socket_options = self->super.socket_options, .dest_port = self->dest_port, .bind_ip = self->bind_ip, .bind_port = self->bind_port }; afinet_dd_failover_init(self->failover, s->expr_node, &ftm); } return TRUE; } #if SYSLOG_NG_ENABLE_SPOOF_SOURCE static gboolean afinet_dd_construct_ipv4_packet(AFInetDestDriver *self, LogMessage *msg, GString *msg_line) { libnet_ptag_t ip, udp; struct sockaddr_in *src, *dst; if (msg->saddr->sa.sa_family != AF_INET) return FALSE; src = (struct sockaddr_in *) &msg->saddr->sa; dst = (struct sockaddr_in *) &self->super.dest_addr->sa; libnet_clear_packet(self->lnet_ctx); udp = libnet_build_udp(ntohs(src->sin_port), ntohs(dst->sin_port), LIBNET_UDP_H + msg_line->len, 0, (guchar *) msg_line->str, msg_line->len, self->lnet_ctx, 0); if (udp == -1) return FALSE; ip = libnet_build_ipv4(LIBNET_IPV4_H + msg_line->len + LIBNET_UDP_H, IPTOS_LOWDELAY, /* IP tos */ 0, /* IP ID */ 0, /* frag stuff */ 64, /* TTL */ IPPROTO_UDP, /* transport protocol */ 0, src->sin_addr.s_addr, /* source IP */ dst->sin_addr.s_addr, /* destination IP */ NULL, /* payload (none) */ 0, /* payload length */ self->lnet_ctx, 0); if (ip == -1) return FALSE; return TRUE; } #if SYSLOG_NG_ENABLE_IPV6 static gboolean afinet_dd_construct_ipv6_packet(AFInetDestDriver *self, LogMessage *msg, GString *msg_line) { libnet_ptag_t ip, udp; struct sockaddr_in *src4; struct sockaddr_in6 src, *dst; struct libnet_in6_addr ln_src, ln_dst; switch (msg->saddr->sa.sa_family) { case AF_INET: src4 = (struct sockaddr_in *) &msg->saddr->sa; memset(&src, 0, sizeof(src)); src.sin6_family = AF_INET6; src.sin6_port = src4->sin_port; ((guint32 *) &src.sin6_addr)[0] = 0; ((guint32 *) &src.sin6_addr)[1] = 0; ((guint32 *) &src.sin6_addr)[2] = htonl(0xffff); ((guint32 *) &src.sin6_addr)[3] = src4->sin_addr.s_addr; break; case AF_INET6: src = *((struct sockaddr_in6 *) &msg->saddr->sa); break; default: g_assert_not_reached(); break; } dst = (struct sockaddr_in6 *) &self->super.dest_addr->sa; libnet_clear_packet(self->lnet_ctx); udp = libnet_build_udp(ntohs(src.sin6_port), ntohs(dst->sin6_port), LIBNET_UDP_H + msg_line->len, 0, (guchar *) msg_line->str, msg_line->len, self->lnet_ctx, 0); if (udp == -1) return FALSE; memcpy(&ln_src, &src.sin6_addr, sizeof(ln_src)); memcpy(&ln_dst, &dst->sin6_addr, sizeof(ln_dst)); ip = libnet_build_ipv6(0, 0, LIBNET_UDP_H + msg_line->len, IPPROTO_UDP, /* IPv6 next header */ 64, /* hop limit */ ln_src, ln_dst, NULL, 0, /* payload and its length */ self->lnet_ctx, 0); if (ip == -1) return FALSE; return TRUE; } #endif static inline gboolean afinet_dd_construct_ip_packet(AFInetDestDriver *self, LogMessage *msg, GString *msg_line) { switch (self->super.dest_addr->sa.sa_family) { case AF_INET: return afinet_dd_construct_ipv4_packet(self, msg, msg_line); #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: return afinet_dd_construct_ipv6_packet(self, msg, msg_line); #endif default: g_assert_not_reached(); } return FALSE; } static gboolean afinet_dd_spoof_write_message(AFInetDestDriver *self, LogMessage *msg, const LogPathOptions *path_options) { g_assert(self->super.transport_mapper->sock_type == SOCK_DGRAM); g_mutex_lock(&self->lnet_lock); if (!self->lnet_buffer) self->lnet_buffer = g_string_sized_new(self->spoof_source_max_msglen); log_writer_format_log(self->super.writer, msg, self->lnet_buffer); if (self->lnet_buffer->len > self->spoof_source_max_msglen) g_string_truncate(self->lnet_buffer, self->spoof_source_max_msglen); gboolean success = afinet_dd_construct_ip_packet(self, msg, self->lnet_buffer); if (!success) goto finish; success = libnet_write(self->lnet_ctx) >= 0; if (!success) { msg_error("Error sending raw frame", evt_tag_str("error", libnet_geterror(self->lnet_ctx))); goto finish; } /* we have finished processing msg */ log_msg_ack(msg, path_options, AT_PROCESSED); log_msg_unref(msg); finish: g_mutex_unlock(&self->lnet_lock); return success; } static inline gboolean _is_message_spoofable(LogMessage *msg) { return msg->saddr && (msg->saddr->sa.sa_family == AF_INET || msg->saddr->sa.sa_family == AF_INET6); } static inline gboolean _is_spoof_source_enabled(AFInetDestDriver *self) { return self->spoof_source && self->lnet_ctx; } #endif static void afinet_dd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { #if SYSLOG_NG_ENABLE_SPOOF_SOURCE AFInetDestDriver *self = (AFInetDestDriver *) s; /* NOTE: This code should probably be moved to the LogProto layer so that * spoofed packets are also going through the LogWriter queue */ if (_is_spoof_source_enabled(self) && _is_message_spoofable(msg) && log_writer_opened(self->super.writer)) { if (afinet_dd_spoof_write_message(self, msg, path_options)) return; } #endif log_dest_driver_queue_method(s, msg, path_options); } void afinet_dd_free(LogPipe *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; g_free(self->primary); afinet_dd_failover_free(self->failover); g_free(self->bind_ip); g_free(self->bind_port); g_free(self->dest_port); #if SYSLOG_NG_ENABLE_SPOOF_SOURCE if (self->lnet_buffer) g_string_free(self->lnet_buffer, TRUE); g_mutex_clear(&self->lnet_lock); #endif afsocket_dd_free(s); } static AFInetDestDriver * afinet_dd_new_instance(TransportMapper *transport_mapper, gchar *hostname, GlobalConfig *cfg) { AFInetDestDriver *self = g_new0(AFInetDestDriver, 1); afsocket_dd_init_instance(&self->super, socket_options_inet_new(), transport_mapper, cfg); self->super.super.super.super.init = afinet_dd_init; self->super.super.super.super.deinit = afinet_dd_deinit; self->super.super.super.super.queue = afinet_dd_queue; self->super.super.super.super.free_fn = afinet_dd_free; self->super.construct_writer = afinet_dd_construct_writer; self->super.setup_addresses = afinet_dd_setup_addresses; self->super.get_dest_name = afinet_dd_get_dest_name; self->primary = g_strdup(hostname); #if SYSLOG_NG_ENABLE_SPOOF_SOURCE g_mutex_init(&self->lnet_lock); self->spoof_source_max_msglen = 1024; #endif return self; } AFInetDestDriver * afinet_dd_new_tcp(gchar *host, GlobalConfig *cfg) { return afinet_dd_new_instance(transport_mapper_tcp_new(), host, cfg); } AFInetDestDriver * afinet_dd_new_tcp6(gchar *host, GlobalConfig *cfg) { return afinet_dd_new_instance(transport_mapper_tcp6_new(), host, cfg); } AFInetDestDriver * afinet_dd_new_udp(gchar *host, GlobalConfig *cfg) { return afinet_dd_new_instance(transport_mapper_udp_new(), host, cfg); } AFInetDestDriver * afinet_dd_new_udp6(gchar *host, GlobalConfig *cfg) { return afinet_dd_new_instance(transport_mapper_udp6_new(), host, cfg); } static LogWriter * afinet_dd_syslog_construct_writer(AFSocketDestDriver *s) { AFInetDestDriver *self = (AFInetDestDriver *) s; TransportMapperInet *transport_mapper_inet = ((TransportMapperInet *) (self->super.transport_mapper)); LogWriter *writer = afsocket_dd_construct_writer_method(s); if (((self->super.transport_mapper->sock_type == SOCK_STREAM) && transport_mapper_inet->tls_context)) _disable_connection_closure_on_input(writer); log_writer_set_flags(writer, log_writer_get_flags(writer) | LW_SYSLOG_PROTOCOL); return writer; } AFInetDestDriver * afinet_dd_new_syslog(gchar *host, GlobalConfig *cfg) { AFInetDestDriver *self = afinet_dd_new_instance(transport_mapper_syslog_new(), host, cfg); self->super.construct_writer = afinet_dd_syslog_construct_writer; return self; } AFInetDestDriver * afinet_dd_new_network(gchar *host, GlobalConfig *cfg) { return afinet_dd_new_instance(transport_mapper_network_new(), host, cfg); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-dest.h000066400000000000000000000065211450431004300232020ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFINET_DEST_H_INCLUDED #define AFINET_DEST_H_INCLUDED #include "afinet.h" #include "afsocket-dest.h" #include "afinet-dest-failover.h" #include "transport/tls-context.h" #if SYSLOG_NG_ENABLE_SPOOF_SOURCE /* this forward declaration avoids having to include libnet, which requires * ugly playing with macros, see that for yourself in the implementation * file */ struct libnet_context; #endif typedef struct _AFInetDestDriver { AFSocketDestDriver super; #if SYSLOG_NG_ENABLE_SPOOF_SOURCE gboolean spoof_source; struct libnet_context *lnet_ctx; GMutex lnet_lock; GString *lnet_buffer; guint spoof_source_max_msglen; #endif gchar *primary; AFInetDestDriverFailover *failover; /* character as it can contain a service name from /etc/services */ gchar *bind_port; gchar *bind_ip; /* character as it can contain a service name from /etc/services */ gchar *dest_port; /* destination hostname is stored in super.hostname */ } AFInetDestDriver; void afinet_dd_set_localport(LogDriver *self, gchar *service); void afinet_dd_set_destport(LogDriver *self, gchar *service); void afinet_dd_set_localip(LogDriver *self, gchar *ip); void afinet_dd_set_sync_freq(LogDriver *self, gint sync_freq); void afinet_dd_set_spoof_source(LogDriver *self, gboolean enable); void afinet_dd_set_spoof_source_max_msglen(LogDriver *s, guint max_msglen); void afinet_dd_set_tls_context(LogDriver *s, TLSContext *tls_context); gint afinet_dd_determine_port(const TransportMapper *transport_mapper, const gchar *service_port); void afinet_dd_enable_failover(LogDriver *s); void afinet_dd_add_failovers(LogDriver *s, GList *failovers); //void afinet_dd_set_failback_mode(LogDriver *s, gboolean enable); void afinet_dd_enable_failback(LogDriver *s); void afinet_dd_set_failback_tcp_probe_interval(LogDriver *s, gint tcp_probe_interval); void afinet_dd_set_failback_successful_probes_required(LogDriver *s, gint successful_probes_required); const gchar *afinet_dd_get_hostname(const AFInetDestDriver *self); AFInetDestDriver *afinet_dd_new_tcp(gchar *host, GlobalConfig *cfg); AFInetDestDriver *afinet_dd_new_tcp6(gchar *host, GlobalConfig *cfg); AFInetDestDriver *afinet_dd_new_udp(gchar *host, GlobalConfig *cfg); AFInetDestDriver *afinet_dd_new_udp6(gchar *host, GlobalConfig *cfg); AFInetDestDriver *afinet_dd_new_syslog(gchar *host, GlobalConfig *cfg); AFInetDestDriver *afinet_dd_new_network(gchar *host, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-source.c000066400000000000000000000113511450431004300235330ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinet-source.h" #include "messages.h" #include "transport-mapper-inet.h" #include "socket-options-inet.h" #include #include #include #include #include #include #include void afinet_sd_set_localport(LogDriver *s, gchar *service) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; if (self->bind_port) g_free(self->bind_port); self->bind_port = g_strdup(service); } void afinet_sd_set_localip(LogDriver *s, gchar *ip) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; if (self->bind_ip) g_free(self->bind_ip); self->bind_ip = g_strdup(ip); } void afinet_sd_set_tls_context(LogDriver *s, TLSContext *tls_context) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; transport_mapper_inet_set_tls_context((TransportMapperInet *) self->super.transport_mapper, tls_context); } static gboolean afinet_sd_setup_addresses(AFSocketSourceDriver *s) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; if (!afsocket_sd_setup_addresses_method(s)) return FALSE; if (self->super.proto_factory->default_inet_port) transport_mapper_inet_set_server_port(self->super.transport_mapper, self->super.proto_factory->default_inet_port); g_sockaddr_unref(self->super.bind_addr); if (!resolve_hostname_to_sockaddr(&self->super.bind_addr, self->super.transport_mapper->address_family, self->bind_ip)) return FALSE; if (!self->bind_port) { const gchar *port_change_warning = transport_mapper_inet_get_port_change_warning(self->super.transport_mapper); if (port_change_warning) { msg_warning(port_change_warning, evt_tag_str("id", self->super.super.super.id)); } g_sockaddr_set_port(self->super.bind_addr, transport_mapper_inet_get_server_port(self->super.transport_mapper)); } else g_sockaddr_set_port(self->super.bind_addr, afinet_lookup_service(self->super.transport_mapper, self->bind_port)); return TRUE; } gboolean afinet_sd_init(LogPipe *s) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; if (!afsocket_sd_init_method(&self->super.super.super.super)) return FALSE; return TRUE; } void afinet_sd_free(LogPipe *s) { AFInetSourceDriver *self = (AFInetSourceDriver *) s; g_free(self->bind_ip); g_free(self->bind_port); afsocket_sd_free_method(s); } static AFInetSourceDriver * afinet_sd_new_instance(TransportMapper *transport_mapper, GlobalConfig *cfg) { AFInetSourceDriver *self = g_new0(AFInetSourceDriver, 1); afsocket_sd_init_instance(&self->super, socket_options_inet_new(), transport_mapper, cfg); self->super.super.super.super.init = afinet_sd_init; self->super.super.super.super.free_fn = afinet_sd_free; self->super.setup_addresses = afinet_sd_setup_addresses; return self; } AFInetSourceDriver * afinet_sd_new_tcp(GlobalConfig *cfg) { return afinet_sd_new_instance(transport_mapper_tcp_new(), cfg); } AFInetSourceDriver * afinet_sd_new_tcp6(GlobalConfig *cfg) { return afinet_sd_new_instance(transport_mapper_tcp6_new(), cfg); } AFInetSourceDriver * afinet_sd_new_udp(GlobalConfig *cfg) { return afinet_sd_new_instance(transport_mapper_udp_new(), cfg); } AFInetSourceDriver * afinet_sd_new_udp6(GlobalConfig *cfg) { return afinet_sd_new_instance(transport_mapper_udp6_new(), cfg); } AFInetSourceDriver * afinet_sd_new_syslog(GlobalConfig *cfg) { AFInetSourceDriver *self = afinet_sd_new_instance(transport_mapper_syslog_new(), cfg); self->super.reader_options.parse_options.flags |= LP_SYSLOG_PROTOCOL; return self; } AFInetSourceDriver * afinet_sd_new_network(GlobalConfig *cfg) { AFInetSourceDriver *self = afinet_sd_new_instance(transport_mapper_network_new(), cfg); return self; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet-source.h000066400000000000000000000035071450431004300235440ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFINET_SOURCE_H_INCLUDED #define AFINET_SOURCE_H_INCLUDED #include "afinet.h" #include "afsocket-source.h" #include "transport/tls-context.h" typedef struct _AFInetSourceDriver { AFSocketSourceDriver super; /* character as it can contain a service name from /etc/services */ gchar *bind_port; gchar *bind_ip; } AFInetSourceDriver; void afinet_sd_set_tls_context(LogDriver *s, TLSContext *tls_context); AFInetSourceDriver *afinet_sd_new_tcp(GlobalConfig *cfg); AFInetSourceDriver *afinet_sd_new_tcp6(GlobalConfig *cfg); AFInetSourceDriver *afinet_sd_new_udp(GlobalConfig *cfg); AFInetSourceDriver *afinet_sd_new_udp6(GlobalConfig *cfg); AFInetSourceDriver *afinet_sd_new_syslog(GlobalConfig *cfg); AFInetSourceDriver *afinet_sd_new_network(GlobalConfig *cfg); void afinet_sd_set_localport(LogDriver *self, gchar *service); void afinet_sd_set_localip(LogDriver *self, gchar *ip); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet.c000066400000000000000000000051741450431004300222430ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinet.h" #include "messages.h" #include "gprocess.h" #include "transport-mapper-inet.h" #include #include #include #include #include #include #include static gint afinet_lookup_service_and_proto(const gchar *service, const gchar *proto) { gchar *end; gint port; /* check if service is numeric */ port = strtol(service, &end, 10); if ((*end != 0)) { struct servent *se; /* service is not numeric, check if it's a service in /etc/services */ se = getservbyname(service, proto); if (se) { port = ntohs(se->s_port); } else { msg_error("Error finding port number, falling back to default", evt_tag_printf("service", "%s/%s", proto, service)); return 0; } } return port; } static const gchar * afinet_lookup_proto(gint protocol_number, gint sock_type) { struct protoent *ipproto_ent = getprotobynumber(protocol_number); return ipproto_ent ? ipproto_ent->p_name : ((sock_type == SOCK_STREAM) ? "tcp" : "udp"); } guint16 afinet_lookup_service(const TransportMapper *transport_mapper, const gchar *service) { const gchar *protocol_name = afinet_lookup_proto(transport_mapper->sock_proto, transport_mapper->sock_type); return afinet_lookup_service_and_proto(service, protocol_name); } gint afinet_determine_port(const TransportMapper *transport_mapper, const gchar *service_port) { gint port = 0; if (!service_port) port = transport_mapper_inet_get_server_port(transport_mapper); else port = afinet_lookup_service(transport_mapper, service_port); return port; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afinet.h000066400000000000000000000023541450431004300222450ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFINET_H_INCLUDED #define AFINET_H_INCLUDED #include "afsocket.h" #include "transport-mapper.h" guint16 afinet_lookup_service(const TransportMapper *transport_mapper, const gchar *service); gint afinet_determine_port(const TransportMapper *transport_mapper, const gchar *service_port); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-dest.c000066400000000000000000000553011450431004300235260ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket-dest.h" #include "messages.h" #include "logwriter.h" #include "gsocket.h" #include "stats/stats-registry.h" #include "mainloop.h" #include "timeutils/misc.h" #include "hostname.h" #include "persist-state.h" #include #include #include typedef struct _ReloadStoreItem { LogProtoClientFactory *proto_factory; GSockAddr *dest_addr; LogWriter *writer; } ReloadStoreItem; static ReloadStoreItem * _reload_store_item_new(AFSocketDestDriver *afsocket_dd) { ReloadStoreItem *item = g_new(ReloadStoreItem, 1); item->proto_factory = afsocket_dd->proto_factory; item->writer = afsocket_dd->writer; item->dest_addr = g_sockaddr_ref(afsocket_dd->dest_addr); return item; } static void _reload_store_item_free(ReloadStoreItem *self) { if (!self) return; if (self->writer) log_pipe_unref((LogPipe *) self->writer); g_sockaddr_unref(self->dest_addr); g_free(self); } static LogWriter * _reload_store_item_release_writer(ReloadStoreItem *self) { LogWriter *writer = self->writer; self->writer = NULL; return writer; } static inline gboolean _is_protocol_compatible_with_writer_after_reload(AFSocketDestDriver *self, ReloadStoreItem *item) { return (self->proto_factory->construct == item->proto_factory->construct); } void afsocket_dd_set_keep_alive(LogDriver *s, gboolean enable) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; self->connections_kept_alive_across_reloads = enable; } void afsocket_dd_set_close_on_input(LogDriver *s, gboolean close_on_input) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; self->close_on_input = close_on_input; } static const gchar *_module_name = "afsocket_dd"; static const gchar * _get_module_identifier(const AFSocketDestDriver *self) { static gchar module_identifier[128]; g_snprintf(module_identifier, sizeof(module_identifier), "%s,%s", (self->transport_mapper->sock_type == SOCK_STREAM) ? "stream" : "dgram", afsocket_dd_get_dest_name(self)); return self->super.super.super.persist_name ? self->super.super.super.persist_name : module_identifier; } static const gchar * _get_legacy_module_identifier(const AFSocketDestDriver *self) { static gchar legacy_module_identifier[128]; const gchar *hostname = get_local_hostname_fqdn(); g_snprintf(legacy_module_identifier, sizeof(legacy_module_identifier), "%s,%s,%s", (self->transport_mapper->sock_type == SOCK_STREAM) ? "stream" : "dgram", afsocket_dd_get_dest_name(self), hostname); return legacy_module_identifier; } static const gchar * afsocket_dd_format_name(const LogPipe *s) { const AFSocketDestDriver *self = (const AFSocketDestDriver *)s; static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s.(%s)", _module_name, _get_module_identifier(self)); return persist_name; } static const gchar * afsocket_dd_format_qfile_name(const AFSocketDestDriver *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s_qfile(%s)", _module_name, _get_module_identifier(self)); return persist_name; } static const gchar * afsocket_dd_format_connections_name(const AFSocketDestDriver *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s_connections(%s)", _module_name, _get_module_identifier(self)); return persist_name; } static const gchar * afsocket_dd_format_legacy_connection_name(const AFSocketDestDriver *self) { static gchar legacy_persist_name[1024]; g_snprintf(legacy_persist_name, sizeof(legacy_persist_name), "%s_connection(%s)", _module_name, _get_legacy_module_identifier(self)); return legacy_persist_name; } static gchar * afsocket_dd_stats_instance(AFSocketDestDriver *self) { static gchar buf[256]; g_snprintf(buf, sizeof(buf), "%s,%s", self->transport_mapper->transport, afsocket_dd_get_dest_name(self)); return buf; } static void _afsocket_dd_connection_in_progress(AFSocketDestDriver *self); static void afsocket_dd_init_watches(AFSocketDestDriver *self) { IV_FD_INIT(&self->connect_fd); self->connect_fd.cookie = self; self->connect_fd.handler_out = (void (*)(void *)) _afsocket_dd_connection_in_progress; IV_TIMER_INIT(&self->reconnect_timer); self->reconnect_timer.cookie = self; self->reconnect_timer.handler = (void (*)(void *)) afsocket_dd_reconnect; } static void afsocket_dd_start_watches(AFSocketDestDriver *self) { main_loop_assert_main_thread(); self->connect_fd.fd = self->fd; iv_fd_register(&self->connect_fd); } void afsocket_dd_stop_watches(AFSocketDestDriver *self) { main_loop_assert_main_thread(); if (iv_fd_registered(&self->connect_fd)) { iv_fd_unregister(&self->connect_fd); /* need to close the fd in this case as it wasn't established yet */ msg_verbose("Closing connecting fd", evt_tag_int("fd", self->fd)); close(self->fd); self->fd = -1; } if (iv_timer_registered(&self->reconnect_timer)) iv_timer_unregister(&self->reconnect_timer); } static void afsocket_dd_start_reconnect_timer(AFSocketDestDriver *self) { main_loop_assert_main_thread(); if (iv_timer_registered(&self->reconnect_timer)) iv_timer_unregister(&self->reconnect_timer); iv_validate_now(); self->reconnect_timer.expires = iv_now; timespec_add_msec(&self->reconnect_timer.expires, self->writer_options.time_reopen * 1000L); iv_timer_register(&self->reconnect_timer); } static gboolean _update_legacy_connection_persist_name(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); const gchar *current_persist_name = afsocket_dd_format_connections_name(self); const gchar *legacy_persist_name = afsocket_dd_format_legacy_connection_name(self); if (persist_state_entry_exists(cfg->state, current_persist_name)) return TRUE; if (!persist_state_entry_exists(cfg->state, legacy_persist_name)) return TRUE; return persist_state_move_entry(cfg->state, legacy_persist_name, current_persist_name); } static LogTransport * afsocket_dd_construct_transport(AFSocketDestDriver *self, gint fd) { return transport_mapper_construct_log_transport(self->transport_mapper, fd); } static gboolean afsocket_dd_connected(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); LogTransport *transport; LogProtoClient *proto; gchar buf1[256], buf2[256]; main_loop_assert_main_thread(); msg_notice("Syslog connection established", evt_tag_int("fd", self->fd), evt_tag_str("server", g_sockaddr_format(self->dest_addr, buf2, sizeof(buf2), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf1, sizeof(buf1), GSA_FULL))); transport = afsocket_dd_construct_transport(self, self->fd); if (!transport) return FALSE; proto = log_proto_client_factory_construct(self->proto_factory, transport, &self->writer_options.proto_options.super); log_proto_client_restart_with_state(proto, cfg->state, afsocket_dd_format_connections_name(self)); log_writer_reopen(self->writer, proto); return TRUE; } void afsocket_dd_connected_with_fd(gpointer s, gint fd, GSockAddr *saddr) { AFSocketDestDriver *self = (AFSocketDestDriver *)s; afsocket_dd_stop_watches(self); g_sockaddr_unref(self->dest_addr); self->dest_addr = saddr; self->fd = fd; if (!afsocket_dd_connected(self)) { close(self->fd); self->fd = -1; afsocket_dd_start_reconnect_timer(self); } } static void _afsocket_dd_connection_in_progress(AFSocketDestDriver *self) { gchar buf[256]; int error = 0; socklen_t errorlen = sizeof(error); if (iv_fd_registered(&self->connect_fd)) iv_fd_unregister(&self->connect_fd); if (self->transport_mapper->sock_type == SOCK_STREAM) { if (getsockopt(self->fd, SOL_SOCKET, SO_ERROR, &error, &errorlen) == -1) { msg_error("getsockopt(SOL_SOCKET, SO_ERROR) failed for connecting socket", evt_tag_int("fd", self->fd), evt_tag_str("server", g_sockaddr_format(self->dest_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_error(EVT_TAG_OSERROR), evt_tag_int("time_reopen", self->writer_options.time_reopen)); goto error_reconnect; } if (error) { msg_error("Syslog connection failed", evt_tag_int("fd", self->fd), evt_tag_str("server", g_sockaddr_format(self->dest_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_errno(EVT_TAG_OSERROR, error), evt_tag_int("time_reopen", self->writer_options.time_reopen)); goto error_reconnect; } } if (afsocket_dd_connected(self)) return; error_reconnect: close(self->fd); self->fd = -1; afsocket_dd_start_reconnect_timer(self); } static gboolean afsocket_dd_start_connect(AFSocketDestDriver *self) { int sock, rc; gchar buf1[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; main_loop_assert_main_thread(); if (log_writer_opened(self->writer)) return TRUE; g_assert(self->transport_mapper->transport); g_assert(self->bind_addr); g_assert(self->dest_addr); if (!transport_mapper_open_socket(self->transport_mapper, self->socket_options, self->bind_addr, self->dest_addr, AFSOCKET_DIR_SEND, &sock)) { return FALSE; } if (!socket_options_setup_peer_socket(self->socket_options, sock, self->dest_addr)) return FALSE; rc = g_connect(sock, self->dest_addr); if (rc == G_IO_STATUS_NORMAL) { self->fd = sock; if (!afsocket_dd_connected(self)) { close(self->fd); self->fd = -1; return FALSE; } } else if (rc == G_IO_STATUS_ERROR && errno == EINPROGRESS) { /* we must wait until connect succeeds */ self->fd = sock; afsocket_dd_start_watches(self); } else { /* error establishing connection */ msg_error("Connection failed", evt_tag_int("fd", sock), evt_tag_str("server", g_sockaddr_format(self->dest_addr, buf2, sizeof(buf2), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf1, sizeof(buf1), GSA_FULL)), evt_tag_error(EVT_TAG_OSERROR)); close(sock); return FALSE; } return TRUE; } void afsocket_dd_reconnect(AFSocketDestDriver *self) { if (!afsocket_dd_setup_addresses(self) || !afsocket_dd_start_connect(self)) { msg_error("Initiating connection failed, reconnecting", evt_tag_int("time_reopen", self->writer_options.time_reopen)); afsocket_dd_start_reconnect_timer(self); } } static gboolean afsocket_dd_setup_proto_factory(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (!self->proto_factory) self->proto_factory = log_proto_client_get_factory(&cfg->plugin_context, self->transport_mapper->logproto); if (!self->proto_factory) { msg_error("Unknown value specified in the transport() option, no such LogProto plugin found", evt_tag_str("transport", self->transport_mapper->logproto)); return FALSE; } self->transport_mapper->create_multitransport = self->proto_factory->use_multitransport; return TRUE; } static gboolean afsocket_dd_setup_writer_options(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); log_writer_options_init(&self->writer_options, cfg, 0); return TRUE; } static gboolean afsocket_dd_setup_transport(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (!transport_mapper_apply_transport(self->transport_mapper, cfg)) return FALSE; if (!afsocket_dd_setup_proto_factory(self)) return FALSE; if (!afsocket_dd_setup_writer_options(self)) return FALSE; return TRUE; } gboolean afsocket_dd_setup_addresses_method(AFSocketDestDriver *self) { return TRUE; } static gboolean _afsocket_dd_try_to_restore_connection_state(AFSocketDestDriver *self) { /* If we are reinitializing an old config, an existing writer may be present */ if (self->writer) return TRUE; ReloadStoreItem *item = cfg_persist_config_fetch( log_pipe_get_config(&self->super.super.super), afsocket_dd_format_connections_name(self)); /* We don't have an item stored in the reload cache, which means */ /* it is the first time when we try to initialize the writer */ if (!item) return FALSE; if (_is_protocol_compatible_with_writer_after_reload(self, item)) self->writer = _reload_store_item_release_writer(item); self->dest_addr = g_sockaddr_ref(item->dest_addr); _reload_store_item_free(item); return TRUE; } LogWriter * afsocket_dd_construct_writer_method(AFSocketDestDriver *self) { guint32 writer_flags = 0; writer_flags |= LW_FORMAT_PROTO; if (self->transport_mapper->sock_type == SOCK_STREAM && self->close_on_input) writer_flags |= LW_DETECT_EOF; LogWriter *writer = log_writer_new(writer_flags, self->super.super.super.cfg); log_pipe_set_options((LogPipe *) writer, &self->super.super.super.options); return writer; } static void _init_stats_key_builders(AFSocketDestDriver *self, StatsClusterKeyBuilder **writer_sck_builder, StatsClusterKeyBuilder **driver_sck_builder, StatsClusterKeyBuilder **queue_sck_builder) { *writer_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*writer_sck_builder, stats_cluster_label("driver", "afsocket")); stats_cluster_key_builder_add_legacy_label(*writer_sck_builder, stats_cluster_label("transport", self->transport_mapper->transport)); stats_cluster_key_builder_add_legacy_label(*writer_sck_builder, stats_cluster_label("address", afsocket_dd_get_dest_name(self))); *driver_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("driver", "afsocket")); stats_cluster_key_builder_add_label(*driver_sck_builder, stats_cluster_label("id", self->super.super.id)); stats_cluster_key_builder_add_legacy_label(*driver_sck_builder, stats_cluster_label("transport", self->transport_mapper->transport)); stats_cluster_key_builder_add_legacy_label(*driver_sck_builder, stats_cluster_label("address", afsocket_dd_get_dest_name(self))); stats_cluster_key_builder_set_legacy_alias(*driver_sck_builder, self->writer_options.stats_source | SCS_DESTINATION, self->super.super.id, afsocket_dd_stats_instance(self)); *queue_sck_builder = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("driver", "afsocket")); stats_cluster_key_builder_add_label(*queue_sck_builder, stats_cluster_label("id", self->super.super.id)); stats_cluster_key_builder_add_legacy_label(*queue_sck_builder, stats_cluster_label("transport", self->transport_mapper->transport)); stats_cluster_key_builder_add_legacy_label(*queue_sck_builder, stats_cluster_label("address", afsocket_dd_get_dest_name(self))); } static gboolean afsocket_dd_setup_writer(AFSocketDestDriver *self) { gboolean kept_alive_connection = _afsocket_dd_try_to_restore_connection_state(self); if (!self->writer) { /* NOTE: we open our writer with no fd, so we can send messages down there * even while the connection is not established */ self->writer = afsocket_dd_construct_writer(self); } StatsClusterKeyBuilder *writer_sck_builder; StatsClusterKeyBuilder *driver_sck_builder; StatsClusterKeyBuilder *queue_sck_builder; _init_stats_key_builders(self, &writer_sck_builder, &driver_sck_builder, &queue_sck_builder); log_pipe_set_config((LogPipe *)self->writer, log_pipe_get_config(&self->super.super.super)); log_writer_set_options(self->writer, &self->super.super.super, &self->writer_options, self->super.super.id, writer_sck_builder); gint stats_level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : self->writer_options.stats_level; LogQueue *queue = log_dest_driver_acquire_queue(&self->super, afsocket_dd_format_qfile_name(self), stats_level, driver_sck_builder, queue_sck_builder); log_writer_set_queue(self->writer, queue); stats_cluster_key_builder_free(queue_sck_builder); stats_cluster_key_builder_free(driver_sck_builder); if (!log_pipe_init((LogPipe *) self->writer)) { log_pipe_unref((LogPipe *) self->writer); return FALSE; } log_pipe_append(&self->super.super.super, (LogPipe *) self->writer); if (kept_alive_connection) { LogProtoClient *proto = log_writer_steal_proto(self->writer); if (proto) { self->fd = log_proto_client_get_fd(proto); log_writer_reopen(self->writer, proto); } } self->connection_initialized = TRUE; return TRUE; } static gboolean _finalize_init(gpointer arg) { AFSocketDestDriver *self = (AFSocketDestDriver *)arg; afsocket_dd_reconnect(self); return TRUE; } static gboolean _dd_init_stream(AFSocketDestDriver *self) { if (!afsocket_dd_setup_writer(self)) return FALSE; return transport_mapper_async_init(self->transport_mapper, _finalize_init, self); } static gboolean _dd_init_dgram(AFSocketDestDriver *self) { if (!transport_mapper_init(self->transport_mapper)) { return FALSE; } if (!afsocket_dd_setup_writer(self)) { return FALSE; } return _finalize_init(self); } static void _dd_rewind_stateless_proto_backlog(AFSocketDestDriver *self) { if (!log_proto_client_factory_is_proto_stateful(self->proto_factory)) { log_writer_msg_rewind(self->writer); } } static gboolean _dd_init_socket(AFSocketDestDriver *self) { switch (self->transport_mapper->sock_type) { case SOCK_STREAM: return _dd_init_stream(self); case SOCK_DGRAM: default: return _dd_init_dgram(self); } } gboolean afsocket_dd_init(LogPipe *s) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; if (!log_dest_driver_init_method(s) || !afsocket_dd_setup_transport(self)) { return FALSE; } if (!_update_legacy_connection_persist_name(self)) return FALSE; if (!_dd_init_socket(self)) { return FALSE; } _dd_rewind_stateless_proto_backlog(self); return TRUE; } static void afsocket_dd_stop_writer(AFSocketDestDriver *self) { if (self->writer) log_pipe_deinit((LogPipe *) self->writer); } static void afsocket_dd_save_connection(AFSocketDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (self->connections_kept_alive_across_reloads) { ReloadStoreItem *item = _reload_store_item_new(self); cfg_persist_config_add(cfg, afsocket_dd_format_connections_name(self), item, (GDestroyNotify)_reload_store_item_free); self->writer = NULL; } } gboolean afsocket_dd_deinit(LogPipe *s) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; afsocket_dd_stop_watches(self); afsocket_dd_stop_writer(self); if (self->connection_initialized) { afsocket_dd_save_connection(self); } return log_dest_driver_deinit_method(s); } static void afsocket_dd_notify(LogPipe *s, gint notify_code, gpointer user_data) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; gchar buf[MAX_SOCKADDR_STRING]; switch (notify_code) { case NC_CLOSE: case NC_WRITE_ERROR: log_writer_reopen(self->writer, NULL); msg_notice((notify_code == NC_CLOSE) ? "Syslog connection closed" : "Syslog connection broken", evt_tag_int("fd", self->fd), evt_tag_str("server", g_sockaddr_format(self->dest_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_int("time_reopen", self->writer_options.time_reopen)); afsocket_dd_start_reconnect_timer(self); break; default: break; } } void afsocket_dd_free(LogPipe *s) { AFSocketDestDriver *self = (AFSocketDestDriver *) s; log_writer_options_destroy(&self->writer_options); g_sockaddr_unref(self->bind_addr); g_sockaddr_unref(self->dest_addr); log_pipe_unref((LogPipe *) self->writer); transport_mapper_free(self->transport_mapper); socket_options_free(self->socket_options); log_dest_driver_free(s); } void afsocket_dd_init_instance(AFSocketDestDriver *self, SocketOptions *socket_options, TransportMapper *transport_mapper, GlobalConfig *cfg) { log_dest_driver_init_instance(&self->super, cfg); log_writer_options_defaults(&self->writer_options); self->super.super.super.init = afsocket_dd_init; self->super.super.super.deinit = afsocket_dd_deinit; self->super.super.super.free_fn = afsocket_dd_free; self->super.super.super.notify = afsocket_dd_notify; self->super.super.super.generate_persist_name = afsocket_dd_format_name; self->setup_addresses = afsocket_dd_setup_addresses_method; self->construct_writer = afsocket_dd_construct_writer_method; self->transport_mapper = transport_mapper; self->socket_options = socket_options; self->connections_kept_alive_across_reloads = TRUE; self->close_on_input = TRUE; self->connection_initialized = FALSE; self->writer_options.mark_mode = MM_GLOBAL; self->writer_options.stats_level = STATS_LEVEL0; self->writer_options.stats_source = self->transport_mapper->stats_source; afsocket_dd_init_watches(self); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-dest.h000066400000000000000000000056471450431004300235430ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_DEST_H_INCLUDED #define AFSOCKET_DEST_H_INCLUDED #include "afsocket.h" #include "socket-options.h" #include "transport-mapper.h" #include "driver.h" #include "logwriter.h" #include typedef struct _AFSocketDestDriver AFSocketDestDriver; struct _AFSocketDestDriver { LogDestDriver super; guint connections_kept_alive_across_reloads:1; gboolean close_on_input; gint fd; LogWriter *writer; LogWriterOptions writer_options; LogProtoClientFactory *proto_factory; GSockAddr *bind_addr; GSockAddr *dest_addr; gboolean connection_initialized; struct iv_fd connect_fd; struct iv_timer reconnect_timer; SocketOptions *socket_options; TransportMapper *transport_mapper; LogWriter *(*construct_writer)(AFSocketDestDriver *self); gboolean (*setup_addresses)(AFSocketDestDriver *s); const gchar *(*get_dest_name)(const AFSocketDestDriver *s); }; static inline LogWriter * afsocket_dd_construct_writer(AFSocketDestDriver *self) { return self->construct_writer(self); } static inline gboolean afsocket_dd_setup_addresses(AFSocketDestDriver *s) { return s->setup_addresses(s); } static inline const gchar * afsocket_dd_get_dest_name(const AFSocketDestDriver *s) { return s->get_dest_name(s); } LogWriter *afsocket_dd_construct_writer_method(AFSocketDestDriver *self); gboolean afsocket_dd_setup_addresses_method(AFSocketDestDriver *self); void afsocket_dd_set_keep_alive(LogDriver *self, gint enable); void afsocket_dd_set_close_on_input(LogDriver *self, gboolean close_on_input); void afsocket_dd_init_instance(AFSocketDestDriver *self, SocketOptions *socket_options, TransportMapper *transport_mapper, GlobalConfig *cfg); void afsocket_dd_reconnect(AFSocketDestDriver *self); void afsocket_dd_stop_watches(AFSocketDestDriver *self); gboolean afsocket_dd_init(LogPipe *s); gboolean afsocket_dd_deinit(LogPipe *s); void afsocket_dd_free(LogPipe *s); void afsocket_dd_connected_with_fd(gpointer self, gint fd, GSockAddr *saddr); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-grammar.ym000066400000000000000000000706621450431004300244270ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "afsocket-parser.h" } %code { #include "afsocket.h" #include "cfg-parser.h" #include "afunix-source.h" #include "afunix-dest.h" #include "afinet-source.h" #include "afinet-dest.h" #include "messages.h" #include "syslog-names.h" #include "plugin.h" #include "cfg-grammar-internal.h" #include "socket-options-inet.h" #include "socket-options-unix.h" #include "transport-mapper-inet.h" #include "service-management.h" #include "systemd-syslog-source.h" #include "afsocket-systemd-override.h" #include "transport/tls-context.h" static SocketOptions *last_sock_options; static TransportMapper *last_transport_mapper; TLSContext *last_tls_context; #if ! SYSLOG_NG_ENABLE_IPV6 #undef AF_INET6 #define AF_INET6 0; g_assert_not_reached() #endif static void afsocket_grammar_set_source_driver(AFSocketSourceDriver *sd) { last_driver = &sd->super.super; last_reader_options = &((AFSocketSourceDriver *) last_driver)->reader_options; last_sock_options = ((AFSocketSourceDriver *) last_driver)->socket_options; last_transport_mapper = ((AFSocketSourceDriver *) last_driver)->transport_mapper; last_proto_server_options = &last_reader_options->proto_options.super; } static void afsocket_grammar_set_dest_driver(AFSocketDestDriver *dd) { last_driver = &dd->super.super; last_writer_options = &((AFSocketDestDriver *) last_driver)->writer_options; last_sock_options = ((AFSocketDestDriver *) last_driver)->socket_options; last_transport_mapper = ((AFSocketDestDriver *) last_driver)->transport_mapper; last_proto_client_options = &last_writer_options->proto_options.super; } void afunix_grammar_set_source_driver(AFUnixSourceDriver *sd) { afsocket_grammar_set_source_driver(&sd->super); last_file_perm_options = &sd->file_perm_options; } static void afinet_grammar_set_source_driver(AFInetSourceDriver *sd) { afsocket_grammar_set_source_driver(&sd->super); } static void afunix_grammar_set_dest_driver(AFUnixDestDriver *dd) { afsocket_grammar_set_dest_driver(&dd->super); } static void afinet_grammar_set_dest_driver(AFInetDestDriver *dd) { afsocket_grammar_set_dest_driver(&dd->super); } void systemd_syslog_grammar_set_source_driver(SystemDSyslogSourceDriver *sd) { afsocket_grammar_set_source_driver(&sd->super); } } %define api.prefix {afsocket_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} %token KW_UNIX_STREAM 20000 %token KW_UNIX_DGRAM %token KW_TCP %token KW_UDP %token KW_TCP6 %token KW_UDP6 %token KW_NETWORK %token KW_TRANSPORT %token KW_IP_PROTOCOL %token KW_SYSTEMD_SYSLOG %token KW_IP_TTL %token KW_SO_BROADCAST %token KW_IP_TOS %token KW_IP_FREEBIND %token KW_SO_SNDBUF %token KW_SO_RCVBUF %token KW_SO_KEEPALIVE %token KW_SO_REUSEPORT %token KW_TCP_KEEPALIVE_TIME %token KW_TCP_KEEPALIVE_PROBES %token KW_TCP_KEEPALIVE_INTVL %token KW_SO_PASSCRED %token KW_LISTEN_BACKLOG %token KW_SPOOF_SOURCE %token KW_SPOOF_SOURCE_MAX_MSGLEN %token KW_KEEP_ALIVE %token KW_MAX_CONNECTIONS %token KW_CLOSE_ON_INPUT %token KW_LOCALIP %token KW_IP %token KW_INTERFACE %token KW_LOCALPORT %token KW_DESTPORT %token KW_FAILOVER_SERVERS %token KW_FAILOVER %token KW_SERVERS %token KW_FAILBACK %token KW_TCP_PROBE_INTERVAL %token KW_SUCCESSFUL_PROBES_REQUIRED %token KW_DYNAMIC_WINDOW_SIZE %token KW_DYNAMIC_WINDOW_STATS_FREQ %token KW_DYNAMIC_WINDOW_REALLOC_TICKS /* SSL support */ %token KW_TLS %token KW_PEER_VERIFY %token KW_KEY_FILE %token KW_CERT_FILE %token KW_DHPARAM_FILE %token KW_PKCS12_FILE %token KW_CA_DIR %token KW_CRL_DIR %token KW_CA_FILE %token KW_TRUSTED_KEYS %token KW_TRUSTED_DN %token KW_CIPHER_SUITE %token KW_TLS12_AND_OLDER %token KW_TLS13 %token KW_SIGALGS %token KW_CLIENT_SIGALGS %token KW_ECDH_CURVE_LIST %token KW_SSL_OPTIONS %token KW_SNI %token KW_ALLOW_COMPRESS %token KW_KEYLOG_FILE %token KW_OCSP_STAPLING_VERIFY %token KW_CONF_CMDS /* INCLUDE_DECLS */ %type driver %type source_afunix %type source_afunix_dgram_params %type source_afunix_stream_params %type source_afinet %type source_afinet_udp_params %type source_afinet_tcp_params %type source_afinet_udp6_params %type source_afinet_tcp6_params %type source_afsyslog %type source_afsyslog_params %type source_afnetwork %type source_afnetwork_params %type source_afsocket_stream_params %type source_systemd_syslog %type source_systemd_syslog_params %type dest_afunix %type dest_afunix_dgram_params %type dest_afunix_stream_params %type dest_afinet %type dest_afinet_udp_params %type dest_afinet_tcp_params %type dest_afinet_udp6_params %type dest_afinet_tcp6_params %type dest_afsyslog %type dest_afsyslog_params %type dest_afnetwork %type dest_afnetwork_params %type inet_ip_protocol_option %type dest_afinet_option %type dest_failover_options %type dest_failover_modes_options %type tls_conf_cmds %type tls_conf_cmd_list_build %% start : driver { *instance = $1; if (yychar != AFSOCKET_EMPTY) cfg_lexer_unput_token(lexer, &yylval); YYACCEPT; } ; driver : LL_CONTEXT_SOURCE source_afunix { $$ = $2; } | LL_CONTEXT_SOURCE source_afinet { $$ = $2; } | LL_CONTEXT_SOURCE source_afsyslog { $$ = $2; } | LL_CONTEXT_SOURCE source_afnetwork { $$ = $2; } | LL_CONTEXT_SOURCE source_systemd_syslog { $$ = $2; } | LL_CONTEXT_DESTINATION dest_afunix { $$ = $2; } | LL_CONTEXT_DESTINATION dest_afinet { $$ = $2; } | LL_CONTEXT_DESTINATION dest_afsyslog { $$ = $2; } | LL_CONTEXT_DESTINATION dest_afnetwork { $$ = $2; } ; source_afunix : KW_UNIX_DGRAM '(' _inner_src_context_push source_afunix_dgram_params _inner_src_context_pop ')' { $$ = $4; } | KW_UNIX_STREAM '(' _inner_src_context_push source_afunix_stream_params _inner_src_context_pop ')' { $$ = $4; } ; source_afunix_dgram_params : string { create_and_set_unix_dgram_or_systemd_syslog_source($1, configuration); } source_afunix_options { $$ = last_driver; free($1); } ; source_afunix_stream_params : string { create_and_set_unix_stream_or_systemd_syslog_source($1, configuration); } source_afunix_options { $$ = last_driver; free($1); } ; /* options are common between dgram & stream */ source_afunix_options : source_afunix_option source_afunix_options | ; source_afunix_option : file_perm_option | source_afsocket_stream_params {} | source_reader_option {} | source_driver_option | unix_socket_option {} | KW_OPTIONAL '(' yesno ')' { last_driver->optional = $3; } | KW_PASS_UNIX_CREDENTIALS '(' yesno ')' { AFUnixSourceDriver *self = (AFUnixSourceDriver*) last_driver; afunix_sd_set_pass_unix_credentials(self, $3); } | KW_CREATE_DIRS '(' yesno ')' { AFUnixSourceDriver *self = (AFUnixSourceDriver*) last_driver; afunix_sd_set_create_dirs(self, $3); } ; source_afinet : KW_UDP '(' _inner_src_context_push source_afinet_udp_params _inner_src_context_pop ')' { $$ = $4; } | KW_TCP '(' _inner_src_context_push source_afinet_tcp_params _inner_src_context_pop ')' { $$ = $4; } | KW_UDP6 '(' _inner_src_context_push source_afinet_udp6_params _inner_src_context_pop ')' { $$ = $4; } | KW_TCP6 '(' _inner_src_context_push source_afinet_tcp6_params _inner_src_context_pop ')' { $$ = $4; } ; source_afinet_udp_params : { AFInetSourceDriver *d = afinet_sd_new_udp(configuration); afinet_grammar_set_source_driver(d); } source_afinet_udp_options { $$ = last_driver; } ; source_afinet_udp6_params : { AFInetSourceDriver *d = afinet_sd_new_udp6(configuration); afinet_grammar_set_source_driver(d); } source_afinet_udp_options { $$ = last_driver; } ; source_afinet_udp_options : source_afinet_udp_option source_afinet_udp_options | ; source_afinet_udp_option : source_afinet_option ; source_afinet_option : KW_LOCALIP '(' string ')' { afinet_sd_set_localip(last_driver, $3); free($3); } | KW_IP '(' string ')' { afinet_sd_set_localip(last_driver, $3); free($3); } | KW_LOCALPORT '(' string_or_number ')' { afinet_sd_set_localport(last_driver, $3); free($3); } | KW_PORT '(' string_or_number ')' { afinet_sd_set_localport(last_driver, $3); free($3); } | source_reader_option | source_driver_option | inet_socket_option ; source_afinet_tcp_params : { AFInetSourceDriver *d = afinet_sd_new_tcp(configuration); afinet_grammar_set_source_driver(d); } source_afinet_tcp_options { $$ = last_driver; } ; source_afinet_tcp6_params : { AFInetSourceDriver *d = afinet_sd_new_tcp6(configuration); afinet_grammar_set_source_driver(d); } source_afinet_tcp_options { $$ = last_driver; } ; source_afinet_tcp_options : source_afinet_tcp_option source_afinet_tcp_options | ; source_afinet_tcp_option : source_afinet_option | KW_TLS { gchar buf[256]; last_tls_context = tls_context_new(TM_SERVER, cfg_lexer_format_location(lexer, &@1, buf, sizeof(buf))); } '(' tls_options ')' { afinet_sd_set_tls_context(last_driver, last_tls_context); } | source_afsocket_stream_params {} ; source_afsocket_stream_params : KW_KEEP_ALIVE '(' yesno ')' { afsocket_sd_set_keep_alive(last_driver, $3); } | KW_MAX_CONNECTIONS '(' positive_integer ')' { afsocket_sd_set_max_connections(last_driver, $3); } | KW_LISTEN_BACKLOG '(' positive_integer ')' { afsocket_sd_set_listen_backlog(last_driver, $3); } | KW_DYNAMIC_WINDOW_SIZE '(' nonnegative_integer ')' { afsocket_sd_set_dynamic_window_size(last_driver, $3); } | KW_DYNAMIC_WINDOW_STATS_FREQ '(' nonnegative_float ')' { afsocket_sd_set_dynamic_window_stats_freq(last_driver, $3); } | KW_DYNAMIC_WINDOW_REALLOC_TICKS '(' nonnegative_integer ')' { afsocket_sd_set_dynamic_window_realloc_ticks(last_driver, $3); } ; source_afsyslog : KW_SYSLOG '(' _inner_src_context_push source_afsyslog_params _inner_src_context_pop ')' { $$ = $4; } ; source_afsyslog_params : { /* we use transport(tcp) transport by default */ AFInetSourceDriver *d = afinet_sd_new_syslog(configuration); afinet_grammar_set_source_driver(d); } source_afsyslog_options { $$ = last_driver; } ; source_afsyslog_options : source_afsyslog_option source_afsyslog_options | ; source_afsyslog_option : source_afinet_option | source_afsocket_transport | source_afsocket_stream_params {} ; source_afnetwork : KW_NETWORK '(' _inner_src_context_push source_afnetwork_params _inner_src_context_pop ')' { $$ = $4; } ; source_afnetwork_params : { /* we use transport(tcp) transport by default */ AFInetSourceDriver *d = afinet_sd_new_network(configuration); afinet_grammar_set_source_driver(d); } source_afnetwork_options { $$ = last_driver; } ; source_afnetwork_options : source_afnetwork_option source_afnetwork_options | ; source_afnetwork_option : source_afinet_option | source_afsocket_transport | source_afsocket_stream_params {} ; source_afsocket_transport : afsocket_transport | KW_TRANSPORT '(' string { Plugin *p; gint context = LL_CONTEXT_SERVER_PROTO; p = cfg_find_plugin(configuration, context, $3); if (p) { /* for transports with grammar */ if (p->parser) { LogProtoServerFactory *sf = cfg_parse_plugin(configuration, p, &@3, last_proto_server_options); ((AFSocketSourceDriver *) last_driver)->proto_factory = sf; } } transport_mapper_set_transport(last_transport_mapper, $3); } ')' { free($3); } | KW_TLS { gchar buf[256]; last_tls_context = tls_context_new(TM_SERVER, cfg_lexer_format_location(lexer, &@1, buf, sizeof(buf))); } '(' tls_options ')' { afinet_sd_set_tls_context(last_driver, last_tls_context); } ; source_systemd_syslog : KW_SYSTEMD_SYSLOG '(' _inner_src_context_push source_systemd_syslog_params _inner_src_context_pop ')' { $$ = $4; } ; source_systemd_syslog_params : { #if ! SYSLOG_NG_ENABLE_SYSTEMD msg_error("systemd-syslog() source cannot be enabled and it is not" " functioning. Please compile your syslog-ng with --enable-systemd" " flag", cfg_lexer_format_location_tag(lexer, &@0)); YYERROR; #else SystemDSyslogSourceDriver *d = systemd_syslog_sd_new(configuration, FALSE); systemd_syslog_grammar_set_source_driver(d); #endif } source_systemd_syslog_options { $$ = last_driver; } ; source_systemd_syslog_options : source_systemd_syslog_option source_systemd_syslog_options | ; source_systemd_syslog_option : source_reader_option | socket_option | source_driver_option ; dest_afunix : KW_UNIX_DGRAM '(' _inner_dest_context_push dest_afunix_dgram_params _inner_dest_context_pop ')' { $$ = $4; } | KW_UNIX_STREAM '(' _inner_dest_context_push dest_afunix_stream_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_afunix_dgram_params : string { AFUnixDestDriver *d = afunix_dd_new_dgram($1, configuration); afunix_grammar_set_dest_driver(d); } dest_afunix_options { $$ = last_driver; free($1); } ; dest_afunix_stream_params : string { AFUnixDestDriver *d = afunix_dd_new_stream($1, configuration); afunix_grammar_set_dest_driver(d); } dest_afunix_options { $$ = last_driver; free($1); } ; dest_afunix_options : dest_afunix_options dest_afunix_option | ; dest_afunix_option : dest_writer_option | dest_afsocket_option | socket_option | dest_driver_option ; dest_afinet : KW_UDP '(' _inner_dest_context_push dest_afinet_udp_params _inner_dest_context_pop ')' { $$ = $4; } | KW_TCP '(' _inner_dest_context_push dest_afinet_tcp_params _inner_dest_context_pop ')' { $$ = $4; } | KW_UDP6 '(' _inner_dest_context_push dest_afinet_udp6_params _inner_dest_context_pop ')' { $$ = $4; } | KW_TCP6 '(' _inner_dest_context_push dest_afinet_tcp6_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_afinet_udp_params : string { AFInetDestDriver *d = afinet_dd_new_udp($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afinet_udp_options { $$ = last_driver; free($1); } ; dest_afinet_udp6_params : string { AFInetDestDriver *d = afinet_dd_new_udp6($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afinet_udp_options { $$ = last_driver; free($1); } ; dest_afinet_udp_options : dest_afinet_udp_options dest_afinet_udp_option | ; dest_afinet_option : KW_LOCALIP '(' string ')' { afinet_dd_set_localip(last_driver, $3); free($3); } | KW_LOCALPORT '(' string_or_number ')' { afinet_dd_set_localport(last_driver, $3); free($3); } | KW_PORT '(' string_or_number ')' { afinet_dd_set_destport(last_driver, $3); free($3); } | KW_DESTPORT '(' string_or_number ')' { afinet_dd_set_destport(last_driver, $3); free($3); } | KW_FAILOVER_SERVERS { afinet_dd_enable_failover(last_driver); } '(' string_list ')' { afinet_dd_add_failovers(last_driver, $4); } | KW_FAILOVER { afinet_dd_enable_failover(last_driver); } '(' dest_failover_options ')' { $$ = $4; } | inet_socket_option | dest_writer_option | dest_afsocket_option | dest_driver_option ; dest_failover_options : KW_SERVERS '(' string_list ')' { afinet_dd_add_failovers(last_driver, $3); } dest_failover_modes_options ; dest_failover_modes_options : dest_failback_options | ; dest_failback_options : KW_FAILBACK { afinet_dd_enable_failback(last_driver); } '(' dest_failback_probe_options ')' ; dest_failback_probe_options : dest_failback_probe_options dest_failback_probe_option | ; dest_failback_probe_option : KW_TCP_PROBE_INTERVAL '(' positive_integer ')' { afinet_dd_set_failback_tcp_probe_interval(last_driver, $3); } | KW_SUCCESSFUL_PROBES_REQUIRED '(' positive_integer ')' { afinet_dd_set_failback_successful_probes_required(last_driver, $3); } ; dest_afinet_dgram_option : KW_SPOOF_SOURCE '(' yesno ')' { afinet_dd_set_spoof_source(last_driver, $3); } | KW_SPOOF_SOURCE_MAX_MSGLEN '(' positive_integer ')' { afinet_dd_set_spoof_source_max_msglen(last_driver, $3); } ; dest_afinet_udp_option : dest_afinet_option | dest_afinet_dgram_option ; dest_afinet_tcp_params : string { AFInetDestDriver *d = afinet_dd_new_tcp($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afinet_tcp_options { $$ = last_driver; free($1); } ; dest_afinet_tcp6_params : string { AFInetDestDriver *d = afinet_dd_new_tcp6($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afinet_tcp_options { $$ = last_driver; free($1); } ; dest_afinet_tcp_options : dest_afinet_tcp_options dest_afinet_tcp_option | ; dest_afinet_tcp_option : dest_afinet_option | KW_TLS { gchar buf[256]; last_tls_context = tls_context_new(TM_CLIENT, cfg_lexer_format_location(lexer, &@1, buf, sizeof(buf))); } '(' dest_tls_options ')' { afinet_dd_set_tls_context(last_driver, last_tls_context); } ; dest_afsocket_option : KW_KEEP_ALIVE '(' yesno ')' { afsocket_dd_set_keep_alive(last_driver, $3); } | KW_CLOSE_ON_INPUT '(' yesno ')' { afsocket_dd_set_close_on_input(last_driver, $3); log_proto_client_options_set_drop_input(last_proto_client_options, !$3); } ; dest_afsyslog : KW_SYSLOG '(' _inner_dest_context_push dest_afsyslog_params _inner_dest_context_pop ')' { $$ = $4; } dest_afsyslog_params : string { AFInetDestDriver *d = afinet_dd_new_syslog($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afsyslog_options { $$ = last_driver; free($1); } ; dest_afsyslog_options : dest_afsyslog_options dest_afsyslog_option | ; dest_afsyslog_option : dest_afinet_option | dest_afsocket_transport ; dest_afnetwork : KW_NETWORK '(' _inner_dest_context_push dest_afnetwork_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_afnetwork_params : string { AFInetDestDriver *d = afinet_dd_new_network($1, configuration); afinet_grammar_set_dest_driver(d); } dest_afnetwork_options { $$ = last_driver; free($1); } ; dest_afnetwork_options : dest_afnetwork_options dest_afnetwork_option | ; dest_afnetwork_option : dest_afinet_option | dest_afsocket_transport ; dest_afsocket_transport : afsocket_transport | KW_TRANSPORT '(' string { Plugin *p; gint context = LL_CONTEXT_CLIENT_PROTO; p = cfg_find_plugin(configuration, context, $3); if (p) { /* for transports with grammar */ if (p->parser) { LogProtoClientFactory *cf = cfg_parse_plugin(configuration, p, &@3, last_proto_client_options); ((AFSocketDestDriver *) last_driver)->proto_factory = cf; } } transport_mapper_set_transport(last_transport_mapper, $3); } ')' { free($3); } | dest_afinet_dgram_option | KW_TLS { gchar buf[256]; last_tls_context = tls_context_new(TM_CLIENT, cfg_lexer_format_location(lexer, &@1, buf, sizeof(buf))); } '(' dest_tls_options ')' { afinet_dd_set_tls_context(last_driver, last_tls_context); } ; afsocket_transport : KW_TRANSPORT '(' KW_TCP ')' { transport_mapper_set_transport(last_transport_mapper, "tcp"); } | KW_TRANSPORT '(' KW_UDP ')' { transport_mapper_set_transport(last_transport_mapper, "udp"); } | KW_TRANSPORT '(' KW_TLS ')' { transport_mapper_set_transport(last_transport_mapper, "tls"); } | KW_IP_PROTOCOL '(' inet_ip_protocol_option ')' { transport_mapper_set_address_family(last_transport_mapper, $3); } ; dest_tls_options : dest_tls_option dest_tls_options | ; dest_tls_option : tls_option | KW_SNI '(' yesno ')' { if ($3) tls_context_set_sni(last_tls_context, ((AFInetDestDriver *)last_driver)->primary); } | KW_OCSP_STAPLING_VERIFY '(' yesno ')' { tls_context_set_ocsp_stapling_verify(last_tls_context, $3); } ; tls_options : tls_option tls_options | ; tls_option : KW_IFDEF { } | KW_PEER_VERIFY '(' yesno ')' { gint verify_mode = $3 ? (TVM_REQUIRED | TVM_TRUSTED) : (TVM_OPTIONAL | TVM_UNTRUSTED); tls_context_set_verify_mode(last_tls_context, verify_mode); } | KW_PEER_VERIFY '(' string ')' { CHECK_ERROR(tls_context_set_verify_mode_by_name(last_tls_context, $3), @3, "unknown peer-verify() argument"); free($3); } | KW_KEY_FILE '(' path_secret ')' { tls_context_set_key_file(last_tls_context, $3); free($3); } | KW_KEYLOG_FILE '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(tls_context_set_keylog_file(last_tls_context, $3, &error), @3, error, "Error setting keylog-file()"); free($3); } | KW_CERT_FILE '(' path_check ')' { tls_context_set_cert_file(last_tls_context, $3); free($3); } | KW_DHPARAM_FILE '(' path_check ')' { tls_context_set_dhparam_file(last_tls_context, $3); free($3); } | KW_PKCS12_FILE '(' path_check ')' { tls_context_set_pkcs12_file(last_tls_context, $3); free($3); } | KW_CA_DIR '(' string ')' { tls_context_set_ca_dir(last_tls_context, $3); free($3); } | KW_CRL_DIR '(' string ')' { tls_context_set_crl_dir(last_tls_context, $3); free($3); } | KW_CA_FILE '(' path_check ')' { tls_context_set_ca_file(last_tls_context, $3); free($3); } | KW_TRUSTED_KEYS '(' string_list ')' { tls_session_set_trusted_fingerprints(last_tls_context, $3); } | KW_TRUSTED_DN '(' string_list ')' { tls_session_set_trusted_dn(last_tls_context, $3); } | KW_CIPHER_SUITE '(' tls_cipher_suites ')' | KW_CIPHER_SUITE '(' string ')' { /* compat for specifying TLS 1.2-or-older ciphers */ tls_context_set_cipher_suite(last_tls_context, $3); free($3); } | KW_SIGALGS '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(tls_context_set_sigalgs(last_tls_context, $3, &error), @3, error, "Error setting sigalgs()"); free($3); } | KW_CLIENT_SIGALGS '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(tls_context_set_client_sigalgs(last_tls_context, $3, &error), @3, error, "Error setting client-sigalgs()"); free($3); } | KW_ECDH_CURVE_LIST '(' string ')' { tls_context_set_ecdh_curve_list(last_tls_context, $3); free($3); } | KW_SSL_OPTIONS '(' string_list ')' { CHECK_ERROR(tls_context_set_ssl_options_by_name(last_tls_context, $3), @3, "unknown ssl-options() argument"); } | KW_ALLOW_COMPRESS '(' yesno ')' { transport_mapper_inet_set_allow_compress(last_transport_mapper, $3); } | KW_CONF_CMDS '(' tls_conf_cmds ')' { GError *error = NULL; CHECK_ERROR_GERROR(tls_context_set_conf_cmds(last_tls_context, $3, &error), @3, error, "Error setting conf-cmds()"); } | KW_ENDIF { } ; tls_conf_cmds : tls_conf_cmd_list_build { $$ = $1; } ; tls_conf_cmd_list_build : string LL_ARROW string tls_conf_cmd_list_build { /* Revers order is important here as this is inside of a bison right recursion */ $$ = g_list_prepend($4, g_strdup($3)); $$ = g_list_prepend($$, g_strdup($1)); free($1); free($3); } | { $$ = NULL; } ; tls_cipher_suites : tls_cipher_suite tls_cipher_suites | ; tls_cipher_suite : KW_TLS12_AND_OLDER '(' string ')' { tls_context_set_cipher_suite(last_tls_context, $3); free($3); } | KW_TLS13 '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(tls_context_set_tls13_cipher_suite(last_tls_context, $3, &error), @3, error, "Error setting cipher-suite(tls13())"); free($3); } ; socket_option : KW_SO_SNDBUF '(' nonnegative_integer ')' { CHECK_ERROR($3 <= G_MAXINT, @3, "Invalid so_sndbuf, it has to be less than %d", G_MAXINT); last_sock_options->so_sndbuf = $3; } | KW_SO_RCVBUF '(' nonnegative_integer ')' { CHECK_ERROR($3 <= G_MAXINT, @3, "Invalid so_rcvbuf, it has to be less than %d", G_MAXINT); last_sock_options->so_rcvbuf = $3; } | KW_SO_BROADCAST '(' yesno ')' { last_sock_options->so_broadcast = $3; } | KW_SO_KEEPALIVE '(' yesno ')' { last_sock_options->so_keepalive = $3; } | KW_SO_REUSEPORT '(' yesno ')' { last_sock_options->so_reuseport = $3; } ; unix_socket_option : socket_option | KW_SO_PASSCRED '(' yesno ')' { socket_options_unix_set_so_passcred(last_sock_options, $3); } ; inet_socket_option : socket_option | KW_IP_TTL '(' nonnegative_integer ')' { ((SocketOptionsInet *) last_sock_options)->ip_ttl = $3; } | KW_IP_TOS '(' nonnegative_integer ')' { ((SocketOptionsInet *) last_sock_options)->ip_tos = $3; } | KW_IP_FREEBIND '(' yesno ')' { ((SocketOptionsInet *) last_sock_options)->ip_freebind = $3; } | KW_INTERFACE '(' string ')' { socket_options_inet_set_interface_name((SocketOptionsInet *) last_sock_options, $3); free($3); } | KW_TCP_KEEPALIVE_TIME '(' nonnegative_integer ')' { CHECK_ERROR(socket_options_inet_set_tcp_keepalive_time((SocketOptionsInet *) last_sock_options, $3), @1, "The tcp-keepalive-time() option is not supported on this platform"); } | KW_TCP_KEEPALIVE_INTVL '(' nonnegative_integer ')' { CHECK_ERROR(socket_options_inet_set_tcp_keepalive_intvl((SocketOptionsInet *) last_sock_options, $3), @1, "The tcp-keepalive-intvl() option is not supported on this platform"); } | KW_TCP_KEEPALIVE_PROBES '(' nonnegative_integer ')' { CHECK_ERROR(socket_options_inet_set_tcp_keepalive_probes((SocketOptionsInet *) last_sock_options, $3), @1, "The tcp-keepalive-probes() option is not supported on this platform"); } ; inet_ip_protocol_option : LL_NUMBER { CHECK_ERROR($1 == 4 || $1 == 6, @1, "ip-protocol option can only be 4 or 6!"); if ($1 == 4) { $$ = AF_INET; } else { $$ = AF_INET6; } } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-parser.c000066400000000000000000000117031450431004300240610ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket.h" #include "driver.h" #include "cfg-parser.h" #include "afsocket-grammar.h" extern int afsocket_debug; int afsocket_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afsocket_keywords[] = { { "unix_dgram", KW_UNIX_DGRAM }, { "unix_stream", KW_UNIX_STREAM }, { "udp", KW_UDP }, { "tcp", KW_TCP }, { "syslog", KW_SYSLOG }, { "network", KW_NETWORK }, #if SYSLOG_NG_ENABLE_IPV6 { "udp6", KW_UDP6 }, { "tcp6", KW_TCP6 }, #endif /* ssl */ { "tls", KW_TLS }, { "peer_verify", KW_PEER_VERIFY }, { "key_file", KW_KEY_FILE }, { "cert_file", KW_CERT_FILE }, { "keylog_file", KW_KEYLOG_FILE }, { "dhparam_file", KW_DHPARAM_FILE }, { "pkcs12_file", KW_PKCS12_FILE }, { "ca_dir", KW_CA_DIR }, { "crl_dir", KW_CRL_DIR }, { "ca_file", KW_CA_FILE }, { "trusted_keys", KW_TRUSTED_KEYS }, { "trusted_dn", KW_TRUSTED_DN }, { "cipher_suite", KW_CIPHER_SUITE }, { "tls12_and_older", KW_TLS12_AND_OLDER }, { "tls13", KW_TLS13 }, { "sigalgs", KW_SIGALGS }, { "client_sigalgs", KW_CLIENT_SIGALGS }, { "ecdh_curve_list", KW_ECDH_CURVE_LIST }, { "curve_list", KW_ECDH_CURVE_LIST, KWS_OBSOLETE, "ecdh_curve_list"}, { "ssl_options", KW_SSL_OPTIONS }, { "sni", KW_SNI }, { "allow_compress", KW_ALLOW_COMPRESS }, { "ocsp_stapling_verify", KW_OCSP_STAPLING_VERIFY }, { "openssl_conf_cmds", KW_CONF_CMDS}, { "localip", KW_LOCALIP }, { "ip", KW_IP }, { "interface", KW_INTERFACE }, { "localport", KW_LOCALPORT }, { "port", KW_PORT }, { "destport", KW_DESTPORT }, { "ip_ttl", KW_IP_TTL }, { "ip_tos", KW_IP_TOS }, { "ip_freebind", KW_IP_FREEBIND }, { "so_broadcast", KW_SO_BROADCAST }, { "so_rcvbuf", KW_SO_RCVBUF }, { "so_sndbuf", KW_SO_SNDBUF }, { "so_keepalive", KW_SO_KEEPALIVE }, { "so_reuseport", KW_SO_REUSEPORT }, { "tcp_keep_alive", KW_SO_KEEPALIVE }, /* old, once deprecated form, but revived in 3.4 */ { "tcp_keepalive", KW_SO_KEEPALIVE }, /* alias for so-keepalive, as tcp is the only option actually using it */ { "tcp_keepalive_time", KW_TCP_KEEPALIVE_TIME }, { "tcp_keepalive_probes", KW_TCP_KEEPALIVE_PROBES }, { "tcp_keepalive_intvl", KW_TCP_KEEPALIVE_INTVL }, { "so_passcred", KW_SO_PASSCRED }, { "local_creds", KW_SO_PASSCRED }, /* BSD specific alias */ { "spoof_source", KW_SPOOF_SOURCE }, { "spoof_source_max_msglen", KW_SPOOF_SOURCE_MAX_MSGLEN }, { "transport", KW_TRANSPORT }, { "ip_protocol", KW_IP_PROTOCOL }, { "max_connections", KW_MAX_CONNECTIONS }, { "listen_backlog", KW_LISTEN_BACKLOG }, { "keep_alive", KW_KEEP_ALIVE }, { "close_on_input", KW_CLOSE_ON_INPUT }, { "systemd_syslog", KW_SYSTEMD_SYSLOG }, { "failover_servers", KW_FAILOVER_SERVERS, KWS_OBSOLETE, "failover-servers has been deprecated, try failover() and use servers() option inside it." }, { "failover", KW_FAILOVER }, { "failback", KW_FAILBACK }, { "servers", KW_SERVERS }, { "tcp_probe_interval", KW_TCP_PROBE_INTERVAL }, { "successful_probes_required", KW_SUCCESSFUL_PROBES_REQUIRED }, { "dynamic_window_size", KW_DYNAMIC_WINDOW_SIZE }, { "dynamic_window_stats_freq", KW_DYNAMIC_WINDOW_STATS_FREQ }, { "dynamic_window_realloc_ticks", KW_DYNAMIC_WINDOW_REALLOC_TICKS }, { NULL } }; CfgParser afsocket_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afsocket_debug, #endif .name = "afsocket", .keywords = afsocket_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) afsocket_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afsocket_, AFSOCKET_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-parser.h000066400000000000000000000022401450431004300240620ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_PARSER_H_INCLUDED #define AFSOCKET_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser afsocket_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afsocket_, AFSOCKET_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-plugin.c000066400000000000000000000063611450431004300240670ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket-parser.h" #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" static Plugin afsocket_plugins[] = { { .type = LL_CONTEXT_SOURCE, .name = "unix-stream", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "unix-stream", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "unix-dgram", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "unix-dgram", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "tcp", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "tcp", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "tcp6", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "tcp6", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "udp", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "udp", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "udp6", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "udp6", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "syslog", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "syslog", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "network", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_DESTINATION, .name = "network", .parser = &afsocket_parser, }, { .type = LL_CONTEXT_SOURCE, .name = "systemd-syslog", .parser = &afsocket_parser, }, }; gboolean afsocket_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afsocket_plugins, G_N_ELEMENTS(afsocket_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afsocket", .version = SYSLOG_NG_VERSION, .description = "The afsocket module provides socket based transports for syslog-ng, such as the udp(), tcp() and syslog() drivers. This module is compiled with SSL support.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afsocket_plugins, .plugins_len = G_N_ELEMENTS(afsocket_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-signals.h000066400000000000000000000034101450431004300242260ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_SIGNALS_H_INCLUDED #define AFSOCKET_SIGNALS_H_INCLUDED #include "signal-slot-connector/signal-slot-connector.h" #include "transport/tls-context.h" typedef struct _AFSocketTLSCertificateValidationSignalData { TLSContext *tls_context; X509_STORE_CTX *ctx; gboolean failure; } AFSocketTLSCertificateValidationSignalData; typedef struct _AFSocketSetupSocketSignalData { gint sock; /* initialized to FALSE by the caller, must be set to TRUE in order to * fail the initialization */ gboolean failure; } AFSocketSetupSocketSignalData; #define signal_afsocket_setup_socket SIGNAL(afsocket, setup_socket, AFSocketSetupSocketSignalData *) #define signal_afsocket_tls_certificate_validation SIGNAL(afsocket, tls_certificate_validation, AFSocketTLSCertificateValidationSignalData *) #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-source.c000066400000000000000000001261761450431004300241000ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket-source.h" #include "messages.h" #include "fdhelpers.h" #include "gsocket.h" #include "stats/stats-registry.h" #include "stats/stats-cluster-single.h" #include "stats/stats-cluster-key-builder.h" #include "mainloop.h" #include "poll-fd-events.h" #include "timeutils/misc.h" #include "afsocket-signals.h" #include #include #include #if SYSLOG_NG_HAVE_LINUX_SOCK_DIAG_H #include #endif #if SYSLOG_NG_ENABLE_AFSOCKET_MEMINFO_METRICS static const glong PACKET_STATS_TIMER_MSECS = 1000; #endif #if SYSLOG_NG_ENABLE_TCP_WRAPPER #include int allow_severity = 0; int deny_severity = 0; #endif static const glong DYNAMIC_WINDOW_TIMER_MSECS = 1000; static const gsize DYNAMIC_WINDOW_REALLOC_TICKS = 5; typedef struct _AFSocketSourceConnection { LogPipe super; struct _AFSocketSourceDriver *owner; LogReader *reader; int sock; GSockAddr *peer_addr; GSockAddr *local_addr; } AFSocketSourceConnection; static void afsocket_sd_close_connection(AFSocketSourceDriver *self, AFSocketSourceConnection *sc); static void _connections_count_set(AFSocketSourceDriver *self, gssize value) { atomic_gssize_set(&self->num_connections, value); } static gssize _connections_count_get(AFSocketSourceDriver *self) { return atomic_gssize_get(&self->num_connections); } static void _connections_count_inc(AFSocketSourceDriver *self) { atomic_gssize_inc(&self->num_connections); } static void _connections_count_dec(AFSocketSourceDriver *self) { atomic_gssize_dec(&self->num_connections); } static gchar * _format_sc_name(AFSocketSourceConnection *self, gint format_type) { static gchar buf[256]; gchar peer_addr[MAX_SOCKADDR_STRING]; if (!self->peer_addr) { /* dgram connection, which means we have no peer, use the bind address */ if (self->owner->bind_addr) { g_sockaddr_format(self->owner->bind_addr, buf, sizeof(buf), format_type); return buf; } else return NULL; } g_sockaddr_format(self->peer_addr, peer_addr, sizeof(peer_addr), format_type); g_snprintf(buf, sizeof(buf), "%s,%s", self->owner->transport_mapper->transport, peer_addr); return buf; } static void afsocket_sc_format_stats_key(AFSocketSourceConnection *self, StatsClusterKeyBuilder *kb) { gchar addr[256]; stats_cluster_key_builder_add_label(kb, stats_cluster_label("driver", "afsocket")); if (!self->peer_addr) { /* dgram connection, which means we have no peer, use the bind address */ if (self->owner->bind_addr) { g_sockaddr_format(self->owner->bind_addr, addr, sizeof(addr), GSA_ADDRESS_ONLY); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("address", addr)); return; } else return; } g_sockaddr_format(self->peer_addr, addr, sizeof(addr), GSA_ADDRESS_ONLY); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("transport", self->owner->transport_mapper->transport)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("address", addr)); } static gchar * afsocket_sc_format_name(AFSocketSourceConnection *self) { return _format_sc_name(self, GSA_FULL); } static LogTransport * afsocket_sc_construct_transport(AFSocketSourceConnection *self, gint fd) { return transport_mapper_construct_log_transport(self->owner->transport_mapper, fd); } static gboolean afsocket_sc_init(LogPipe *s) { AFSocketSourceConnection *self = (AFSocketSourceConnection *) s; LogTransport *transport; LogProtoServer *proto; gboolean restored_kept_alive_source = !!self->reader; if (!restored_kept_alive_source) { transport = afsocket_sc_construct_transport(self, self->sock); /* transport_mapper_inet_construct_log_transport() can return NULL on TLS errors */ if (!transport) return FALSE; proto = log_proto_server_factory_construct(self->owner->proto_factory, transport, &self->owner->reader_options.proto_options.super); if (!proto) { log_transport_free(transport); return FALSE; } self->reader = log_reader_new(s->cfg); log_pipe_set_options(&self->reader->super.super, &self->super.options); log_reader_open(self->reader, proto, poll_fd_events_new(self->sock)); log_reader_set_peer_addr(self->reader, self->peer_addr); log_reader_set_local_addr(self->reader, self->local_addr); } StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); afsocket_sc_format_stats_key(self, kb); log_reader_set_options(self->reader, &self->super, &self->owner->reader_options, self->owner->super.super.id, kb); log_reader_set_name(self->reader, afsocket_sc_format_name(self)); if (!restored_kept_alive_source && self->owner->dynamic_window_pool) log_source_enable_dynamic_window(&self->reader->super, self->owner->dynamic_window_pool); log_pipe_append((LogPipe *) self->reader, s); if (log_pipe_init((LogPipe *) self->reader)) { return TRUE; } else { log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; } return FALSE; } static gboolean afsocket_sc_deinit(LogPipe *s) { AFSocketSourceConnection *self = (AFSocketSourceConnection *) s; log_pipe_unref(&self->owner->super.super.super); self->owner = NULL; log_pipe_deinit((LogPipe *) self->reader); return TRUE; } static void afsocket_sc_notify(LogPipe *s, gint notify_code, gpointer user_data) { AFSocketSourceConnection *self = (AFSocketSourceConnection *) s; switch (notify_code) { case NC_CLOSE: case NC_READ_ERROR: { if (self->owner->transport_mapper->sock_type == SOCK_STREAM) afsocket_sd_close_connection(self->owner, self); break; } default: break; } } static void afsocket_sc_set_owner(AFSocketSourceConnection *self, AFSocketSourceDriver *owner) { GlobalConfig *cfg = log_pipe_get_config(&owner->super.super.super); if (self->owner) log_pipe_unref(&self->owner->super.super.super); log_pipe_ref(&owner->super.super.super); self->owner = owner; self->super.expr_node = owner->super.super.super.expr_node; log_pipe_set_config(&self->super, cfg); if (self->reader) log_pipe_set_config((LogPipe *) self->reader, cfg); log_pipe_append(&self->super, &owner->super.super.super); } /* This should be called by log_reader_free -> log_pipe_unref because this is the control pipe of the reader */ static void afsocket_sc_free(LogPipe *s) { AFSocketSourceConnection *self = (AFSocketSourceConnection *) s; g_sockaddr_unref(self->peer_addr); g_sockaddr_unref(self->local_addr); log_pipe_free_method(s); } AFSocketSourceConnection * afsocket_sc_new(GSockAddr *peer_addr, GSockAddr *local_addr, int fd, GlobalConfig *cfg) { AFSocketSourceConnection *self = g_new0(AFSocketSourceConnection, 1); log_pipe_init_instance(&self->super, cfg); self->super.init = afsocket_sc_init; self->super.deinit = afsocket_sc_deinit; self->super.notify = afsocket_sc_notify; self->super.free_fn = afsocket_sc_free; self->peer_addr = g_sockaddr_ref(peer_addr); self->local_addr = g_sockaddr_ref(local_addr); self->sock = fd; return self; } void afsocket_sd_add_connection(AFSocketSourceDriver *self, AFSocketSourceConnection *connection) { self->connections = g_list_prepend(self->connections, connection); } static void afsocket_sd_kill_connection(AFSocketSourceConnection *connection) { log_pipe_deinit(&connection->super); /* Remove the circular reference between the connection and its * reader (through the connection->reader and reader->control * pointers these have a circular references). */ log_pipe_unref((LogPipe *) connection->reader); connection->reader = NULL; log_pipe_unref(&connection->super); } static void afsocket_sd_kill_connection_list(GList *list) { GList *l, *next; /* NOTE: the list may contain a list of * - deinitialized AFSocketSourceConnection instances (in case the persist-config list is * freed), or * - initialized AFSocketSourceConnection instances (in case keep-alive is turned off) */ for (l = list; l; l = next) { AFSocketSourceConnection *connection = (AFSocketSourceConnection *) l->data; next = l->next; if (connection->owner) connection->owner->connections = g_list_remove(connection->owner->connections, connection); afsocket_sd_kill_connection(connection); } } void afsocket_sd_set_keep_alive(LogDriver *s, gint enable) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; self->connections_kept_alive_across_reloads = enable; } void afsocket_sd_set_max_connections(LogDriver *s, gint max_connections) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; atomic_gssize_set(&self->max_connections, max_connections); } void afsocket_sd_set_listen_backlog(LogDriver *s, gint listen_backlog) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; self->listen_backlog = listen_backlog; } void afsocket_sd_set_dynamic_window_size(LogDriver *s, gint dynamic_window_size) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; self->dynamic_window_size = dynamic_window_size; } void afsocket_sd_set_dynamic_window_stats_freq(LogDriver *s, gdouble stats_freq) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; self->dynamic_window_stats_freq = (glong) (stats_freq * 1000); } void afsocket_sd_set_dynamic_window_realloc_ticks(LogDriver *s, gint realloc_ticks) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; self->dynamic_window_realloc_ticks = realloc_ticks; } static const gchar * afsocket_sd_format_name(const LogPipe *s) { const AFSocketSourceDriver *self = (const AFSocketSourceDriver *)s; static gchar persist_name[1024]; if (s->persist_name) { g_snprintf(persist_name, sizeof(persist_name), "afsocket_sd.%s", self->super.super.super.persist_name); } else { gchar buf[64]; g_snprintf(persist_name, sizeof(persist_name), "afsocket_sd.(%s,%s)", (self->transport_mapper->sock_type == SOCK_STREAM) ? "stream" : "dgram", g_sockaddr_format(self->bind_addr, buf, sizeof(buf), GSA_FULL)); } return persist_name; } static const gchar * afsocket_sd_format_listener_name(const AFSocketSourceDriver *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s.listen_fd", afsocket_sd_format_name((const LogPipe *)self)); return persist_name; } static const gchar * afsocket_sd_format_connections_name(const AFSocketSourceDriver *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s.connections", afsocket_sd_format_name((const LogPipe *)self)); return persist_name; } static const gchar * afsocket_sd_format_dynamic_window_pool_name(const AFSocketSourceDriver *self) { static gchar persist_name[1024]; g_snprintf(persist_name, sizeof(persist_name), "%s.dynamic_window", afsocket_sd_format_name((const LogPipe *)self)); return persist_name; } static gboolean afsocket_sd_process_connection(AFSocketSourceDriver *self, GSockAddr *client_addr, GSockAddr *local_addr, gint fd) { gchar buf[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; #if SYSLOG_NG_ENABLE_TCP_WRAPPER if (client_addr && (client_addr->sa.sa_family == AF_INET #if SYSLOG_NG_ENABLE_IPV6 || client_addr->sa.sa_family == AF_INET6 #endif )) { struct request_info req; request_init(&req, RQ_DAEMON, "syslog-ng", RQ_FILE, fd, 0); fromhost(&req); if (hosts_access(&req) == 0) { msg_error("Syslog connection rejected by tcpd", evt_tag_str("client", g_sockaddr_format(client_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(local_addr, buf2, sizeof(buf2), GSA_FULL))); stats_counter_inc(self->metrics.rejected_connections); return FALSE; } } #endif if (_connections_count_get(self) >= atomic_gssize_get(&self->max_connections)) { msg_error("Number of allowed concurrent connections reached, rejecting connection", evt_tag_str("client", g_sockaddr_format(client_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(local_addr, buf2, sizeof(buf2), GSA_FULL)), evt_tag_str("group_name", self->super.super.group), log_pipe_location_tag(&self->super.super.super), evt_tag_int("max", atomic_gssize_get(&self->max_connections))); stats_counter_inc(self->metrics.rejected_connections); return FALSE; } else { AFSocketSourceConnection *conn; conn = afsocket_sc_new(client_addr, local_addr, fd, self->super.super.super.cfg); afsocket_sc_set_owner(conn, self); if (log_pipe_init(&conn->super)) { afsocket_sd_add_connection(self, conn); _connections_count_inc(self); log_pipe_append(&conn->super, &self->super.super.super); } else { log_pipe_unref(&conn->super); return FALSE; } } return TRUE; } #define MAX_ACCEPTS_AT_A_TIME 30 static void afsocket_sd_accept(gpointer s) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; GSockAddr *peer_addr; GSockAddr *local_addr; gchar buf1[256], buf2[256]; gint new_fd; gboolean res; int accepts = 0; while (accepts < MAX_ACCEPTS_AT_A_TIME) { GIOStatus status; status = g_accept(self->fd, &new_fd, &peer_addr); if (status == G_IO_STATUS_AGAIN) { /* no more connections to accept */ break; } else if (status != G_IO_STATUS_NORMAL) { msg_error("Error accepting new connection", evt_tag_error(EVT_TAG_OSERROR)); return; } g_fd_set_nonblock(new_fd, TRUE); g_fd_set_cloexec(new_fd, TRUE); local_addr = g_socket_get_local_name(new_fd); res = afsocket_sd_process_connection(self, peer_addr, local_addr, new_fd); g_sockaddr_unref(local_addr); if (res) { socket_options_setup_peer_socket(self->socket_options, new_fd, peer_addr); if (peer_addr->sa.sa_family != AF_UNIX) msg_notice("Syslog connection accepted", evt_tag_int("fd", new_fd), evt_tag_str("client", g_sockaddr_format(peer_addr, buf1, sizeof(buf1), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf2, sizeof(buf2), GSA_FULL))); else msg_verbose("Syslog connection accepted", evt_tag_int("fd", new_fd), evt_tag_str("client", g_sockaddr_format(peer_addr, buf1, sizeof(buf1), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf2, sizeof(buf2), GSA_FULL))); } else { close(new_fd); } g_sockaddr_unref(peer_addr); accepts++; } return; } static void afsocket_sd_close_connection(AFSocketSourceDriver *self, AFSocketSourceConnection *sc) { gchar buf1[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; if (sc->peer_addr->sa.sa_family != AF_UNIX) msg_notice("Syslog connection closed", evt_tag_int("fd", sc->sock), evt_tag_str("client", g_sockaddr_format(sc->peer_addr, buf1, sizeof(buf1), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf2, sizeof(buf2), GSA_FULL))); else msg_verbose("Syslog connection closed", evt_tag_int("fd", sc->sock), evt_tag_str("client", g_sockaddr_format(sc->peer_addr, buf1, sizeof(buf1), GSA_FULL)), evt_tag_str("local", g_sockaddr_format(self->bind_addr, buf2, sizeof(buf2), GSA_FULL))); log_reader_close_proto(sc->reader); log_pipe_deinit(&sc->super); self->connections = g_list_remove(self->connections, sc); afsocket_sd_kill_connection(sc); _connections_count_dec(self); } static void _listen_fd_init(AFSocketSourceDriver *self) { IV_FD_INIT(&self->listen_fd); /* the fd is initialized only when the listening socket is opened */ self->listen_fd.fd = -1; self->listen_fd.cookie = self; self->listen_fd.handler_in = afsocket_sd_accept; } static void _listen_fd_start(AFSocketSourceDriver *self) { if (self->listen_fd.fd != -1) iv_fd_register(&self->listen_fd); } static void _listen_fd_stop(AFSocketSourceDriver *self) { if (iv_fd_registered (&self->listen_fd)) iv_fd_unregister(&self->listen_fd); } static void _dynamic_window_timer_start(AFSocketSourceDriver *self) { iv_validate_now(); self->dynamic_window_timer.expires = iv_now; timespec_add_msec(&self->dynamic_window_timer.expires, self->dynamic_window_stats_freq); iv_timer_register(&self->dynamic_window_timer); } static void _dynamic_window_update_statistics_cb(AFSocketSourceConnection *conn) { log_source_dynamic_window_update_statistics(&conn->reader->super); } static void _dynamic_window_update_stats(AFSocketSourceDriver *self) { g_list_foreach(self->connections, (GFunc) _dynamic_window_update_statistics_cb, NULL); } static void _dynamic_window_realloc_cb(AFSocketSourceConnection *conn) { log_source_schedule_dynamic_window_realloc(&conn->reader->super); } static void _dynamic_window_realloc(AFSocketSourceDriver *self) { g_list_foreach(self->connections, (GFunc) _dynamic_window_realloc_cb, NULL); } static void _dynamic_window_set_balanced_window(AFSocketSourceDriver *self) { gssize number_of_connections= _connections_count_get(self); if (number_of_connections <= 0) return; gsize new_balanced_win = self->dynamic_window_pool->pool_size / number_of_connections; if (new_balanced_win == 0) { msg_info("Cannot allocate more dynamic window for new clients. From now, only static window is allocated." "The reason of dynamic-window-pool exhaustion is that the number of clients is larger than the" " dynamic-window-size", evt_tag_long("total_dynamic_window_size", self->dynamic_window_size), evt_tag_int("max_connections", atomic_gssize_get(&self->max_connections)), evt_tag_int("active_connections", number_of_connections), evt_tag_long("dynamic_window_size_for_existing_clients", self->dynamic_window_pool->balanced_window), evt_tag_long("static_window_size", self->reader_options.super.init_window_size)); return; } self->dynamic_window_pool->balanced_window = new_balanced_win; } static gboolean _is_dynamic_window_realloc_needed(AFSocketSourceDriver *self) { return self->dynamic_window_timer_tick >= self->dynamic_window_realloc_ticks; } static void _on_dynamic_window_timer_elapsed(gpointer cookie) { AFSocketSourceDriver *self = (AFSocketSourceDriver *)cookie; if (_is_dynamic_window_realloc_needed(self)) { _dynamic_window_set_balanced_window(self); _dynamic_window_realloc(self); self->dynamic_window_timer_tick = 0; } else { _dynamic_window_update_stats(self); } self->dynamic_window_timer_tick++; msg_trace("Dynamic window timer elapsed", evt_tag_int("tick", self->dynamic_window_timer_tick)); _dynamic_window_timer_start(self); } static void _dynamic_window_timer_init(AFSocketSourceDriver *self) { IV_TIMER_INIT(&self->dynamic_window_timer); self->dynamic_window_timer.cookie = self; self->dynamic_window_timer.handler = _on_dynamic_window_timer_elapsed; } static void _dynamic_window_timer_stop(AFSocketSourceDriver *self) { if (iv_timer_registered(&self->dynamic_window_timer)) iv_timer_unregister(&self->dynamic_window_timer); } static void afsocket_sd_save_dynamic_window_pool(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (self->connections_kept_alive_across_reloads) { cfg_persist_config_add(cfg, afsocket_sd_format_dynamic_window_pool_name(self), self->dynamic_window_pool, (GDestroyNotify) dynamic_window_pool_unref); } else { dynamic_window_pool_unref(self->dynamic_window_pool); } self->dynamic_window_pool = NULL; } static gboolean afsocket_sd_restore_dynamic_window_pool(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (!self->connections_kept_alive_across_reloads) return FALSE; DynamicWindowPool *ctr = cfg_persist_config_fetch(cfg, afsocket_sd_format_dynamic_window_pool_name(self)); if (ctr == NULL) return FALSE; self->dynamic_window_pool = ctr; return TRUE; } static void afsocket_sd_create_dynamic_window_pool(AFSocketSourceDriver *self) { if (self->dynamic_window_size != 0) { self->dynamic_window_pool = dynamic_window_pool_new(self->dynamic_window_size); dynamic_window_pool_init(self->dynamic_window_pool); } } static void afsocket_sd_drop_dynamic_window_pool(AFSocketSourceDriver *self) { if (self->dynamic_window_pool) { dynamic_window_pool_unref(self->dynamic_window_pool); self->dynamic_window_pool = NULL; } } static void afsocket_sd_dynamic_window_start(AFSocketSourceDriver *self) { if (self->dynamic_window_pool == NULL) return; _dynamic_window_timer_start(self); } static void afsocket_sd_dynamic_window_init(AFSocketSourceDriver *self) { if (!afsocket_sd_restore_dynamic_window_pool(self)) afsocket_sd_create_dynamic_window_pool(self); } static void afsocket_sd_dynamic_window_deinit(AFSocketSourceDriver *self) { if (self->dynamic_window_pool == NULL) return; afsocket_sd_save_dynamic_window_pool(self); } static void afsocket_sd_adjust_dynamic_window_size_if_needed(AFSocketSourceDriver *self) { gssize max_connections = atomic_gssize_get(&self->max_connections); if (max_connections > 0 && self->dynamic_window_size > 0) { gsize remainder = self->dynamic_window_size % max_connections; if (remainder) { gsize new_dynamic_window_size = self->dynamic_window_size + (max_connections - remainder); msg_warning("WARNING: dynamic-window-size() is advised to be a multiple of max-connections(), " "to achieve effective dynamic-window usage. Adjusting dynamic-window-size()", evt_tag_int("orig_dynamic_window_size", self->dynamic_window_size), evt_tag_int("new_dynamic_window_size", new_dynamic_window_size), log_pipe_location_tag(&self->super.super.super)); self->dynamic_window_size = new_dynamic_window_size; } if (self->dynamic_window_size / max_connections < 10) { msg_warning("WARNING: dynamic-window-size() is advised to be at least 10 times larger, than max-connections(), " "to achieve effective dynamic-window usage. Please update your configuration", log_pipe_location_tag(&self->super.super.super)); } } } #if SYSLOG_NG_ENABLE_AFSOCKET_MEMINFO_METRICS static void _packet_stats_timer_start(AFSocketSourceDriver *self) { if (!self->metrics.socket_dropped_packets) return; iv_validate_now(); self->metrics.packet_stats_timer.expires = iv_now; timespec_add_msec(&self->metrics.packet_stats_timer.expires, PACKET_STATS_TIMER_MSECS); iv_timer_register(&self->metrics.packet_stats_timer); } static void _on_packet_stats_timer_elapsed(gpointer cookie) { AFSocketSourceDriver *self = (AFSocketSourceDriver *)cookie; guint32 meminfo[SK_MEMINFO_VARS]; socklen_t meminfo_len = sizeof(meminfo); AFSocketSourceConnection *first_connection = self->connections->data; gint sock = first_connection->sock; /* once this getsockopt() fails, we won't try again */ if (getsockopt(sock, SOL_SOCKET, SO_MEMINFO, &meminfo, &meminfo_len) < 0) return; stats_counter_set(self->metrics.socket_dropped_packets, meminfo[SK_MEMINFO_DROPS]); stats_counter_set(self->metrics.socket_receive_buffer_max, meminfo[SK_MEMINFO_RCVBUF]); stats_counter_set(self->metrics.socket_receive_buffer_used, meminfo[SK_MEMINFO_RMEM_ALLOC]); _packet_stats_timer_start(self); } static void _packet_stats_timer_init(AFSocketSourceDriver *self) { IV_TIMER_INIT(&self->metrics.packet_stats_timer); self->metrics.packet_stats_timer.cookie = self; self->metrics.packet_stats_timer.handler = _on_packet_stats_timer_elapsed; } static void _packet_stats_timer_stop(AFSocketSourceDriver *self) { if (iv_timer_registered(&self->metrics.packet_stats_timer)) iv_timer_unregister(&self->metrics.packet_stats_timer); } static void _register_packet_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { gint level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL1; StatsClusterKey sc_key; stats_cluster_single_key_set(&sc_key, "socket_receive_dropped_packets_total", labels, labels_len); stats_register_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_dropped_packets); stats_cluster_single_key_set(&sc_key, "socket_receive_buffer_max_bytes", labels, labels_len); stats_register_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_receive_buffer_max); stats_cluster_single_key_set(&sc_key, "socket_receive_buffer_used_bytes", labels, labels_len); stats_register_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_receive_buffer_used); } static void _unregister_packet_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { StatsClusterKey sc_key; stats_cluster_single_key_set(&sc_key, "socket_receive_dropped_packets_total", labels, labels_len); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_dropped_packets); stats_cluster_single_key_set(&sc_key, "socket_receive_buffer_max_bytes", labels, labels_len); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_receive_buffer_max); stats_cluster_single_key_set(&sc_key, "socket_receive_buffer_used_bytes", labels, labels_len); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.socket_receive_buffer_used); } #else #define _packet_stats_timer_init(s) #define _packet_stats_timer_start(s) #define _packet_stats_timer_stop(s) #define _register_packet_stats(s, l, ll) #define _unregister_packet_stats(s, l, ll) #endif static gboolean afsocket_sd_setup_reader_options(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (self->transport_mapper->sock_type == SOCK_STREAM && !self->window_size_initialized) { /* Distribute the window evenly between each of our possible * connections. This is quite pessimistic and can result in very low * window sizes. Increase that but warn the user at the same time. */ /* NOTE: this changes the initial window size from 100 to 1000. Reasons: * Starting with syslog-ng 3.3, window-size is distributed evenly between * _all_ possible connections to avoid starving. With the defaults this * means that we get a window size of 10 messages log_iw_size(100) / * max_connections(10), but that is incredibly slow, thus bump this value here. */ if (self->reader_options.super.init_window_size == -1) { self->reader_options.super.init_window_size = 1000; if (self->dynamic_window_size != 0) self->reader_options.super.init_window_size = atomic_gssize_get(&self->max_connections) * 10; } guint min_iw_size_per_reader = cfg->min_iw_size_per_reader; if (self->dynamic_window_size != 0) min_iw_size_per_reader = 1; afsocket_sd_adjust_dynamic_window_size_if_needed(self); self->reader_options.super.init_window_size /= atomic_gssize_get(&self->max_connections); if (self->reader_options.super.init_window_size < min_iw_size_per_reader) { msg_warning("WARNING: window sizing for tcp sources were changed in " VERSION_3_3 ", the configuration value was divided by the value of max-connections(). The result was too small, clamping to value of min_iw_size_per_reader. Ensure you have a proper log_fifo_size setting to avoid message loss.", evt_tag_int("orig_log_iw_size", self->reader_options.super.init_window_size), evt_tag_int("new_log_iw_size", min_iw_size_per_reader), evt_tag_int("min_iw_size_per_reader", min_iw_size_per_reader), evt_tag_int("min_log_fifo_size", min_iw_size_per_reader * atomic_gssize_get(&self->max_connections))); self->reader_options.super.init_window_size = min_iw_size_per_reader; } self->window_size_initialized = TRUE; } log_reader_options_init(&self->reader_options, cfg, self->super.super.group); return TRUE; } static gboolean afsocket_sd_setup_transport(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (!transport_mapper_apply_transport(self->transport_mapper, cfg)) return FALSE; if (!self->proto_factory) self->proto_factory = log_proto_server_get_factory(&cfg->plugin_context, self->transport_mapper->logproto); if (!self->proto_factory) { msg_error("Unknown value specified in the transport() option, no such LogProto plugin found", evt_tag_str("transport", self->transport_mapper->logproto)); return FALSE; } self->transport_mapper->create_multitransport = self->proto_factory->use_multitransport; afsocket_sd_setup_reader_options(self); return TRUE; } static void afsocket_sd_save_connections(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (!self->connections_kept_alive_across_reloads || !cfg->persist) { afsocket_sd_kill_connection_list(self->connections); } else { GList *p; /* for SOCK_STREAM source drivers this is a list, for * SOCK_DGRAM this is a single connection */ for (p = self->connections; p; p = p->next) { log_pipe_deinit((LogPipe *) p->data); } cfg_persist_config_add(cfg, afsocket_sd_format_connections_name(self), self->connections, (GDestroyNotify)afsocket_sd_kill_connection_list); } self->connections = NULL; } static void afsocket_sd_restore_kept_alive_connections(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); /* fetch persistent connections first */ if (self->connections_kept_alive_across_reloads) { GList *p = NULL; self->connections = cfg_persist_config_fetch(cfg, afsocket_sd_format_connections_name(self)); _connections_count_set(self, 0); for (p = self->connections; p; p = p->next) { afsocket_sc_set_owner((AFSocketSourceConnection *) p->data, self); if (log_pipe_init((LogPipe *) p->data)) { _connections_count_inc(self); } else { AFSocketSourceConnection *sc = (AFSocketSourceConnection *)p->data; self->connections = g_list_remove(self->connections, sc); afsocket_sd_kill_connection((AFSocketSourceConnection *)sc); } } } } /* afsocket */ static void afsocket_sd_init_watches(AFSocketSourceDriver *self) { _dynamic_window_timer_init(self); _listen_fd_init(self); _packet_stats_timer_init(self); } static void afsocket_sd_start_watches(AFSocketSourceDriver *self) { _listen_fd_start(self); afsocket_sd_dynamic_window_start(self); _packet_stats_timer_start(self); } static void afsocket_sd_stop_watches(AFSocketSourceDriver *self) { _packet_stats_timer_stop(self); _dynamic_window_timer_stop(self); _listen_fd_stop(self); } static gboolean _sd_open_stream_finalize(gpointer arg) { AFSocketSourceDriver *self = (AFSocketSourceDriver *)arg; /* set up listening source */ if (listen(self->fd, self->listen_backlog) < 0) { msg_error("Error during listen()", evt_tag_error(EVT_TAG_OSERROR)); close(self->fd); self->fd = -1; return FALSE; } self->listen_fd.fd = self->fd; afsocket_sd_start_watches(self); char buf[256]; msg_info("Accepting connections", evt_tag_str("addr", g_sockaddr_format(self->bind_addr, buf, sizeof(buf), GSA_FULL))); return TRUE; } static gboolean afsocket_sd_open_socket(AFSocketSourceDriver *self, gint *sock) { if (!transport_mapper_open_socket(self->transport_mapper, self->socket_options, self->bind_addr, self->bind_addr, AFSOCKET_DIR_RECV, sock)) return FALSE; AFSocketSetupSocketSignalData signal_data = {0}; signal_data.sock = *sock; EMIT(self->super.super.super.signal_slot_connector, signal_afsocket_setup_socket, &signal_data); return !signal_data.failure; } static gboolean _sd_open_stream(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); gint sock = -1; if (self->connections_kept_alive_across_reloads) { /* NOTE: this assumes that fd 0 will never be used for listening fds, * main.c opens fd 0 so this assumption can hold */ gpointer config_result = cfg_persist_config_fetch(cfg, afsocket_sd_format_listener_name(self)); sock = GPOINTER_TO_UINT(config_result) - 1; } if (sock == -1) { if (!afsocket_sd_acquire_socket(self, &sock)) return self->super.super.optional; if (sock == -1 && !afsocket_sd_open_socket(self, &sock)) return self->super.super.optional; } self->fd = sock; return transport_mapper_async_init(self->transport_mapper, _sd_open_stream_finalize, self); } static gboolean _sd_open_dgram(AFSocketSourceDriver *self) { gint sock = -1; if (!self->connections) { if (!afsocket_sd_acquire_socket(self, &sock)) return self->super.super.optional; if (sock == -1 && !afsocket_sd_open_socket(self, &sock)) return self->super.super.optional; } self->fd = -1; /* we either have self->connections != NULL, or sock contains a new fd */ if (!(self->connections || afsocket_sd_process_connection(self, NULL, self->bind_addr, sock))) return FALSE; if (!transport_mapper_init(self->transport_mapper)) return FALSE; afsocket_sd_start_watches(self); return TRUE; } static gboolean afsocket_sd_open_listener(AFSocketSourceDriver *self) { if (self->transport_mapper->sock_type == SOCK_STREAM) { return _sd_open_stream(self); } else { return _sd_open_dgram(self); } } static void afsocket_sd_close_fd(gpointer value) { gint fd = GPOINTER_TO_UINT(value) - 1; close(fd); } static void afsocket_sd_save_listener(AFSocketSourceDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); afsocket_sd_stop_watches(self); if (self->transport_mapper->sock_type == SOCK_STREAM) { if (!self->connections_kept_alive_across_reloads) { msg_verbose("Closing listener fd", evt_tag_int("fd", self->fd)); close(self->fd); } else { /* NOTE: the fd is incremented by one when added to persistent config * as persist config cannot store NULL */ cfg_persist_config_add(cfg, afsocket_sd_format_listener_name(self), GUINT_TO_POINTER(self->fd + 1), afsocket_sd_close_fd); } } } gboolean afsocket_sd_setup_addresses_method(AFSocketSourceDriver *self) { return TRUE; } static void _register_stream_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { gint level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL0; StatsClusterKey sc_key; stats_cluster_single_key_set(&sc_key, "socket_connections", labels, labels_len); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, self->transport_mapper->stats_source | SCS_SOURCE, self->super.super.group, afsocket_sd_format_name(&self->super.super.super), "connections"); stats_register_external_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->num_connections); _connections_count_set(self, 0); stats_cluster_single_key_set(&sc_key, "socket_max_connections", labels, labels_len); stats_register_external_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->max_connections); level = log_pipe_is_internal(&self->super.super.super) ? STATS_LEVEL3 : STATS_LEVEL1; stats_cluster_single_key_set(&sc_key, "socket_rejected_connections_total", labels, labels_len); stats_register_counter(level, &sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.rejected_connections); } static void _unregister_stream_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { StatsClusterKey sc_key; stats_cluster_single_key_set(&sc_key, "socket_connections", labels, labels_len); stats_cluster_single_key_add_legacy_alias_with_name(&sc_key, self->transport_mapper->stats_source | SCS_SOURCE, self->super.super.group, afsocket_sd_format_name(&self->super.super.super), "connections"); stats_unregister_external_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->num_connections); stats_cluster_single_key_set(&sc_key, "socket_max_connections", labels, labels_len); stats_unregister_external_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->max_connections); stats_cluster_single_key_set(&sc_key, "socket_rejected_connections_total", labels, labels_len); stats_unregister_counter(&sc_key, SC_TYPE_SINGLE_VALUE, &self->metrics.rejected_connections); } static void _register_dgram_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { _register_packet_stats(self, labels, labels_len); } static void _unregister_dgram_stats(AFSocketSourceDriver *self, StatsClusterLabel *labels, gsize labels_len) { _unregister_packet_stats(self, labels, labels_len); } static void afsocket_sd_register_stats(AFSocketSourceDriver *self) { gchar addr[256]; g_sockaddr_format(self->bind_addr, addr, sizeof(addr), GSA_FULL); StatsClusterLabel labels[] = { stats_cluster_label("id", self->super.super.id), stats_cluster_label("driver", "afsocket"), stats_cluster_label("transport", (self->transport_mapper->sock_type == SOCK_STREAM) ? "stream" : "dgram"), stats_cluster_label("address", addr), stats_cluster_label("direction", "input"), }; stats_lock(); if (self->transport_mapper->sock_type == SOCK_STREAM) _register_stream_stats(self, labels, G_N_ELEMENTS(labels)); else _register_dgram_stats(self, labels, G_N_ELEMENTS(labels)); stats_unlock(); } static void afsocket_sd_unregister_stats(AFSocketSourceDriver *self) { gchar addr[256]; g_sockaddr_format(self->bind_addr, addr, sizeof(addr), GSA_FULL); StatsClusterLabel labels[] = { stats_cluster_label("id", self->super.super.id), stats_cluster_label("driver", "afsocket"), stats_cluster_label("transport", (self->transport_mapper->sock_type == SOCK_STREAM) ? "stream" : "dgram"), stats_cluster_label("address", addr), stats_cluster_label("direction", "input"), }; stats_lock(); if (self->transport_mapper->sock_type == SOCK_STREAM) _unregister_stream_stats(self, labels, G_N_ELEMENTS(labels)); else _unregister_dgram_stats(self, labels, G_N_ELEMENTS(labels)); stats_unlock(); } gboolean afsocket_sd_init_method(LogPipe *s) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; if (!log_src_driver_init_method(s)) return FALSE; if (!afsocket_sd_setup_transport(self) || !afsocket_sd_setup_addresses(self)) return FALSE; afsocket_sd_register_stats(self); afsocket_sd_dynamic_window_init(self); afsocket_sd_restore_kept_alive_connections(self); if (!afsocket_sd_open_listener(self)) { /* returning FALSE, so deinit is not called */ afsocket_sd_unregister_stats(self); afsocket_sd_drop_dynamic_window_pool(self); return FALSE; } return TRUE; } gboolean afsocket_sd_deinit_method(LogPipe *s) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; afsocket_sd_save_listener(self); afsocket_sd_save_connections(self); afsocket_sd_dynamic_window_deinit(self); afsocket_sd_unregister_stats(self); return log_src_driver_deinit_method(s); } static void afsocket_sd_notify(LogPipe *s, gint notify_code, gpointer user_data) { switch (notify_code) { case NC_CLOSE: case NC_READ_ERROR: { g_assert_not_reached(); break; } default: break; } } void afsocket_sd_free_method(LogPipe *s) { AFSocketSourceDriver *self = (AFSocketSourceDriver *) s; log_reader_options_destroy(&self->reader_options); transport_mapper_free(self->transport_mapper); socket_options_free(self->socket_options); g_sockaddr_unref(self->bind_addr); self->bind_addr = NULL; log_src_driver_free(s); } void afsocket_sd_init_instance(AFSocketSourceDriver *self, SocketOptions *socket_options, TransportMapper *transport_mapper, GlobalConfig *cfg) { log_src_driver_init_instance(&self->super, cfg); self->super.super.super.init = afsocket_sd_init_method; self->super.super.super.deinit = afsocket_sd_deinit_method; self->super.super.super.free_fn = afsocket_sd_free_method; self->super.super.super.notify = afsocket_sd_notify; self->super.super.super.generate_persist_name = afsocket_sd_format_name; self->setup_addresses = afsocket_sd_setup_addresses_method; self->socket_options = socket_options; self->transport_mapper = transport_mapper; atomic_gssize_set(&self->max_connections, 10); self->listen_backlog = 255; self->dynamic_window_stats_freq = DYNAMIC_WINDOW_TIMER_MSECS; self->dynamic_window_realloc_ticks = DYNAMIC_WINDOW_REALLOC_TICKS; self->connections_kept_alive_across_reloads = TRUE; log_reader_options_defaults(&self->reader_options); self->reader_options.super.stats_level = STATS_LEVEL1; self->reader_options.super.stats_source = transport_mapper->stats_source; afsocket_sd_init_watches(self); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-source.h000066400000000000000000000077331450431004300241020ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_SOURCE_H_INCLUDED #define AFSOCKET_SOURCE_H_INCLUDED #include "afsocket.h" #include "socket-options.h" #include "transport-mapper.h" #include "driver.h" #include "logreader.h" #include "dynamic-window-pool.h" #include "atomic-gssize.h" #include "stats/stats-counter.h" #include typedef struct _AFSocketSourceDriver AFSocketSourceDriver; struct _AFSocketSourceDriver { LogSrcDriver super; guint32 connections_kept_alive_across_reloads:1, window_size_initialized:1; struct iv_fd listen_fd; struct iv_timer dynamic_window_timer; gsize dynamic_window_size; gsize dynamic_window_timer_tick; glong dynamic_window_stats_freq; gint dynamic_window_realloc_ticks; gint fd; LogReaderOptions reader_options; DynamicWindowPool *dynamic_window_pool; LogProtoServerFactory *proto_factory; struct { struct iv_timer packet_stats_timer; StatsCounterItem *socket_dropped_packets; StatsCounterItem *socket_receive_buffer_max; StatsCounterItem *socket_receive_buffer_used; StatsCounterItem *rejected_connections; } metrics; GSockAddr *bind_addr; atomic_gssize max_connections; atomic_gssize num_connections; gint listen_backlog; GList *connections; SocketOptions *socket_options; TransportMapper *transport_mapper; /* * Apply transport options, set up bind_addr based on the * information processed during parse time. This used to be * constructed during the parser, however that made the ordering of * various options matter and behave incorrectly when the port() was * specified _after_ transport(). Now, it collects the information, * and then applies them with a separate call to apply_transport() * during init(). */ gboolean (*setup_addresses)(AFSocketSourceDriver *s); /* optionally acquire a socket from the runtime environment (e.g. systemd) */ gboolean (*acquire_socket)(AFSocketSourceDriver *s, gint *fd); }; void afsocket_sd_set_keep_alive(LogDriver *self, gint enable); void afsocket_sd_set_max_connections(LogDriver *self, gint max_connections); void afsocket_sd_set_listen_backlog(LogDriver *self, gint listen_backlog); void afsocket_sd_set_dynamic_window_size(LogDriver *self, gint dynamic_window_size); void afsocket_sd_set_dynamic_window_stats_freq(LogDriver *self, gdouble stats_freq); void afsocket_sd_set_dynamic_window_realloc_ticks(LogDriver *self, gint realloc_ticks); static inline gboolean afsocket_sd_acquire_socket(AFSocketSourceDriver *s, gint *fd) { if (s->acquire_socket) return s->acquire_socket(s, fd); *fd = -1; return TRUE; } static inline gboolean afsocket_sd_setup_addresses(AFSocketSourceDriver *s) { return s->setup_addresses(s); } gboolean afsocket_sd_setup_addresses_method(AFSocketSourceDriver *self); gboolean afsocket_sd_init_method(LogPipe *s); gboolean afsocket_sd_deinit_method(LogPipe *s); void afsocket_sd_free_method(LogPipe *self); void afsocket_sd_init_instance(AFSocketSourceDriver *self, SocketOptions *socket_options, TransportMapper *transport_mapper, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket-systemd-override.h000066400000000000000000000022261450431004300260770ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Tibor Benke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_GRAMMAR_EXTRA_H_INCLUDED #define AFSOCKET_GRAMMAR_EXTRA_H_INCLUDED void afunix_grammar_set_source_driver(AFUnixSourceDriver *sd); void systemd_syslog_grammar_set_source_driver(SystemDSyslogSourceDriver *sd); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket.c000066400000000000000000000017211450431004300225660ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket.h" syslog-ng-syslog-ng-4.4.0/modules/afsocket/afsocket.h000066400000000000000000000020241450431004300225700ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_H_INCLUDED #define AFSOCKET_H_INCLUDED #include "syslog-ng.h" #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afunix-dest.c000066400000000000000000000054111450431004300232160ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afunix-dest.h" #include "messages.h" #include "gprocess.h" #include #include #include #include #include #include #include static const gchar * afunix_dd_get_dest_name(const AFSocketDestDriver *s) { const AFUnixDestDriver *self = (const AFUnixDestDriver *)s; static gchar buf[256]; g_snprintf(buf, sizeof(buf), "localhost.afunix:%s", self->filename); return buf; } static gboolean afunix_dd_setup_addresses(AFSocketDestDriver *s) { AFUnixDestDriver *self = (AFUnixDestDriver *) s; if (!afsocket_dd_setup_addresses_method(s)) return FALSE; if (!self->super.bind_addr) self->super.bind_addr = g_sockaddr_unix_new(NULL); if (!self->super.dest_addr) self->super.dest_addr = g_sockaddr_unix_new(self->filename); return TRUE; } static void afunix_dd_free(LogPipe *s) { AFUnixDestDriver *self = (AFUnixDestDriver *) s; g_free(self->filename); afsocket_dd_free(s); } AFUnixDestDriver * afunix_dd_new_instance(TransportMapper *transport_mapper, gchar *filename, GlobalConfig *cfg) { AFUnixDestDriver *self = g_new0(AFUnixDestDriver, 1); afsocket_dd_init_instance(&self->super, socket_options_new(), transport_mapper, cfg); self->super.super.super.super.free_fn = afunix_dd_free; self->super.setup_addresses = afunix_dd_setup_addresses; self->super.writer_options.mark_mode = MM_NONE; self->super.get_dest_name = afunix_dd_get_dest_name; self->filename = g_strdup(filename); return self; } AFUnixDestDriver * afunix_dd_new_dgram(gchar *filename, GlobalConfig *cfg) { return afunix_dd_new_instance(transport_mapper_unix_dgram_new(), filename, cfg); } AFUnixDestDriver * afunix_dd_new_stream(gchar *filename, GlobalConfig *cfg) { return afunix_dd_new_instance(transport_mapper_unix_stream_new(), filename, cfg); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afunix-dest.h000066400000000000000000000025001450431004300232170ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFUNIX_DEST_H_INCLUDED #define AFUNIX_DEST_H_INCLUDED #include "afsocket-dest.h" #include "transport-mapper-unix.h" typedef struct _AFUnixDestDriver { AFSocketDestDriver super; gchar *filename; } AFUnixDestDriver; AFUnixDestDriver *afunix_dd_new_dgram(gchar *filename, GlobalConfig *cfg); AFUnixDestDriver *afunix_dd_new_stream(gchar *filename, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/afunix-source.c000066400000000000000000000133371450431004300235650ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afunix-source.h" #include "messages.h" #include "gprocess.h" #include "transport-mapper-unix.h" #include "socket-options-unix.h" #include #include #include #include #include #include #include static gboolean afunix_sd_setup_addresses(AFSocketSourceDriver *s) { AFUnixSourceDriver *self = (AFUnixSourceDriver *) s; if (!afsocket_sd_setup_addresses_method(s)) return FALSE; if (self->create_dirs) { if (!file_perm_options_create_containing_directory(&self->file_perm_options, self->filename)) return FALSE; } if (!self->super.bind_addr) self->super.bind_addr = g_sockaddr_unix_new(self->filename); return TRUE; } static gboolean afunix_sd_adjust_reader_options(AFUnixSourceDriver *self, GlobalConfig *cfg) { self->super.reader_options.parse_options.flags |= LP_LOCAL; if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_2)) { msg_warning_once("WARNING: the expected message format is being changed for unix-domain transports to improve " "syslogd compatibity with " VERSION_3_2 ". If you are using custom " "applications which bypass the syslog() API, you might " "need the 'expect-hostname' flag to get the old behaviour back"); } else { self->super.reader_options.parse_options.flags &= ~LP_EXPECT_HOSTNAME; } return TRUE; } static gboolean afunix_sd_apply_perms_to_socket(AFUnixSourceDriver *self) { cap_t saved_caps; saved_caps = g_process_cap_save(); g_process_enable_cap("cap_chown"); g_process_enable_cap("cap_fowner"); g_process_enable_cap("cap_dac_override"); file_perm_options_apply_file(&self->file_perm_options, self->filename); g_process_cap_restore(saved_caps); return TRUE; } static void afunix_sd_propagate_legacy_pass_unix_credentials_option(AFUnixSourceDriver *self, GlobalConfig *cfg) { if (self->pass_unix_credentials == -1 && cfg->pass_unix_credentials == -1) { /* both local & global legacy options are unset, we use the values as * specified by the new so-passcred() option (TRUE by default) */ } else if (self->pass_unix_credentials != -1) { /* legacy, local option is set, force SO_PASSCRED to that value */ socket_options_unix_set_so_passcred(self->super.socket_options, self->pass_unix_credentials); } else if (cfg->pass_unix_credentials != -1) { /* legacy, global option is set, force SO_PASSCRED to that value, this * way a local so-passcred() cannot override a global * pass-unix-credentials() option */ socket_options_unix_set_so_passcred(self->super.socket_options, cfg->pass_unix_credentials); } } static gboolean afunix_sd_init(LogPipe *s) { AFUnixSourceDriver *self = (AFUnixSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (self->create_dirs == -1) self->create_dirs = cfg->create_dirs; afunix_sd_propagate_legacy_pass_unix_credentials_option(self, cfg); file_perm_options_inherit_dont_change(&self->file_perm_options); return afsocket_sd_init_method(s) && afunix_sd_apply_perms_to_socket(self); } static void afunix_sd_free(LogPipe *s) { AFUnixSourceDriver *self = (AFUnixSourceDriver *) s; g_free(self->filename); afsocket_sd_free_method(s); } AFUnixSourceDriver * afunix_sd_new_instance(TransportMapper *transport_mapper, gchar *filename, GlobalConfig *cfg) { AFUnixSourceDriver *self = g_new0(AFUnixSourceDriver, 1); afsocket_sd_init_instance(&self->super, socket_options_unix_new(), transport_mapper, cfg); self->super.super.super.super.init = afunix_sd_init; self->super.super.super.super.free_fn = afunix_sd_free; self->super.setup_addresses = afunix_sd_setup_addresses; atomic_gssize_set(&self->super.max_connections, 256); self->filename = g_strdup(filename); file_perm_options_defaults(&self->file_perm_options); file_perm_options_set_file_perm(&self->file_perm_options, 0666); self->pass_unix_credentials = -1; self->create_dirs = -1; afunix_sd_adjust_reader_options(self, cfg); return self; } void afunix_sd_set_pass_unix_credentials(AFUnixSourceDriver *self, gboolean pass) { self->pass_unix_credentials = pass; } void afunix_sd_set_create_dirs(AFUnixSourceDriver *self, gboolean create_dirs) { self->create_dirs = create_dirs; } AFUnixSourceDriver * afunix_sd_new_dgram(gchar *filename, GlobalConfig *cfg) { return afunix_sd_new_instance(transport_mapper_unix_dgram_new(), filename, cfg); } AFUnixSourceDriver * afunix_sd_new_stream(gchar *filename, GlobalConfig *cfg) { AFUnixSourceDriver *self = afunix_sd_new_instance(transport_mapper_unix_stream_new(), filename, cfg); self->super.reader_options.super.init_window_size = atomic_gssize_get(&self->super.max_connections )* 100; return self; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/afunix-source.h000066400000000000000000000031421450431004300235630ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFUNIX_SOURCE_H_INCLUDED #define AFUNIX_SOURCE_H_INCLUDED #include "afsocket-source.h" #include "transport-mapper-unix.h" #include "file-perms.h" typedef struct _AFUnixSourceDriver { AFSocketSourceDriver super; gchar *filename; FilePermOptions file_perm_options; gint pass_unix_credentials; gint create_dirs; } AFUnixSourceDriver; AFUnixSourceDriver *afunix_sd_new_stream(gchar *filename, GlobalConfig *cfg); AFUnixSourceDriver *afunix_sd_new_dgram(gchar *filename, GlobalConfig *cfg); void afunix_sd_set_pass_unix_credentials(AFUnixSourceDriver *self, gboolean pass); void afunix_sd_set_create_dirs(AFUnixSourceDriver *self, gboolean create_dirs); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/compat-unix-creds.c000066400000000000000000000022671450431004300243370ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "compat-unix-creds.h" void setsockopt_so_passcred(gint fd, gint onoff) { #ifdef LOCAL_CREDS setsockopt(fd, 0, LOCAL_CREDS, &onoff, sizeof(onoff)); #else #ifdef SO_PASSCRED setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &onoff, sizeof(onoff)); #endif #endif } syslog-ng-syslog-ng-4.4.0/modules/afsocket/compat-unix-creds.h000066400000000000000000000030731450431004300243400ustar00rootroot00000000000000/* * Copyright (c) 2014 Balabit * Copyright (c) 2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef _SYSLOG_NG_UNIX_CREDENTIALS_H #define _SYSLOG_NG_UNIX_CREDENTIALS_H #include #include #include "syslog-ng.h" #if defined(__linux__) # if SYSLOG_NG_HAVE_STRUCT_UCRED && SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR # define CRED_PASS_SUPPORTED # define cred_t struct ucred # define cred_get(c,x) ((c)->x) # endif #elif defined(__FreeBSD__) # if SYSLOG_NG_HAVE_STRUCT_CMSGCRED && SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR # define CRED_PASS_SUPPORTED # define SCM_CREDENTIALS SCM_CREDS # define cred_t struct cmsgcred # define cred_get(c,x) ((c)->cmcred_##x) # endif #endif void setsockopt_so_passcred(gint fd, gint enable); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options-inet.c000066400000000000000000000177231450431004300247160ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "socket-options-inet.h" #include "gsockaddr.h" #include "messages.h" #include "gprocess.h" #include #include #ifndef SOL_IP #define SOL_IP IPPROTO_IP #endif #ifndef SOL_IPV6 #define SOL_IPV6 IPPROTO_IPV6 #endif #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif #ifdef SO_BINDTODEVICE static int socket_options_inet_set_interface(SocketOptionsInet *self, gint fd) { cap_t saved_caps; int result, rc; saved_caps = g_process_cap_save(); g_process_enable_cap("cap_net_raw"); rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, self->interface_name, strlen(self->interface_name)); result = (rc < 0) ? errno : 0; g_process_cap_restore(saved_caps); return result; } static gboolean socket_options_inet_try_to_set_interface(SocketOptionsInet *self, gint fd) { int result = socket_options_inet_set_interface(self, fd); if (result != 0) { msg_error("Can't bind to interface", evt_tag_str("interface", self->interface_name), evt_tag_errno("error", result)); return FALSE; } return TRUE; } #else static gboolean socket_options_inet_try_to_set_interface(SocketOptionsInet *self, gint fd) { msg_error("interface() is set but no SO_BINDTODEVICE setsockopt on this platform"); return FALSE; } #endif static inline gboolean _tcp_keepalive_timers_supported(void) { #ifdef SYSLOG_NG_HAVE_TCP_KEEPALIVE_TIMERS return TRUE; #else return FALSE; #endif } gboolean socket_options_inet_set_tcp_keepalive_time(SocketOptionsInet *self, gint tcp_keepalive_time) { if (!_tcp_keepalive_timers_supported()) return FALSE; self->tcp_keepalive_time = tcp_keepalive_time; return TRUE; } gboolean socket_options_inet_set_tcp_keepalive_intvl(SocketOptionsInet *self, gint tcp_keepalive_intvl) { if (!_tcp_keepalive_timers_supported()) return FALSE; self->tcp_keepalive_intvl = tcp_keepalive_intvl; return TRUE; } gboolean socket_options_inet_set_tcp_keepalive_probes(SocketOptionsInet *self, gint tcp_keepalive_probes) { if (!_tcp_keepalive_timers_supported()) return FALSE; self->tcp_keepalive_probes = tcp_keepalive_probes; return TRUE; } static void socket_options_inet_setup_tcp_keepalive_timers(SocketOptionsInet *self, gint fd) { #ifdef SYSLOG_NG_HAVE_TCP_KEEPALIVE_TIMERS if (self->tcp_keepalive_time > 0) setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &self->tcp_keepalive_time, sizeof(self->tcp_keepalive_time)); if (self->tcp_keepalive_probes > 0) setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &self->tcp_keepalive_probes, sizeof(self->tcp_keepalive_probes)); if (self->tcp_keepalive_intvl > 0) setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &self->tcp_keepalive_intvl, sizeof(self->tcp_keepalive_intvl)); #endif } static gboolean socket_options_inet_setup_socket(SocketOptions *s, gint fd, GSockAddr *addr, AFSocketDirection dir) { SocketOptionsInet *self = (SocketOptionsInet *) s; gint off = 0; gint on = 1; if (!socket_options_setup_socket_method(s, fd, addr, dir)) return FALSE; if (self->interface_name) { if (!socket_options_inet_try_to_set_interface(self, fd)) return FALSE; } switch (addr->sa.sa_family) { case AF_INET: { struct ip_mreq mreq; if (IN_MULTICAST(ntohl(g_sockaddr_inet_get_address(addr).s_addr))) { if (dir & AFSOCKET_DIR_RECV) { memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr = g_sockaddr_inet_get_address(addr); mreq.imr_interface.s_addr = INADDR_ANY; setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &off, sizeof(off)); } if (dir & AFSOCKET_DIR_SEND) { if (self->ip_ttl) setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &self->ip_ttl, sizeof(self->ip_ttl)); } } else { if (self->ip_ttl && (dir & AFSOCKET_DIR_SEND)) setsockopt(fd, SOL_IP, IP_TTL, &self->ip_ttl, sizeof(self->ip_ttl)); } if (self->ip_tos && (dir & AFSOCKET_DIR_SEND)) setsockopt(fd, SOL_IP, IP_TOS, &self->ip_tos, sizeof(self->ip_tos)); if (self->ip_freebind && (dir & AFSOCKET_DIR_RECV)) { #ifdef IP_FREEBIND setsockopt(fd, SOL_IP, IP_FREEBIND, &on, sizeof(on)); #else msg_error("ip-freebind() is set but no IP_FREEBIND setsockopt on this platform"); return FALSE; #endif } break; } #if SYSLOG_NG_ENABLE_IPV6 case AF_INET6: { struct ipv6_mreq mreq6; if (IN6_IS_ADDR_MULTICAST(&g_sockaddr_inet6_get_sa(addr)->sin6_addr)) { if (dir & AFSOCKET_DIR_RECV) { memset(&mreq6, 0, sizeof(mreq6)); mreq6.ipv6mr_multiaddr = *g_sockaddr_inet6_get_address(addr); mreq6.ipv6mr_interface = 0; setsockopt(fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)); setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); } if (dir & AFSOCKET_DIR_SEND) { if (self->ip_ttl) setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &self->ip_ttl, sizeof(self->ip_ttl)); } } else { if (self->ip_ttl && (dir & AFSOCKET_DIR_SEND)) setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &self->ip_ttl, sizeof(self->ip_ttl)); } if (self->ip_freebind && (dir & AFSOCKET_DIR_RECV)) { #ifdef IP_FREEBIND /* NOTE: there's no separate IP_FREEBIND option for IPV6, it re-uses the IPv4 one */ setsockopt(fd, SOL_IP, IP_FREEBIND, &on, sizeof(on)); #else msg_error("ip-freebind() is set but no IP_FREEBIND setsockopt on this platform"); return FALSE; #endif } break; } #endif default: g_assert_not_reached(); break; } return TRUE; } static gboolean socket_options_inet_setup_peer_socket(SocketOptions *s, gint fd, GSockAddr *addr) { SocketOptionsInet *self = (SocketOptionsInet *) s; if(!socket_options_setup_peer_socket_method(s, fd, addr)) return FALSE; socket_options_inet_setup_tcp_keepalive_timers(self, fd); return TRUE; } void socket_options_inet_set_interface_name(SocketOptionsInet *self, const gchar *interface_name) { g_free(self->interface_name); self->interface_name = g_strdup(interface_name); } void socket_options_inet_free(gpointer s) { SocketOptionsInet *self = (SocketOptionsInet *) s; g_free(self->interface_name); g_free(self); } SocketOptionsInet * socket_options_inet_new_instance(void) { SocketOptionsInet *self = g_new0(SocketOptionsInet, 1); socket_options_init_instance(&self->super); self->super.setup_socket = socket_options_inet_setup_socket; self->super.setup_peer_socket = socket_options_inet_setup_peer_socket; self->super.so_keepalive = TRUE; self->tcp_keepalive_time = 60; self->tcp_keepalive_intvl = 10; self->tcp_keepalive_probes = 6; self->super.free = socket_options_inet_free; return self; } SocketOptions * socket_options_inet_new(void) { return &socket_options_inet_new_instance()->super; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options-inet.h000066400000000000000000000034741450431004300247210ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SOCKET_OPTIONS_INET_H_INCLUDED #define SOCKET_OPTIONS_INET_H_INCLUDED #include "socket-options.h" typedef struct _SocketOptionsInet { SocketOptions super; /* user settings */ gint ip_ttl; gint ip_tos; gboolean ip_freebind; gint tcp_keepalive_time; gint tcp_keepalive_intvl; gint tcp_keepalive_probes; gchar *interface_name; } SocketOptionsInet; void socket_options_inet_set_interface_name(SocketOptionsInet *self, const gchar *interface); gboolean socket_options_inet_set_tcp_keepalive_time(SocketOptionsInet *self, gint tcp_keepalive_time); gboolean socket_options_inet_set_tcp_keepalive_intvl(SocketOptionsInet *self, gint tcp_keepalive_intvl); gboolean socket_options_inet_set_tcp_keepalive_probes(SocketOptionsInet *self, gint tcp_keepalive_probes); SocketOptionsInet *socket_options_inet_new_instance(void); SocketOptions *socket_options_inet_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options-unix.c000066400000000000000000000030641450431004300247330ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "socket-options-unix.h" #include "compat-unix-creds.h" static gboolean socket_options_unix_setup_socket(SocketOptions *s, gint fd, GSockAddr *addr, AFSocketDirection dir) { SocketOptionsUnix *self = (SocketOptionsUnix *) s; if (!socket_options_setup_socket_method(s, fd, addr, dir)) return FALSE; setsockopt_so_passcred(fd, self->so_passcred); return TRUE; } SocketOptions * socket_options_unix_new(void) { SocketOptionsUnix *self = g_new0(SocketOptionsUnix, 1); socket_options_init_instance(&self->super); self->super.setup_socket = socket_options_unix_setup_socket; self->so_passcred = TRUE; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options-unix.h000066400000000000000000000025461450431004300247440ustar00rootroot00000000000000/* * Copyright (c) 2021 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SOCKET_OPTIONS_UNIX_H_INCLUDED #define SOCKET_OPTIONS_UNIX_H_INCLUDED #include "socket-options.h" typedef struct _SocketOptionsUnix { SocketOptions super; gint so_passcred; } SocketOptionsUnix; static inline void socket_options_unix_set_so_passcred(SocketOptions *s, gint so_passcred) { SocketOptionsUnix *self = (SocketOptionsUnix *) s; self->so_passcred = so_passcred; } SocketOptions *socket_options_unix_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options.c000066400000000000000000000111751450431004300237540ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "socket-options.h" #include "messages.h" #include #include static gboolean _setup_receive_buffer(gint fd, gint so_rcvbuf) { gint so_rcvbuf_set = 0; socklen_t sz = sizeof(so_rcvbuf_set); gint rc; rc = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf, sizeof(so_rcvbuf)); if (rc < 0 || getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &so_rcvbuf_set, &sz) < 0 || sz != sizeof(so_rcvbuf_set) || so_rcvbuf_set < so_rcvbuf) { msg_warning("The kernel refused to set the receive buffer (SO_RCVBUF) to the requested size, you probably need to adjust buffer related kernel parameters", evt_tag_int("so_rcvbuf", so_rcvbuf), evt_tag_int("so_rcvbuf_set", so_rcvbuf_set)); } return TRUE; } static gboolean _setup_send_buffer(gint fd, gint so_sndbuf) { gint so_sndbuf_set = 0; socklen_t sz = sizeof(so_sndbuf_set); gint rc; rc = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, sizeof(so_sndbuf)); if (rc < 0 || getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf_set, &sz) < 0 || sz != sizeof(so_sndbuf_set) || so_sndbuf_set < so_sndbuf) { msg_warning("The kernel refused to set the send buffer (SO_SNDBUF) to the requested size, you probably need to adjust buffer related kernel parameters", evt_tag_int("so_sndbuf", so_sndbuf), evt_tag_int("so_sndbuf_set", so_sndbuf_set)); } return TRUE; } static gboolean _setup_broadcast(gint fd) { gint on = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); return TRUE; } static gboolean _setup_keepalive(gint fd) { gint on = 1; setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); return TRUE; } static gboolean _setup_reuseport(gint fd) { #if defined(SO_REUSEPORT_LB) gint on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on)) < 0) { msg_error("The kernel refused our SO_REUSEPORT_LB setting, which should be supported by FreeBSD 12.0+", evt_tag_error("error")); return FALSE; } return TRUE; #elif defined(SO_REUSEPORT) gint on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) { msg_error("The kernel refused our SO_REUSEPORT setting, which should be supported by Linux 3.9+", evt_tag_error("error")); return FALSE; } return TRUE; #else msg_error("You enabled so-reuseport(), but your platform does not support SO_REUSEPORT socket option, which should be supported on Linux 3.9+"); return FALSE; #endif } gboolean socket_options_setup_socket_method(SocketOptions *self, gint fd, GSockAddr *bind_addr, AFSocketDirection dir) { if (dir & AFSOCKET_DIR_RECV) { if (self->so_rcvbuf && !_setup_receive_buffer(fd, self->so_rcvbuf)) return FALSE; if (self->so_reuseport && !_setup_reuseport(fd)) return FALSE; } if (dir & AFSOCKET_DIR_SEND) { if (self->so_sndbuf && !_setup_send_buffer(fd, self->so_sndbuf)) return FALSE; if (self->so_broadcast && !_setup_broadcast(fd)) return FALSE; } if (self->so_keepalive && !_setup_keepalive(fd)) return FALSE; return TRUE; } gboolean socket_options_setup_peer_socket_method(SocketOptions *self, gint fd, GSockAddr *peer_addr) { if (self->so_keepalive && !_setup_keepalive(fd)) return FALSE; return TRUE; } void socket_options_init_instance(SocketOptions *self) { self->setup_socket = socket_options_setup_socket_method; self->setup_peer_socket = socket_options_setup_peer_socket_method; self->free = g_free; } SocketOptions * socket_options_new(void) { SocketOptions *self = g_new0(SocketOptions, 1); socket_options_init_instance(self); return self; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/socket-options.h000066400000000000000000000043761450431004300237660ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SOCKET_OPTIONS_H_INCLUDED #define SOCKET_OPTIONS_H_INCLUDED #include "gsockaddr.h" typedef enum { AFSOCKET_DIR_RECV = 0x01, AFSOCKET_DIR_SEND = 0x02, } AFSocketDirection; typedef struct _SocketOptions SocketOptions; struct _SocketOptions { /* socket options */ gint so_sndbuf; gint so_rcvbuf; gint so_broadcast; gint so_keepalive; gboolean so_reuseport; gboolean (*setup_socket)(SocketOptions *s, gint sock, GSockAddr *bind_addr, AFSocketDirection dir); gboolean (*setup_peer_socket)(SocketOptions *s, gint sock, GSockAddr *peer_addr); void (*free)(gpointer s); }; gboolean socket_options_setup_socket_method(SocketOptions *self, gint fd, GSockAddr *bind_addr, AFSocketDirection dir); gboolean socket_options_setup_peer_socket_method(SocketOptions *self, gint fd, GSockAddr *bind_addr); void socket_options_init_instance(SocketOptions *self); SocketOptions *socket_options_new(void); static inline gboolean socket_options_setup_socket(SocketOptions *s, gint sock, GSockAddr *bind_addr, AFSocketDirection dir) { return s->setup_socket(s, sock, bind_addr, dir); } static inline gboolean socket_options_setup_peer_socket(SocketOptions *s, gint sock, GSockAddr *peer_addr) { return s->setup_peer_socket(s, sock, peer_addr); } static inline void socket_options_free(SocketOptions *s) { s->free(s); } #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/systemd-syslog-source.c000066400000000000000000000141501450431004300252730ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 2013-2014 Tibor Benke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "systemd-syslog-source.h" #include "afunix-source.h" #include "afsocket-systemd-override.h" #include "service-management.h" #include "fdhelpers.h" #include #include #if SYSLOG_NG_ENABLE_SYSTEMD #include static gboolean systemd_syslog_sd_acquire_socket(AFSocketSourceDriver *s, gint *acquired_fd) { *acquired_fd = -1; gint number_of_fds = sd_listen_fds(0); if (number_of_fds > 1) { msg_error("Systemd socket activation failed: got more than one fd", evt_tag_int("number", number_of_fds)); return TRUE; } else if (number_of_fds < 1) { msg_error("Failed to acquire /run/systemd/journal/syslog socket, disabling systemd-syslog source"); return TRUE; } else { gint fd = SD_LISTEN_FDS_START; msg_debug("Systemd socket activation", evt_tag_int("file-descriptor", fd)); if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, NULL, 0)) { *acquired_fd = fd; } else { msg_error("The systemd supplied UNIX domain socket is of a" " different type, check the configured driver and" " the matching systemd unit file", evt_tag_int("systemd-sock-fd", fd), evt_tag_str("expecting", "unix-dgram()")); *acquired_fd = -1; return TRUE; } } if (*acquired_fd != -1) { g_fd_set_nonblock(*acquired_fd, TRUE); msg_verbose("Acquired systemd syslog socket", evt_tag_int("systemd-syslog-sock-fd", *acquired_fd)); return TRUE; } return TRUE; } #else static gboolean systemd_syslog_sd_acquire_socket(AFSocketSourceDriver *s, gint *acquired_fd) { return TRUE; } #endif static gboolean systemd_syslog_sd_init_method(LogPipe *s) { SystemDSyslogSourceDriver *self = (SystemDSyslogSourceDriver *) s; if (service_management_get_type() != SMT_SYSTEMD) { msg_error("Error initializing systemd-syslog() source", evt_tag_str("systemd_status", "not-running")); return FALSE; } if (self->from_unix_source) { msg_warning("systemd-syslog() source ignores configuration options. " "Please, do not set anything on it"); socket_options_free(self->super.socket_options); self->super.socket_options = socket_options_new(); socket_options_init_instance(self->super.socket_options); } return afsocket_sd_init_method((LogPipe *) &self->super); } SystemDSyslogSourceDriver * systemd_syslog_sd_new(GlobalConfig *cfg, gboolean fallback) { SystemDSyslogSourceDriver *self; TransportMapper *transport_mapper; self = g_new0(SystemDSyslogSourceDriver, 1); transport_mapper = transport_mapper_unix_dgram_new(); afsocket_sd_init_instance(&self->super, socket_options_new(), transport_mapper, cfg); self->super.super.super.super.init = systemd_syslog_sd_init_method; self->super.acquire_socket = systemd_syslog_sd_acquire_socket; atomic_gssize_set(&self->super.max_connections, 256); if (!self->super.bind_addr) self->super.bind_addr = g_sockaddr_unix_new(NULL); return self; } static gboolean should_use_systemd_syslog_instead_of_unix_socket(gchar *filename) { return (service_management_get_type() == SMT_SYSTEMD && (strncmp("/dev/log", filename, 9) == 0 || strncmp("/run/systemd/journal/syslog", filename, 28) == 0))? TRUE : FALSE; } typedef enum _SocketType { ST_DGRAM, ST_STREAM } SocketType; AFSocketSourceDriver * create_afunix_sd(gchar *filename, GlobalConfig *cfg, SocketType socket_type) { AFUnixSourceDriver *ud = NULL; if (socket_type == ST_DGRAM) { ud = afunix_sd_new_dgram(filename, cfg); } else if (socket_type == ST_STREAM) { ud = afunix_sd_new_stream(filename, cfg); } afunix_grammar_set_source_driver(ud); return &ud->super; } static AFSocketSourceDriver * create_and_set_unix_socket_or_systemd_syslog_source(gchar *filename, GlobalConfig *cfg, SocketType socket_type) { SystemDSyslogSourceDriver *sd; if (should_use_systemd_syslog_instead_of_unix_socket(filename)) { msg_warning("Using /dev/log Unix socket with systemd is not" " possible. Changing to systemd-syslog source, which supports" " socket activation."); sd = systemd_syslog_sd_new(configuration, TRUE); systemd_syslog_grammar_set_source_driver(sd); return &sd->super; } else return create_afunix_sd(filename, cfg, socket_type); } AFSocketSourceDriver * create_and_set_unix_dgram_or_systemd_syslog_source(gchar *filename, GlobalConfig *cfg) { return create_and_set_unix_socket_or_systemd_syslog_source(filename, cfg, ST_DGRAM); } AFSocketSourceDriver * create_and_set_unix_stream_or_systemd_syslog_source(gchar *filename, GlobalConfig *cfg) { return create_and_set_unix_socket_or_systemd_syslog_source(filename, cfg, ST_STREAM); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/systemd-syslog-source.h000066400000000000000000000030751450431004300253040ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * Copyright (c) 2013-2014 Tibor Benke * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef SYSTEMD_SYSLOG_SOURCE_H_INCLUDED #define SYSTEMD_SYSLOG_SOURCE_H_INCLUDED 1 #include "afsocket-source.h" #include "transport-mapper-unix.h" typedef struct _SystemDSyslogSourceDriver { AFSocketSourceDriver super; gboolean from_unix_source; } SystemDSyslogSourceDriver; SystemDSyslogSourceDriver *systemd_syslog_sd_new(GlobalConfig *cfg, gboolean fallback); AFSocketSourceDriver *create_and_set_unix_dgram_or_systemd_syslog_source(gchar *filename, GlobalConfig *cfg); AFSocketSourceDriver *create_and_set_unix_stream_or_systemd_syslog_source(gchar *filename, GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/000077500000000000000000000000001450431004300217645ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/CMakeLists.txt000066400000000000000000000006421450431004300245260ustar00rootroot00000000000000add_unit_test(CRITERION TARGET test-transport-mapper DEPENDS afsocket SOURCES test-transport-mapper.c transport-mapper-lib.c) add_unit_test(CRITERION TARGET test-transport-mapper-inet DEPENDS afsocket SOURCES test-transport-mapper-inet.c transport-mapper-lib.c) add_unit_test(CRITERION TARGET test-transport-mapper-unix DEPENDS afsocket SOURCES test-transport-mapper-unix.c transport-mapper-lib.c) syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/Makefile.am000066400000000000000000000035351450431004300240260ustar00rootroot00000000000000TEST_TRANSPORT_MAPPER_CFLAGS = $(TEST_CFLAGS) EXTRA_DIST += modules/afsocket/tests/CMakeLists.txt TRANSPORT_MAPPER_LIB = \ modules/afsocket/tests/transport-mapper-lib.c \ modules/afsocket/tests/transport-mapper-lib.h modules_afsocket_tests_TESTS = \ modules/afsocket/tests/test-transport-mapper \ modules/afsocket/tests/test-transport-mapper-inet \ modules/afsocket/tests/test-transport-mapper-unix check_PROGRAMS += \ $(modules_afsocket_tests_TESTS) modules_afsocket_tests_test_transport_mapper_CFLAGS = \ $(TEST_TRANSPORT_MAPPER_CFLAGS) \ -I$(top_srcdir)/modules/afsocket modules_afsocket_tests_test_transport_mapper_LDADD = \ $(TEST_LDADD) modules_afsocket_tests_test_transport_mapper_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsocket/libafsocket.la modules_afsocket_tests_test_transport_mapper_SOURCES = \ modules/afsocket/tests/test-transport-mapper.c \ $(TRANSPORT_MAPPER_LIB) modules_afsocket_tests_test_transport_mapper_inet_CFLAGS = \ $(TEST_TRANSPORT_MAPPER_CFLAGS) \ -I$(top_srcdir)/modules/afsocket modules_afsocket_tests_test_transport_mapper_inet_LDADD = \ $(TEST_LDADD) modules_afsocket_tests_test_transport_mapper_inet_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsocket/libafsocket.la modules_afsocket_tests_test_transport_mapper_inet_SOURCES = \ modules/afsocket/tests/test-transport-mapper-inet.c \ $(TRANSPORT_MAPPER_LIB) modules_afsocket_tests_test_transport_mapper_unix_CFLAGS = \ $(TEST_TRANSPORT_MAPPER_CFLAGS) \ -I$(top_srcdir)/modules/afsocket modules_afsocket_tests_test_transport_mapper_unix_LDADD = \ $(TEST_LDADD) modules_afsocket_tests_test_transport_mapper_unix_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afsocket/libafsocket.la modules_afsocket_tests_test_transport_mapper_unix_SOURCES = \ modules/afsocket/tests/test-transport-mapper-unix.c \ $(TRANSPORT_MAPPER_LIB) syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/test-transport-mapper-inet.c000066400000000000000000000314501450431004300273630ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afinet.h" #include "afsocket.h" #include "stats/stats-registry.h" #include "apphook.h" #include "transport-mapper-inet.h" #include "socket-options-inet.h" #include "transport-mapper-lib.h" #include guint SCS_TCP; guint SCS_TCP6; guint SCS_UDP; guint SCS_UDP6; guint SCS_NETWORK; guint SCS_SYSLOG; static inline void assert_transport_mapper_inet_server_port(TransportMapper *s, gint server_port) { cr_assert_eq(transport_mapper_inet_get_server_port(s), server_port, "TransportMapper server_port mismatch"); } static void assert_transport_mapper_tcp_socket(TransportMapper *self) { assert_transport_mapper_address_family(self, AF_INET); assert_transport_mapper_sock_type(self, SOCK_STREAM); assert_transport_mapper_sock_proto(self, IPPROTO_TCP); } static void assert_transport_mapper_tcp6_socket(TransportMapper *self) { assert_transport_mapper_address_family(self, AF_INET6); assert_transport_mapper_sock_type(self, SOCK_STREAM); assert_transport_mapper_sock_proto(self, IPPROTO_TCP); } static void assert_transport_mapper_udp_socket(TransportMapper *self) { assert_transport_mapper_address_family(self, AF_INET); assert_transport_mapper_sock_type(self, SOCK_DGRAM); assert_transport_mapper_sock_proto(self, IPPROTO_UDP); } static void assert_transport_mapper_udp6_socket(TransportMapper *self) { assert_transport_mapper_address_family(self, AF_INET6); assert_transport_mapper_sock_type(self, SOCK_DGRAM); assert_transport_mapper_sock_proto(self, IPPROTO_UDP); } static gboolean create_socket_with_address(GSockAddr *addr, gint *sock) { SocketOptionsInet *sock_options; gboolean result; sock_options = socket_options_inet_new_instance(); result = transport_mapper_open_socket(transport_mapper, &sock_options->super, addr, addr, AFSOCKET_DIR_RECV, sock); socket_options_free(&sock_options->super); return result; } static gboolean create_socket(gint *sock) { GSockAddr *addr = g_sockaddr_inet_new("127.0.0.1", 0); gboolean success; success = create_socket_with_address(addr, sock); g_sockaddr_unref(addr); return success; } static void assert_create_socket_fails_with_address(GSockAddr *addr) { gint sock; cr_assert_not(create_socket_with_address(addr, &sock), "transport_mapper_open_socket() succeeded unexpectedly"); cr_assert_eq(sock, -1, "failed create_socket returned a non-extremal value on failure"); } static void assert_create_socket_fails(void) { gint sock; cr_assert_not(create_socket(&sock), "transport_mapper_open_socket() succeeded unexpectedly"); cr_assert_eq(sock, -1, "failed create_socket returned a non-extremal value on failure"); } static void assert_create_socket_succeeds(void) { gint sock; cr_assert(create_socket(&sock), "transport_mapper_open_socket() failed unexpectedly"); close(sock); } static TLSContext * create_dummy_tls_context(void) { TLSContext *tls_context; tls_context = tls_context_new(TM_SERVER, "dummy-location"); return tls_context; } /****************************************************************************** * Tests start here ******************************************************************************/ Test(transport_mapper_inet, test_tcp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_tcp_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tcp"); assert_transport_mapper_logproto(transport_mapper, "text"); assert_transport_mapper_stats_source(transport_mapper, SCS_TCP); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_tcp6_apply_transport_sets_defaults) { transport_mapper = transport_mapper_tcp6_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_tcp6_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tcp"); assert_transport_mapper_logproto(transport_mapper, "text"); assert_transport_mapper_stats_source(transport_mapper, SCS_TCP6); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_udp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_udp_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_udp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "udp"); assert_transport_mapper_logproto(transport_mapper, "dgram"); assert_transport_mapper_stats_source(transport_mapper, SCS_UDP); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_udp_apply_fails_when_tls_context_is_set) { transport_mapper = transport_mapper_udp_new(); transport_mapper_inet_set_tls_context((TransportMapperInet *) transport_mapper, create_dummy_tls_context()); assert_transport_mapper_apply_fails(transport_mapper, "udp"); } Test(transport_mapper_inet, test_udp6_apply_transport_sets_defaults) { transport_mapper = transport_mapper_udp6_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_udp6_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "udp"); assert_transport_mapper_logproto(transport_mapper, "dgram"); assert_transport_mapper_stats_source(transport_mapper, SCS_UDP6); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_network_transport_udp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_network_new(); assert_transport_mapper_apply(transport_mapper, "udp"); assert_transport_mapper_udp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "udp"); assert_transport_mapper_logproto(transport_mapper, "dgram"); assert_transport_mapper_stats_source(transport_mapper, SCS_NETWORK); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_network_transport_udp_apply_fails_when_tls_context_is_set) { transport_mapper = transport_mapper_network_new(); transport_mapper_inet_set_tls_context((TransportMapperInet *) transport_mapper, create_dummy_tls_context()); assert_transport_mapper_apply_fails(transport_mapper, "udp"); } Test(transport_mapper_inet, test_network_transport_tcp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_network_new(); assert_transport_mapper_apply(transport_mapper, "tcp"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tcp"); assert_transport_mapper_logproto(transport_mapper, "text"); assert_transport_mapper_stats_source(transport_mapper, SCS_NETWORK); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_network_transport_tls_apply_fails_without_tls_context) { transport_mapper = transport_mapper_network_new(); assert_transport_mapper_apply_fails(transport_mapper, "tls"); } Test(transport_mapper_inet, test_network_transport_tls_apply_transport_sets_defaults) { transport_mapper = transport_mapper_network_new(); transport_mapper_inet_set_tls_context((TransportMapperInet *) transport_mapper, create_dummy_tls_context()); assert_transport_mapper_apply(transport_mapper, "tls"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tls"); assert_transport_mapper_logproto(transport_mapper, "text"); assert_transport_mapper_stats_source(transport_mapper, SCS_NETWORK); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_network_transport_foo_apply_transport_sets_defaults) { transport_mapper = transport_mapper_network_new(); assert_transport_mapper_apply(transport_mapper, "foo"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "foo"); assert_transport_mapper_logproto(transport_mapper, "foo"); assert_transport_mapper_stats_source(transport_mapper, SCS_NETWORK); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_syslog_transport_udp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_syslog_new(); assert_transport_mapper_apply(transport_mapper, "udp"); assert_transport_mapper_udp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "udp"); assert_transport_mapper_logproto(transport_mapper, "dgram"); assert_transport_mapper_stats_source(transport_mapper, SCS_SYSLOG); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_syslog_transport_udp_apply_fails_when_tls_context_is_set) { transport_mapper = transport_mapper_syslog_new(); transport_mapper_inet_set_tls_context((TransportMapperInet *) transport_mapper, create_dummy_tls_context()); assert_transport_mapper_apply_fails(transport_mapper, "udp"); } Test(transport_mapper_inet, test_syslog_transport_tcp_apply_transport_sets_defaults) { transport_mapper = transport_mapper_syslog_new(); assert_transport_mapper_apply(transport_mapper, "tcp"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tcp"); assert_transport_mapper_logproto(transport_mapper, "framed"); assert_transport_mapper_stats_source(transport_mapper, SCS_SYSLOG); assert_transport_mapper_inet_server_port(transport_mapper, 601); } Test(transport_mapper_inet, test_syslog_transport_tls_apply_fails_without_tls_context) { transport_mapper = transport_mapper_syslog_new(); assert_transport_mapper_apply_fails(transport_mapper, "tls"); } Test(transport_mapper_inet, test_syslog_transport_tls_apply_transport_sets_defaults) { transport_mapper = transport_mapper_syslog_new(); transport_mapper_inet_set_tls_context((TransportMapperInet *) transport_mapper, create_dummy_tls_context()); assert_transport_mapper_apply(transport_mapper, "tls"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "tls"); assert_transport_mapper_logproto(transport_mapper, "framed"); assert_transport_mapper_stats_source(transport_mapper, SCS_SYSLOG); assert_transport_mapper_inet_server_port(transport_mapper, 6514); } Test(transport_mapper_inet, test_syslog_transport_foo_apply_transport_sets_defaults) { transport_mapper = transport_mapper_syslog_new(); assert_transport_mapper_apply(transport_mapper, "foo"); assert_transport_mapper_tcp_socket(transport_mapper); assert_transport_mapper_transport(transport_mapper, "foo"); assert_transport_mapper_logproto(transport_mapper, "foo"); assert_transport_mapper_stats_source(transport_mapper, SCS_SYSLOG); assert_transport_mapper_inet_server_port(transport_mapper, 514); } Test(transport_mapper_inet, test_open_socket_opens_a_socket_and_applies_socket_options) { transport_mapper = transport_mapper_tcp_new(); assert_create_socket_succeeds(); } Test(transport_mapper_inet, test_open_socket_fails_properly_on_socket_failure) { transport_mapper = transport_mapper_tcp_new(); transport_mapper_set_address_family(transport_mapper, 0xdeadbeef); assert_create_socket_fails(); } Test(transport_mapper_inet, test_open_socket_fails_properly_on_bind_failure) { transport_mapper = transport_mapper_tcp_new(); GSockAddr *addr = g_sockaddr_unix_new("/foo/bar/no/such/dir"); transport_mapper_set_address_family(transport_mapper, AF_UNIX); assert_create_socket_fails_with_address(addr); g_sockaddr_unref(addr); } static void setup(void) { app_startup(); SCS_TCP = stats_register_type("tcp"); SCS_TCP6 = stats_register_type("tcp6"); SCS_UDP = stats_register_type("udp"); SCS_UDP6 = stats_register_type("udp6"); SCS_NETWORK = stats_register_type("network"); SCS_SYSLOG = stats_register_type("syslog"); } static void teardown(void) { transport_mapper_free(transport_mapper); app_shutdown(); } TestSuite(transport_mapper_inet, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/test-transport-mapper-unix.c000066400000000000000000000051541450431004300274110ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-mapper-unix.h" #include "apphook.h" #include "stats/stats-registry.h" #include "transport-mapper-lib.h" guint SCS_UNIX_STREAM; guint SCS_UNIX_DGRAM; Test(transport_mapper_unix, test_transport_mapper_unix_stream_apply_transport_sets_defaults) { transport_mapper = transport_mapper_unix_stream_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_transport(transport_mapper, "unix-stream"); assert_transport_mapper_address_family(transport_mapper, AF_UNIX); assert_transport_mapper_sock_type(transport_mapper, SOCK_STREAM); assert_transport_mapper_sock_proto(transport_mapper, 0); assert_transport_mapper_logproto(transport_mapper, "text"); assert_transport_mapper_stats_source(transport_mapper, SCS_UNIX_STREAM); } Test(transport_mapper_unix, test_transport_mapper_unix_dgram_apply_transport_sets_defaults) { transport_mapper = transport_mapper_unix_dgram_new(); assert_transport_mapper_apply(transport_mapper, NULL); assert_transport_mapper_transport(transport_mapper, "unix-dgram"); assert_transport_mapper_address_family(transport_mapper, AF_UNIX); assert_transport_mapper_sock_type(transport_mapper, SOCK_DGRAM); assert_transport_mapper_sock_proto(transport_mapper, 0); assert_transport_mapper_logproto(transport_mapper, "dgram"); assert_transport_mapper_stats_source(transport_mapper, SCS_UNIX_DGRAM); } static void setup(void) { app_startup(); SCS_UNIX_STREAM = stats_register_type("unix-stream"); SCS_UNIX_DGRAM = stats_register_type("unix-dgram"); } static void teardown(void) { transport_mapper_free(transport_mapper); app_shutdown(); } TestSuite(transport_mapper_unix, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/test-transport-mapper.c000066400000000000000000000042001450431004300264170ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsocket.h" #include "transport-mapper.h" #include "transport-mapper-lib.h" #include "apphook.h" TransportMapper * transport_mapper_dummy_new(void) { TransportMapper *self = g_new0(TransportMapper, 1); transport_mapper_init_instance(self, "dummy"); return self; } Test(transport_mapper, test_set_transport_stores_value) { transport_mapper_set_transport(transport_mapper, "foobar"); assert_transport_mapper_transport(transport_mapper, "foobar"); } Test(transport_mapper, test_set_address_value_stores_value) { transport_mapper_set_address_family(transport_mapper, AF_UNIX); assert_transport_mapper_address_family(transport_mapper, AF_UNIX); transport_mapper_set_address_family(transport_mapper, AF_INET); assert_transport_mapper_address_family(transport_mapper, AF_INET); } Test(transport_mapper, test_apply_transport_returns_success) { assert_transport_mapper_apply(transport_mapper, "transport_mapper_apply_transport() failed"); } static void setup(void) { transport_mapper = transport_mapper_dummy_new(); app_startup(); } static void teardown(void) { transport_mapper_free(transport_mapper); app_shutdown(); } TestSuite(transport_mapper, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/transport-mapper-lib.c000066400000000000000000000017671450431004300262250ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-mapper-lib.h" TransportMapper *transport_mapper; syslog-ng-syslog-ng-4.4.0/modules/afsocket/tests/transport-mapper-lib.h000066400000000000000000000057041450431004300262250ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_OPTIONS_LIB_H_INCLUDED #define AFSOCKET_OPTIONS_LIB_H_INCLUDED #include #include "transport-mapper.h" extern TransportMapper *transport_mapper; static inline void assert_transport_mapper_apply(TransportMapper *self, const gchar *transport) { if (transport) transport_mapper_set_transport(self, transport); cr_assert(transport_mapper_apply_transport(self, configuration), "afsocket_apply_transport() failed"); } static inline void assert_transport_mapper_apply_fails(TransportMapper *self, const gchar *transport) { if (transport) transport_mapper_set_transport(self, transport); cr_assert_not(transport_mapper_apply_transport(self, configuration), "afsocket_apply_transport() succeeded while we expected failure"); } static inline void assert_transport_mapper_transport(TransportMapper *options, const gchar *expected_transport) { cr_assert_str_eq(options->transport, expected_transport, "TransportMapper contains a mismatching transport name"); } static inline void assert_transport_mapper_logproto(TransportMapper *options, const gchar *expected_logproto) { cr_assert_str_eq(options->logproto, expected_logproto, "TransportMapper contains a mismatching log_proto name"); } static inline void assert_transport_mapper_stats_source(TransportMapper *options, gint stats_source) { cr_assert_eq(options->stats_source, stats_source, "TransportMapper contains a mismatching stats_source"); } static inline void assert_transport_mapper_address_family(TransportMapper *options, gint address_family) { cr_assert_eq(options->address_family, address_family, "TransportMapper address family mismatch"); } static inline void assert_transport_mapper_sock_type(TransportMapper *options, gint sock_type) { cr_assert_eq(options->sock_type, sock_type, "TransportMapper sock_type mismatch"); } static inline void assert_transport_mapper_sock_proto(TransportMapper *options, gint sock_proto) { cr_assert_eq(options->sock_proto, sock_proto, "TransportMapper sock_proto mismatch"); } #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper-inet.c000066400000000000000000000353661450431004300252560ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-mapper-inet.h" #include "afinet.h" #include "cfg.h" #include "messages.h" #include "stats/stats-registry.h" #include "transport/transport-tls.h" #include "transport/multitransport.h" #include "transport/transport-factory-tls.h" #include "transport/transport-factory-socket.h" #include "transport/transport-udp-socket.h" #include "secret-storage/secret-storage.h" #include #include #include #include #include #define UDP_PORT 514 #define TCP_PORT 514 #define NETWORK_PORT 514 #define SYSLOG_TRANSPORT_UDP_PORT 514 #define SYSLOG_TRANSPORT_TCP_PORT 601 #define SYSLOG_TRANSPORT_TLS_PORT 6514 static inline gboolean _is_tls_required(TransportMapperInet *self) { return self->require_tls || (self->tls_context && self->require_tls_when_has_tls_context); } static inline gboolean _is_tls_allowed(TransportMapperInet *self) { return self->require_tls || self->allow_tls || self->require_tls_when_has_tls_context; } static gboolean transport_mapper_inet_validate_tls_options(TransportMapperInet *self) { if (!self->tls_context && _is_tls_required(self)) { msg_error("transport(tls) was specified, but tls() options missing"); return FALSE; } else if (self->tls_context && !_is_tls_allowed(self)) { msg_error("tls() options specified for a transport that doesn't allow TLS encryption", evt_tag_str("transport", self->super.transport)); return FALSE; } return TRUE; } static gboolean transport_mapper_inet_apply_transport_method(TransportMapper *s, GlobalConfig *cfg) { TransportMapperInet *self = (TransportMapperInet *) s; if (!transport_mapper_apply_transport_method(s, cfg)) return FALSE; return transport_mapper_inet_validate_tls_options(self); } static LogTransport * _construct_multitransport_with_tls_factory(TransportMapperInet *self, gint fd) { TransportFactory *default_factory = transport_factory_tls_new(self->tls_context, self->tls_verifier, self->flags); return multitransport_new(default_factory, fd); } static LogTransport * _construct_tls_transport(TransportMapperInet *self, gint fd) { if (self->super.create_multitransport) return _construct_multitransport_with_tls_factory(self, fd); TLSSession *tls_session = tls_context_setup_session(self->tls_context); if (!tls_session) return NULL; tls_session_configure_allow_compress(tls_session, self->flags & TMI_ALLOW_COMPRESS); tls_session_set_verifier(tls_session, self->tls_verifier); return log_transport_tls_new(tls_session, fd); } static LogTransport * _construct_multitransport_with_plain_tcp_factory(TransportMapperInet *self, gint fd) { TransportFactory *default_factory = transport_factory_socket_new(self->super.sock_type); return multitransport_new(default_factory, fd); } static LogTransport * _construct_multitransport_with_plain_and_tls_factories(TransportMapperInet *self, gint fd) { LogTransport *transport = _construct_multitransport_with_plain_tcp_factory(self, fd); TransportFactory *tls_factory = transport_factory_tls_new(self->tls_context, self->tls_verifier, self->flags); multitransport_add_factory((MultiTransport *)transport, tls_factory); return transport; } static LogTransport * _construct_plain_tcp_transport(TransportMapperInet *self, gint fd) { if (self->super.create_multitransport) return _construct_multitransport_with_plain_tcp_factory(self, fd); if (self->super.sock_type == SOCK_DGRAM) return log_transport_udp_socket_new(fd); else return log_transport_stream_socket_new(fd); } static LogTransport * transport_mapper_inet_construct_log_transport(TransportMapper *s, gint fd) { TransportMapperInet *self = (TransportMapperInet *) s; if (self->tls_context && _is_tls_required(self)) { return _construct_tls_transport(self, fd); } if (self->tls_context) { return _construct_multitransport_with_plain_and_tls_factories(self, fd); } return _construct_plain_tcp_transport(self, fd); } static gboolean transport_mapper_inet_init(TransportMapper *s) { TransportMapperInet *self = (TransportMapperInet *) s; if (self->tls_context && (tls_context_setup_context(self->tls_context) != TLS_CONTEXT_SETUP_OK)) return FALSE; return TRUE; } typedef struct _call_finalize_init_args { TransportMapperInet *transport_mapper_inet; TransportMapperAsyncInitCB func; gpointer func_args; } call_finalize_init_args; static void _call_finalize_init(Secret *secret, gpointer user_data) { call_finalize_init_args *args = user_data; TransportMapperInet *self = args->transport_mapper_inet; if (!self) return; TLSContextSetupResult r = tls_context_setup_context(self->tls_context); const gchar *key = tls_context_get_key_file(self->tls_context); switch (r) { case TLS_CONTEXT_SETUP_ERROR: { msg_error("Error setting up TLS context", evt_tag_str("keyfile", key)); secret_storage_update_status(key, SECRET_STORAGE_STATUS_FAILED); return; } case TLS_CONTEXT_SETUP_BAD_PASSWORD: { msg_error("Invalid password, error setting up TLS context", evt_tag_str("keyfile", key)); if (!secret_storage_subscribe_for_key(key, _call_finalize_init, args)) msg_error("Failed to subscribe for key", evt_tag_str("keyfile", key)); else msg_debug("Re-subscribe for key", evt_tag_str("keyfile", key)); secret_storage_update_status(key, SECRET_STORAGE_STATUS_INVALID_PASSWORD); return; } default: secret_storage_update_status(key, SECRET_STORAGE_SUCCESS); if (!args->func(args->func_args)) { msg_error("Error finalize initialization", evt_tag_str("keyfile", key)); } } } static gboolean transport_mapper_inet_async_init(TransportMapper *s, TransportMapperAsyncInitCB func, gpointer func_args) { TransportMapperInet *self = (TransportMapperInet *)s; if (!self->tls_context) return func(func_args); TLSContextSetupResult tls_ctx_setup_res = tls_context_setup_context(self->tls_context); const gchar *key = tls_context_get_key_file(self->tls_context); if (tls_ctx_setup_res == TLS_CONTEXT_SETUP_OK) { if (key && secret_storage_contains_key(key)) secret_storage_update_status(key, SECRET_STORAGE_SUCCESS); return func(func_args); } if (tls_ctx_setup_res == TLS_CONTEXT_SETUP_BAD_PASSWORD) { msg_error("Error setting up TLS context", evt_tag_str("keyfile", key)); call_finalize_init_args *args = g_new0(call_finalize_init_args, 1); args->transport_mapper_inet = self; args->func = func; args->func_args = func_args; self->secret_store_cb_data = args; gboolean subscribe_res = secret_storage_subscribe_for_key(key, _call_finalize_init, args); if (subscribe_res) msg_info("Waiting for password", evt_tag_str("keyfile", key)); else msg_error("Failed to subscribe for key", evt_tag_str("keyfile", key)); return subscribe_res; } return FALSE; } void transport_mapper_inet_free_method(TransportMapper *s) { TransportMapperInet *self = (TransportMapperInet *) s; if (self->secret_store_cb_data) { const gchar *key = tls_context_get_key_file(self->tls_context); secret_storage_unsubscribe(key, _call_finalize_init, self->secret_store_cb_data); g_free(self->secret_store_cb_data); } if (self->tls_verifier) tls_verifier_unref(self->tls_verifier); if (self->tls_context) tls_context_unref(self->tls_context); transport_mapper_free_method(s); } void transport_mapper_inet_init_instance(TransportMapperInet *self, const gchar *transport) { transport_mapper_init_instance(&self->super, transport); self->super.apply_transport = transport_mapper_inet_apply_transport_method; self->super.construct_log_transport = transport_mapper_inet_construct_log_transport; self->super.init = transport_mapper_inet_init; self->super.async_init = transport_mapper_inet_async_init; self->super.free_fn = transport_mapper_inet_free_method; self->super.address_family = AF_INET; } TransportMapperInet * transport_mapper_inet_new_instance(const gchar *transport) { TransportMapperInet *self = g_new0(TransportMapperInet, 1); transport_mapper_inet_init_instance(self, transport); return self; } TransportMapper * transport_mapper_tcp_new(void) { TransportMapperInet *self = transport_mapper_inet_new_instance("tcp"); self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; self->super.logproto = "text"; self->super.stats_source = stats_register_type("tcp"); self->server_port = TCP_PORT; self->require_tls_when_has_tls_context = TRUE; return &self->super; } TransportMapper * transport_mapper_tcp6_new(void) { TransportMapper *self = transport_mapper_tcp_new(); self->address_family = AF_INET6; self->stats_source = stats_register_type("tcp6"); return self; } TransportMapper * transport_mapper_udp_new(void) { TransportMapperInet *self = transport_mapper_inet_new_instance("udp"); self->super.sock_type = SOCK_DGRAM; self->super.sock_proto = IPPROTO_UDP; self->super.logproto = "dgram"; self->super.stats_source = stats_register_type("udp"); self->server_port = UDP_PORT; return &self->super; } TransportMapper * transport_mapper_udp6_new(void) { TransportMapper *self = transport_mapper_udp_new(); self->address_family = AF_INET6; self->stats_source = stats_register_type("udp6"); return self; } static gboolean transport_mapper_network_apply_transport(TransportMapper *s, GlobalConfig *cfg) { TransportMapperInet *self = (TransportMapperInet *) s; const gchar *transport; /* determine default port, apply transport setting to afsocket flags */ if (!transport_mapper_apply_transport_method(s, cfg)) return FALSE; transport = self->super.transport; self->server_port = NETWORK_PORT; if (strcasecmp(transport, "udp") == 0) { self->super.sock_type = SOCK_DGRAM; self->super.sock_proto = IPPROTO_UDP; self->super.logproto = "dgram"; } else if (strcasecmp(transport, "tcp") == 0) { self->super.logproto = "text"; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; } else if (strcasecmp(transport, "tls") == 0) { self->super.logproto = "text"; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; self->require_tls = TRUE; } else if (strcasecmp(transport, "proxied-tls") == 0) { self->super.logproto = "proxied-tcp"; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; self->require_tls = TRUE; } else { self->super.logproto = self->super.transport; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; /* FIXME: look up port/protocol from the logproto */ self->server_port = TCP_PORT; self->allow_tls = TRUE; } g_assert(self->server_port != 0); if (!transport_mapper_inet_validate_tls_options(self)) return FALSE; return TRUE; } TransportMapper * transport_mapper_network_new(void) { TransportMapperInet *self = transport_mapper_inet_new_instance("tcp"); self->super.apply_transport = transport_mapper_network_apply_transport; self->super.stats_source = stats_register_type("network"); return &self->super; } static gboolean transport_mapper_syslog_apply_transport(TransportMapper *s, GlobalConfig *cfg) { TransportMapperInet *self = (TransportMapperInet *) s; const gchar *transport = self->super.transport; /* determine default port, apply transport setting to afsocket flags */ if (!transport_mapper_apply_transport_method(s, cfg)) return FALSE; if (strcasecmp(transport, "udp") == 0) { if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_3)) { self->server_port_change_warning = "WARNING: Default port for syslog(transport(udp)) has changed from 601 to 514 in " VERSION_3_3 ", please update your configuration"; self->server_port = 601; } else self->server_port = SYSLOG_TRANSPORT_UDP_PORT; self->super.sock_type = SOCK_DGRAM; self->super.sock_proto = IPPROTO_UDP; self->super.logproto = "dgram"; } else if (strcasecmp(transport, "tcp") == 0) { self->server_port = SYSLOG_TRANSPORT_TCP_PORT; self->super.logproto = "framed"; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; } else if (strcasecmp(transport, "tls") == 0) { if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_3)) { self->server_port_change_warning = "WARNING: Default port for syslog(transport(tls)) has changed from 601 to 6514 in " VERSION_3_3 ", please update your configuration"; self->server_port = 601; } else self->server_port = SYSLOG_TRANSPORT_TLS_PORT; self->super.logproto = "framed"; self->super.sock_type = SOCK_STREAM; self->super.sock_proto = IPPROTO_TCP; self->require_tls = TRUE; } else { self->super.logproto = self->super.transport; self->super.sock_type = SOCK_STREAM; /* FIXME: look up port/protocol from the logproto */ self->server_port = 514; self->super.sock_proto = IPPROTO_TCP; self->allow_tls = TRUE; } g_assert(self->server_port != 0); if (!transport_mapper_inet_validate_tls_options(self)) return FALSE; return TRUE; } TransportMapper * transport_mapper_syslog_new(void) { TransportMapperInet *self = transport_mapper_inet_new_instance("tcp"); self->super.apply_transport = transport_mapper_syslog_apply_transport; self->super.stats_source = stats_register_type("syslog"); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper-inet.h000066400000000000000000000056271450431004300252600ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_MAPPER_INET_H_INCLUDED #define TRANSPORT_MAPPER_INET_H_INCLUDED #include "transport-mapper.h" #include "transport/tls-context.h" typedef struct _TransportMapperInet { TransportMapper super; gint server_port; const gchar *server_port_change_warning; guint32 flags; gboolean require_tls; gboolean allow_tls; gboolean require_tls_when_has_tls_context; TLSContext *tls_context; TLSVerifier *tls_verifier; gpointer secret_store_cb_data; } TransportMapperInet; static inline void transport_mapper_inet_set_allow_compress(TransportMapper *s, gboolean value) { TransportMapperInet *self = (TransportMapperInet *) s; if (value) self->flags |= TMI_ALLOW_COMPRESS; else self->flags &= ~TMI_ALLOW_COMPRESS; } static inline gint transport_mapper_inet_get_server_port(const TransportMapper *self) { return ((TransportMapperInet *) self)->server_port; } static inline void transport_mapper_inet_set_server_port(TransportMapper *self, gint server_port) { ((TransportMapperInet *) self)->server_port = server_port; } static inline const gchar * transport_mapper_inet_get_port_change_warning(TransportMapper *s) { TransportMapperInet *self = (TransportMapperInet *) s; return self->server_port_change_warning; } static inline void transport_mapper_inet_set_tls_context(TransportMapperInet *self, TLSContext *tls_context) { self->tls_context = tls_context; } static inline void transport_mapper_inet_set_tls_verifier(TransportMapperInet *self, TLSVerifier *tls_verifier) { tls_verifier_unref(self->tls_verifier); self->tls_verifier = tls_verifier; } void transport_mapper_inet_init_instance(TransportMapperInet *self, const gchar *transport); TransportMapper *transport_mapper_tcp_new(void); TransportMapper *transport_mapper_tcp6_new(void); TransportMapper *transport_mapper_udp_new(void); TransportMapper *transport_mapper_udp6_new(void); TransportMapper *transport_mapper_network_new(void); TransportMapper *transport_mapper_syslog_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper-unix.c000066400000000000000000000044661450431004300252770ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-mapper-unix.h" #include "transport-unix-socket.h" #include "stats/stats-registry.h" #include #include #include struct _TransportMapperUnix { TransportMapper super; }; static LogTransport * _construct_log_transport(TransportMapper *s, gint fd) { if (s->sock_type == SOCK_DGRAM) return log_transport_unix_dgram_socket_new(fd); else return log_transport_unix_stream_socket_new(fd); } static TransportMapperUnix * transport_mapper_unix_new_instance(const gchar *transport, gint sock_type) { TransportMapperUnix *self = g_new0(TransportMapperUnix, 1); transport_mapper_init_instance(&self->super, transport); self->super.construct_log_transport = _construct_log_transport; self->super.address_family = AF_UNIX; self->super.sock_type = sock_type; return self; } TransportMapper * transport_mapper_unix_dgram_new(void) { TransportMapperUnix *self = transport_mapper_unix_new_instance("unix-dgram", SOCK_DGRAM); self->super.logproto = "dgram"; self->super.stats_source = stats_register_type("unix-dgram"); return &self->super; } TransportMapper * transport_mapper_unix_stream_new(void) { TransportMapperUnix *self = transport_mapper_unix_new_instance("unix-stream", SOCK_STREAM); self->super.logproto = "text"; self->super.stats_source = stats_register_type("unix-stream"); return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper-unix.h000066400000000000000000000023401450431004300252710ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_MAPPER_UNIX_H_INCLUDED #define TRANSPORT_MAPPER_UNIX_H_INCLUDED #include "transport-mapper.h" typedef struct _TransportMapperUnix TransportMapperUnix; TransportMapper *transport_mapper_unix_dgram_new(void); TransportMapper *transport_mapper_unix_stream_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper.c000066400000000000000000000067371450431004300243210ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-mapper.h" #include "gprocess.h" #include "gsockaddr.h" #include "gsocket.h" #include "messages.h" #include "fdhelpers.h" #include "transport/transport-socket.h" #include #include static gboolean transport_mapper_privileged_bind(gint sock, GSockAddr *bind_addr) { cap_t saved_caps; GIOStatus status; saved_caps = g_process_cap_save(); g_process_enable_cap("cap_net_bind_service"); g_process_enable_cap("cap_dac_override"); status = g_bind(sock, bind_addr); g_process_cap_restore(saved_caps); return status == G_IO_STATUS_NORMAL; } gboolean transport_mapper_open_socket(TransportMapper *self, SocketOptions *socket_options, GSockAddr *bind_addr, GSockAddr *peer_addr, AFSocketDirection dir, int *fd) { gint sock; sock = socket(self->address_family, self->sock_type, self->sock_proto); if (sock < 0) { msg_error("Error creating socket", evt_tag_error(EVT_TAG_OSERROR)); goto error; } g_fd_set_nonblock(sock, TRUE); g_fd_set_cloexec(sock, TRUE); if (!socket_options_setup_socket(socket_options, sock, peer_addr, dir)) goto error_close; if (!transport_mapper_privileged_bind(sock, bind_addr)) { gchar buf[256]; msg_error("Error binding socket", evt_tag_str("addr", g_sockaddr_format(bind_addr, buf, sizeof(buf), GSA_FULL)), evt_tag_error(EVT_TAG_OSERROR)); goto error_close; } *fd = sock; return TRUE; error_close: close(sock); error: *fd = -1; return FALSE; } gboolean transport_mapper_apply_transport_method(TransportMapper *self, GlobalConfig *cfg) { return TRUE; } void transport_mapper_set_transport(TransportMapper *self, const gchar *transport) { g_free(self->transport); self->transport = g_strdup(transport); } void transport_mapper_set_address_family(TransportMapper *self, gint address_family) { self->address_family = address_family; } void transport_mapper_free_method(TransportMapper *self) { g_free(self->transport); } void transport_mapper_init_instance(TransportMapper *self, const gchar *transport) { self->transport = g_strdup(transport); self->address_family = -1; self->sock_type = -1; self->free_fn = transport_mapper_free_method; self->apply_transport = transport_mapper_apply_transport_method; } void transport_mapper_free(TransportMapper *self) { if (self->free_fn) self->free_fn(self); g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-mapper.h000066400000000000000000000070231450431004300243130ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef TRANSPORT_MAPPER_H_INCLUDED #define TRANSPORT_MAPPER_H_INCLUDED #include "socket-options.h" #include "transport/logtransport.h" #include "gsockaddr.h" typedef struct _TransportMapper TransportMapper; typedef gboolean (*TransportMapperAsyncInitCB)(gpointer arg); struct _TransportMapper { /* the transport() option as specified by the user */ gchar *transport; /* output parameters as determinted by TransportMapper */ gint address_family; /* SOCK_DGRAM or SOCK_STREAM or other SOCK_XXX values used by the socket() call */ gint sock_type; /* protocol parameter for the socket() call, 0 for default or IPPROTO_XXX for specific transports */ gint sock_proto; /* when a proto needs a Multitransport instance */ gboolean create_multitransport; const gchar *logproto; gint stats_source; gboolean (*apply_transport)(TransportMapper *self, GlobalConfig *cfg); LogTransport *(*construct_log_transport)(TransportMapper *self, gint fd); gboolean (*init)(TransportMapper *self); gboolean (*async_init)(TransportMapper *self, TransportMapperAsyncInitCB func, gpointer arg); void (*free_fn)(TransportMapper *self); }; void transport_mapper_set_transport(TransportMapper *self, const gchar *transport); void transport_mapper_set_address_family(TransportMapper *self, gint address_family); gboolean transport_mapper_open_socket(TransportMapper *self, SocketOptions *socket_options, GSockAddr *bind_addr, GSockAddr *peer_addr, AFSocketDirection dir, int *fd); gboolean transport_mapper_apply_transport_method(TransportMapper *self, GlobalConfig *cfg); void transport_mapper_init_instance(TransportMapper *self, const gchar *transport); void transport_mapper_free(TransportMapper *self); void transport_mapper_free_method(TransportMapper *self); static inline gboolean transport_mapper_apply_transport(TransportMapper *self, GlobalConfig *cfg) { return self->apply_transport(self, cfg); } static inline LogTransport * transport_mapper_construct_log_transport(TransportMapper *self, gint fd) { return self->construct_log_transport(self, fd); } static inline gboolean transport_mapper_init(TransportMapper *self) { if (self->init) return self->init(self); return TRUE; } static inline gboolean transport_mapper_async_init(TransportMapper *self, TransportMapperAsyncInitCB func, gpointer arg) { if (self->async_init) { return self->async_init(self, func, arg); } return func(arg); } #endif syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-unix-socket.c000066400000000000000000000200161450431004300252700ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * Copyright (c) 2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "transport-unix-socket.h" #include "transport/transport-socket.h" #include "scratch-buffers.h" #include "str-format.h" #include "compat-unix-creds.h" #include #include #include #include #include #include #include static void G_GNUC_UNUSED _add_nv_pair_int(LogTransportAuxData *aux, const gchar *name, gint value) { ScratchBuffersMarker marker; GString *buf = scratch_buffers_alloc_and_mark(&marker); g_string_truncate(buf, 0); format_uint32_padded(buf, -1, 0, 10, value); log_transport_aux_data_add_nv_pair(aux, name, buf->str); scratch_buffers_reclaim_marked(marker); } static void _format_proc_file_name(gchar *buf, gsize buflen, pid_t pid, const gchar *proc_file) { g_snprintf(buf, buflen, "/proc/%d/%s", pid, proc_file); } static gssize _read_text_file_content(const gchar *filename, gchar *buf, gsize buflen) { gint fd; gssize rc; gssize pos = 0; fd = open(filename, O_RDONLY); if (fd < 0) return -1; rc = 1; /* this loop leaves the last character of buf untouched, thus -1 in the * condition and the number of bytes to be read */ while (rc > 0 && pos < buflen - 1) { gsize count = (buflen - 1) - pos; rc = read(fd, buf + pos, count); if (rc < 0) { close(fd); return -1; } pos += rc; } /* zero terminate the buffer */ buf[pos] = 0; close(fd); return pos; } static gssize _read_text_file_content_without_trailing_newline(const gchar *filename, gchar *buf, gsize buflen) { gssize content_len; content_len = _read_text_file_content(filename, buf, buflen); if (content_len <= 0) return content_len; if (buf[content_len - 1] == '\n') content_len--; buf[content_len] = 0; return content_len; } static void G_GNUC_UNUSED _add_nv_pair_proc_read_unless_unset(LogTransportAuxData *aux, const gchar *name, pid_t pid, const gchar *proc_file, const gchar *unset_value) { gchar filename[64]; gchar content[4096]; gssize content_len; _format_proc_file_name(filename, sizeof(filename), pid, proc_file); content_len = _read_text_file_content_without_trailing_newline(filename, content, sizeof(content)); if (content_len > 0 && (!unset_value || strcmp(content, unset_value) != 0)) log_transport_aux_data_add_nv_pair(aux, name, content); } static void G_GNUC_UNUSED _add_nv_pair_proc_read_argv(LogTransportAuxData *aux, const gchar *name, pid_t pid, const gchar *proc_file) { gchar filename[64]; gchar content[4096]; gssize content_len; gint i; _format_proc_file_name(filename, sizeof(filename), pid, proc_file); content_len = _read_text_file_content(filename, content, sizeof(content)); for (i = 0; i < content_len; i++) { if (!g_ascii_isprint(content[i])) content[i] = ' '; } if (content_len > 0) log_transport_aux_data_add_nv_pair(aux, name, content); } static void G_GNUC_UNUSED _add_nv_pair_proc_readlink(LogTransportAuxData *aux, const gchar *name, pid_t pid, const gchar *proc_file) { gchar filename[64]; gchar content[4096]; gssize content_len; _format_proc_file_name(filename, sizeof(filename), pid, proc_file); content_len = readlink(filename, content, sizeof(content)); if (content_len > 0) { if (content_len == sizeof(content)) content_len--; content[content_len] = 0; log_transport_aux_data_add_nv_pair(aux, name, content); } } #if defined (CRED_PASS_SUPPORTED) static void _feed_aux_from_ucred(LogTransportAuxData *aux, cred_t *uc) { _add_nv_pair_int(aux, ".unix.pid", cred_get(uc, pid)); _add_nv_pair_int(aux, ".unix.uid", cred_get(uc, uid)); _add_nv_pair_int(aux, ".unix.gid", cred_get(uc, gid)); } #endif #if defined(__linux__) && defined(CRED_PASS_SUPPORTED) static void _feed_aux_from_procfs(LogTransportAuxData *aux, pid_t pid) { _add_nv_pair_proc_read_argv(aux, ".unix.cmdline", pid, "cmdline"); _add_nv_pair_proc_readlink(aux, ".unix.exe", pid, "exe"); /* NOTE: we use the names the audit subsystem does, so if in the future we'd be * processing audit records, the nvpair names would match up. */ _add_nv_pair_proc_read_unless_unset(aux, ".audit.auid", pid, "loginuid", "4294967295"); _add_nv_pair_proc_read_unless_unset(aux, ".audit.ses", pid, "sessionid", "4294967295"); } #elif defined(__FreeBSD__) && defined(CRED_PASS_SUPPORTED) static void _feed_aux_from_procfs(LogTransportAuxData *aux, pid_t pid) { _add_nv_pair_proc_read_argv(aux, ".unix.cmdline", pid, "cmdline"); _add_nv_pair_proc_readlink(aux, ".unix.exe", pid, "file"); } #endif static void _feed_credentials_from_cmsg(LogTransportAuxData *aux, struct msghdr *msg) { #if defined(CRED_PASS_SUPPORTED) struct cmsghdr *cmsg; cred_t uc; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { memcpy(&uc, CMSG_DATA(cmsg), sizeof(uc)); _feed_aux_from_procfs(aux, cred_get(&uc, pid)); _feed_aux_from_ucred(aux, &uc); break; } } #endif } static void _feed_aux_from_cmsg(LogTransportAuxData *aux, struct msghdr *msg) { _feed_credentials_from_cmsg(aux, msg); } static gssize _unix_socket_read(gint fd, gpointer buf, gsize buflen, LogTransportAuxData *aux) { gint rc; struct msghdr msg; struct iovec iov[1]; struct sockaddr_storage ss; #if defined(SYSLOG_NG_HAVE_CTRLBUF_IN_MSGHDR) gchar ctlbuf[32]; msg.msg_control = ctlbuf; msg.msg_controllen = sizeof(ctlbuf); #endif msg.msg_name = (struct sockaddr *) &ss; msg.msg_namelen = sizeof(ss); msg.msg_iovlen = 1; msg.msg_iov = iov; iov[0].iov_base = buf; iov[0].iov_len = buflen; do { rc = recvmsg(fd, &msg, 0); } while (rc == -1 && errno == EINTR); if (rc >= 0) { if (msg.msg_namelen && aux) log_transport_aux_data_set_peer_addr_ref(aux, g_sockaddr_new((struct sockaddr *) &ss, msg.msg_namelen)); _feed_aux_from_cmsg(aux, &msg); } return rc; } static gssize log_transport_unix_dgram_socket_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { gint rc; rc = _unix_socket_read(s->fd, buf, buflen, aux); if (rc == 0) { /* DGRAM sockets should never return EOF, they just need to be read again */ rc = -1; errno = EAGAIN; } return rc; } LogTransport * log_transport_unix_dgram_socket_new(gint fd) { LogTransportSocket *self = g_new0(LogTransportSocket, 1); log_transport_dgram_socket_init_instance(self, fd); self->super.read = log_transport_unix_dgram_socket_read_method; return &self->super; } static gssize log_transport_unix_stream_socket_read_method(LogTransport *s, gpointer buf, gsize buflen, LogTransportAuxData *aux) { return _unix_socket_read(s->fd, buf, buflen, aux); } LogTransport * log_transport_unix_stream_socket_new(gint fd) { LogTransportSocket *self = g_new0(LogTransportSocket, 1); log_transport_stream_socket_init_instance(self, fd); self->super.read = log_transport_unix_stream_socket_read_method; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/afsocket/transport-unix-socket.h000066400000000000000000000023071450431004300253000ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_TRANSPORT_UNIX_SOCKET_H_INCLUDED #define AFSOCKET_TRANSPORT_UNIX_SOCKET_H_INCLUDED #include "transport/logtransport.h" LogTransport *log_transport_unix_dgram_socket_new(gint fd); LogTransport *log_transport_unix_stream_socket_new(gint fd); #endif syslog-ng-syslog-ng-4.4.0/modules/afsql/000077500000000000000000000000001450431004300201315ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afsql/CMakeLists.txt000066400000000000000000000007111450431004300226700ustar00rootroot00000000000000if (NOT DEFINED ENABLE_SQL OR ENABLE_SQL) find_package(LIBDBI) find_package(OpenSSL) endif() module_switch(ENABLE_SQL "Enable SQL plugin" LIBDBI_FOUND) if (NOT ENABLE_SQL) return() endif() set(AFSQL_SOURCES afsql.c afsql.h afsql-parser.c afsql-parser.h afsql-plugin.c ) add_module( TARGET afsql GRAMMAR afsql-grammar INCLUDES ${LIBDBI_INCLUDE_DIRS} DEPENDS ${LIBDBI_LIBRARIES} OpenSSL::SSL SOURCES ${AFSQL_SOURCES} ) syslog-ng-syslog-ng-4.4.0/modules/afsql/Makefile.am000066400000000000000000000017701450431004300221720ustar00rootroot00000000000000if ENABLE_SQL module_LTLIBRARIES += modules/afsql/libafsql.la modules_afsql_libafsql_la_SOURCES = \ modules/afsql/afsql.c \ modules/afsql/afsql.h \ modules/afsql/afsql-grammar.y \ modules/afsql/afsql-parser.c \ modules/afsql/afsql-parser.h \ modules/afsql/afsql-plugin.c modules_afsql_libafsql_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/afsql \ -I$(top_builddir)/modules/afsql modules_afsql_libafsql_la_LIBADD = \ $(MODULE_DEPS_LIBS) $(LIBDBI_LIBS) \ $(OPENSSL_LIBS) modules_afsql_libafsql_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afsql_libafsql_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) modules/afsql modules/afsql/ mod-afsql mod-sql: \ modules/afsql/libafsql.la else modules/afsql modules/afsql/ mod-afsql mod-sql: endif BUILT_SOURCES += \ modules/afsql/afsql-grammar.y \ modules/afsql/afsql-grammar.c \ modules/afsql/afsql-grammar.h EXTRA_DIST += \ modules/afsql/afsql-grammar.ym \ modules/afsql/CMakeLists.txt .PHONY: modules/afsql/ mod-afsql mod-sql syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql-grammar.ym000066400000000000000000000120701450431004300232320ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "afsql-parser.h" } %code { #include "afsql.h" #include "cfg-grammar-internal.h" #include "cfg-parser.h" #include "messages.h" #include "plugin.h" } %define api.prefix {afsql_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_DEFAULT %token KW_DBD_OPTION %token KW_DBI_DRIVER_DIR %token KW_QUOTE_CHAR %token KW_INDEXES %token KW_VALUES %token KW_SQL %token KW_PASSWORD %token KW_USERNAME %token KW_DATABASE %token KW_TABLE %token KW_SESSION_STATEMENTS %token KW_CREATE_STATEMENT_APPEND %token KW_COLUMNS %token KW_NULL %token KW_IGNORE_TNS_CONFIG %type dest_afsql %type dest_afsql_params %type dest_afsql_values %type dest_afsql_values_build %type dest_afsql_flags %% start : LL_CONTEXT_DESTINATION dest_afsql { YYACCEPT; } ; dest_afsql : KW_SQL '(' _inner_dest_context_push dest_afsql_params _inner_dest_context_pop ')' { $$ = $4; } ; dest_afsql_params : { last_driver = *instance = afsql_dd_new(configuration); } dest_afsql_options { $$ = last_driver; } ; dest_afsql_options : dest_afsql_option dest_afsql_options | ; dest_afsql_option : KW_TYPE '(' string ')' { afsql_dd_set_type(last_driver, $3); free($3); } | KW_HOST '(' string ')' { afsql_dd_set_host(last_driver, $3); free($3); } | KW_PORT '(' string_or_number ')' { CHECK_ERROR(afsql_dd_check_port($3), @3, "Illegal sql port number: %s", $3); afsql_dd_set_port(last_driver, $3); free($3); } | KW_USERNAME '(' string ')' { afsql_dd_set_user(last_driver, $3); free($3); } | KW_DBD_OPTION '(' string LL_NUMBER ')' { afsql_dd_add_dbd_option_numeric(last_driver, $3, $4); free($3); } | KW_DBD_OPTION '(' string string ')' { afsql_dd_add_dbd_option(last_driver, $3, $4); free($3); free($4); } | KW_DBI_DRIVER_DIR '(' path ')' { afsql_dd_set_dbi_driver_dir(last_driver, $3); free($3); } | KW_QUOTE_CHAR '(' string ')' { afsql_dd_set_quote_char(last_driver, $3); } | KW_PASSWORD '(' string ')' { afsql_dd_set_password(last_driver, $3); free($3); } | KW_DATABASE '(' string ')' { afsql_dd_set_database(last_driver, $3); free($3); } | KW_TABLE '(' template_content ')' { afsql_dd_set_table(last_driver, $3); } | KW_COLUMNS '(' string_list ')' { afsql_dd_set_columns(last_driver, $3); } | KW_INDEXES '(' string_list ')' { afsql_dd_set_indexes(last_driver, $3); } | KW_VALUES '(' dest_afsql_values ')' { afsql_dd_set_values(last_driver, $3); } | KW_IGNORE_TNS_CONFIG '(' yesno ')' { afsql_dd_set_ignore_tns_config(last_driver,$3); } | KW_NULL '(' string ')' { afsql_dd_set_null_value(last_driver, $3); free($3); } | KW_SESSION_STATEMENTS '(' string_list ')' { afsql_dd_set_session_statements(last_driver, $3); } | KW_FLAGS '(' dest_afsql_flags ')' { afsql_dd_set_flags(last_driver, $3); } | KW_CREATE_STATEMENT_APPEND '(' string ')' { afsql_dd_set_create_statement_append(last_driver, $3); free($3); } | { last_template_options = &((AFSqlDestDriver *) last_driver)->template_options; } template_option | threaded_dest_driver_general_option | threaded_dest_driver_batch_option ; dest_afsql_values : dest_afsql_values_build { $$ = g_list_reverse($1); } ; dest_afsql_values_build : template_content dest_afsql_values_build { $$ = g_list_append($2, log_template_ref($1)); log_template_unref($1); } | KW_DEFAULT dest_afsql_values_build { $$ = g_list_append($2, NULL); } | { $$ = NULL; } ; dest_afsql_flags : normalized_flag dest_afsql_flags { $$ = afsql_dd_lookup_flag($1) | $2; free($1); } | { $$ = 0; } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql-parser.c000066400000000000000000000052231450431004300226770ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsql.h" #include "cfg-parser.h" #include "afsql-grammar.h" extern int afsql_debug; int afsql_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afsql_keywords[] = { { "sql", KW_SQL }, { "username", KW_USERNAME }, { "password", KW_PASSWORD }, { "database", KW_DATABASE }, { "table", KW_TABLE }, { "columns", KW_COLUMNS }, { "indexes", KW_INDEXES }, { "values", KW_VALUES }, { "quote_char", KW_QUOTE_CHAR }, { "frac_digits", KW_FRAC_DIGITS }, { "session_statements", KW_SESSION_STATEMENTS }, { "host", KW_HOST }, { "port", KW_PORT }, { "default", KW_DEFAULT }, { "local_time_zone", KW_LOCAL_TIME_ZONE }, { "null", KW_NULL }, { "retry_sql_inserts", KW_RETRIES }, { "flush_lines", KW_BATCH_LINES, KWS_OBSOLETE, "The flush-lines() option is deprecated, use batch-lines() instead." }, { "flush_timeout", KW_BATCH_TIMEOUT, KWS_OBSOLETE, "The flush-timeout() option is deprecated, use batch-timeout() instead." }, { "flags", KW_FLAGS }, { "create_statement_append", KW_CREATE_STATEMENT_APPEND }, { "ignore_tns_config", KW_IGNORE_TNS_CONFIG }, { "dbd_option", KW_DBD_OPTION }, { "dbi_driver_dir", KW_DBI_DRIVER_DIR }, { NULL } }; CfgParser afsql_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afsql_debug, #endif .name = "afsql", .keywords = afsql_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) afsql_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afsql_, AFSQL_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql-parser.h000066400000000000000000000022231450431004300227010ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSSQL_PARSER_H_INCLUDED #define AFSSQL_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser afsql_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afsql_, AFSQL_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql-plugin.c000066400000000000000000000031611450431004300227000ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afsql_parser; static Plugin afsql_plugins[] = { { .type = LL_CONTEXT_DESTINATION, .name = "sql", .parser = &afsql_parser, }, }; gboolean afsql_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afsql_plugins, G_N_ELEMENTS(afsql_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afsql", .version = SYSLOG_NG_VERSION, .description = "The afsql module provides SQL destination support for syslog-ng", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afsql_plugins, .plugins_len = G_N_ELEMENTS(afsql_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql.c000066400000000000000000001146631450431004300214160ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afsql.h" #include "logqueue.h" #include "template/templates.h" #include "messages.h" #include "string-list.h" #include "str-format.h" #include "seqnum.h" #include "stats/stats-registry.h" #include "apphook.h" #include "mainloop-worker.h" #include "str-utils.h" #include #include #include "compat/openssl_support.h" #include static gboolean dbi_initialized = FALSE; static const char *s_oracle = "oracle"; static const char *s_freetds = "freetds"; static dbi_inst dbi_instance; static const gint DEFAULT_SQL_TX_SIZE = 100; #define MAX_FAILED_ATTEMPTS 3 void afsql_dd_add_dbd_option(LogDriver *s, const gchar *name, const gchar *value) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_hash_table_insert(self->dbd_options, g_strdup(name), g_strdup(value)); } void afsql_dd_add_dbd_option_numeric(LogDriver *s, const gchar *name, gint value) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_hash_table_insert(self->dbd_options_numeric, g_strdup(name), GINT_TO_POINTER(value)); } void afsql_dd_set_dbi_driver_dir(LogDriver *s, const gchar *dbi_driver_dir) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->dbi_driver_dir); self->dbi_driver_dir = g_strdup(dbi_driver_dir); } void afsql_dd_set_quote_char(LogDriver *s, const gchar *quote_str) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->quote_as_string); self->quote_as_string = g_strdup(quote_str); } void afsql_dd_set_type(LogDriver *s, const gchar *type) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->type); if (strcmp(type, "mssql") == 0) type = s_freetds; self->type = g_strdup(type); } void afsql_dd_set_host(LogDriver *s, const gchar *host) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->host); self->host = g_strdup(host); } gboolean afsql_dd_check_port(const gchar *port) { /* only digits (->numbers) are allowed */ int len = strlen(port); for (int i = 0; i < len; ++i) if (port[i] < '0' || port[i] > '9') return FALSE; return TRUE; } void afsql_dd_set_port(LogDriver *s, const gchar *port) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->port); self->port = g_strdup(port); } void afsql_dd_set_user(LogDriver *s, const gchar *user) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->user); self->user = g_strdup(user); } void afsql_dd_set_password(LogDriver *s, const gchar *password) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->password); self->password = g_strdup(password); } void afsql_dd_set_database(LogDriver *s, const gchar *database) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->database); self->database = g_strdup(database); } void afsql_dd_set_table(LogDriver *s, LogTemplate *table_template) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; log_template_unref(self->table); self->table = table_template; } void afsql_dd_set_columns(LogDriver *s, GList *columns) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; string_list_free(self->columns); self->columns = columns; } void afsql_dd_set_indexes(LogDriver *s, GList *indexes) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; string_list_free(self->indexes); self->indexes = indexes; } void afsql_dd_set_values(LogDriver *s, GList *values) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; string_list_free(self->values); self->values = values; } void afsql_dd_set_null_value(LogDriver *s, const gchar *null) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; if (self->null_value) g_free(self->null_value); self->null_value = g_strdup(null); } void afsql_dd_set_ignore_tns_config(LogDriver *s, const gboolean ignore_tns_config) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; self->ignore_tns_config = ignore_tns_config; } void afsql_dd_set_session_statements(LogDriver *s, GList *session_statements) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; self->session_statements = session_statements; } void afsql_dd_set_flags(LogDriver *s, gint flags) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; self->flags = flags; } void afsql_dd_set_create_statement_append(LogDriver *s, const gchar *create_statement_append) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; g_free(self->create_statement_append); self->create_statement_append = g_strdup(create_statement_append); } /** * afsql_dd_run_query: * * Run an SQL query on the connected database. * * NOTE: This function can only be called from the database thread. **/ static gboolean afsql_dd_run_query(AFSqlDestDriver *self, const gchar *query, gboolean silent, dbi_result *result) { dbi_result db_res; msg_debug("Running SQL query", evt_tag_str("query", query)); db_res = dbi_conn_query(self->dbi_ctx, query); if (!db_res) { const gchar *dbi_error; if (!silent) { dbi_conn_error(self->dbi_ctx, &dbi_error); msg_error("Error running SQL query", evt_tag_str("type", self->type), evt_tag_str("host", self->host), evt_tag_str("port", self->port), evt_tag_str("user", self->user), evt_tag_str("database", self->database), evt_tag_str("error", dbi_error), evt_tag_str("query", query)); } return FALSE; } if (result) *result = db_res; else dbi_result_free(db_res); return TRUE; } /** * afsql_dd_commit_transaction: * * Commit SQL transaction. * * NOTE: This function can only be called from the database thread. **/ static gboolean afsql_dd_commit_transaction(AFSqlDestDriver *self) { gboolean success; if (!self->transaction_active) return TRUE; success = afsql_dd_run_query(self, "COMMIT", FALSE, NULL); if (success) { self->transaction_active = FALSE; } else { msg_error("SQL transaction commit failed, rewinding backlog and starting again"); } return success; } /** * afsql_dd_begin_transaction: * * Begin SQL transaction. * * NOTE: This function can only be called from the database thread. **/ static gboolean afsql_dd_begin_transaction(AFSqlDestDriver *self) { gboolean success = TRUE; const char *s_begin = "BEGIN"; if (!strcmp(self->type, s_freetds)) { /* the mssql requires this command */ s_begin = "BEGIN TRANSACTION"; } if (strcmp(self->type, s_oracle) != 0) { /* oracle db has no BEGIN TRANSACTION command, it implicitly starts one, after every commit. */ success = afsql_dd_run_query(self, s_begin, FALSE, NULL); } self->transaction_active = success; return success; } static gboolean afsql_dd_rollback_transaction(AFSqlDestDriver *self) { if (!self->transaction_active) return TRUE; self->transaction_active = FALSE; return afsql_dd_run_query(self, "ROLLBACK", FALSE, NULL); } static gboolean afsql_dd_begin_new_transaction(AFSqlDestDriver *self) { if (self->transaction_active) { if (!afsql_dd_commit_transaction(self)) { afsql_dd_rollback_transaction(self); return FALSE; } } return afsql_dd_begin_transaction(self); } static gboolean _sql_identifier_is_valid_char(gchar c) { return ((c == '.') || (c == '_') || (c >= '0' && c <= '9') || (g_ascii_tolower(c) >= 'a' && g_ascii_tolower(c) <= 'z')); } static gboolean _is_sql_identifier_sanitized(const gchar *token) { gint i; for (i = 0; token[i]; i++) { if (!_sql_identifier_is_valid_char(token[i])) return FALSE; } return TRUE; } static void _sanitize_sql_identifier(gchar *token) { gint i; for (i = 0; token[i]; i++) { if (!_sql_identifier_is_valid_char(token[i])) token[i] = '_'; } } /** * afsql_dd_create_index: * * This function creates an index for the column specified and returns * TRUE to indicate success. * * NOTE: This function can only be called from the database thread. **/ static gboolean afsql_dd_create_index(AFSqlDestDriver *self, const gchar *table, const gchar *column) { GString *query_string; gboolean success = TRUE; query_string = g_string_sized_new(64); if (strcmp(self->type, s_oracle) == 0) { /* NOTE: oracle index indentifier length is max 30 characters * so we use the first 30 characters of the table_column MD5 hash */ if ((strlen(table) + strlen(column)) > 25) { guchar hash[EVP_MAX_MD_SIZE]; gchar hash_str[31]; gchar *cat = g_strjoin("_", table, column, NULL); guint md_len; const EVP_MD *md5 = EVP_get_digestbyname("md5"); DECLARE_EVP_MD_CTX(mdctx); EVP_MD_CTX_init(mdctx); EVP_DigestInit_ex(mdctx, md5, NULL); EVP_DigestUpdate(mdctx, (guchar *) cat, strlen(cat)); EVP_DigestFinal_ex(mdctx, hash, &md_len); EVP_MD_CTX_destroy(mdctx); g_free(cat); format_hex_string(hash, md_len, hash_str, sizeof(hash_str)); hash_str[0] = 'i'; g_string_printf(query_string, "CREATE INDEX %s ON %s%s%s (%s)", hash_str, self->quote_as_string, table, self->quote_as_string, column); } else g_string_printf(query_string, "CREATE INDEX %s%s_%s_idx%s ON %s%s%s (%s)", self->quote_as_string, table, column, self->quote_as_string, self->quote_as_string, table, self->quote_as_string, column); } else g_string_printf(query_string, "CREATE INDEX %s%s_%s_idx%s ON %s%s%s (%s)", self->quote_as_string, table, column, self->quote_as_string, self->quote_as_string, table, self->quote_as_string, column); if (!afsql_dd_run_query(self, query_string->str, FALSE, NULL)) { msg_error("Error adding missing index", evt_tag_str("table", table), evt_tag_str("column", column)); success = FALSE; } g_string_free(query_string, TRUE); return success; } static inline gboolean _is_table_syslogng_conform(AFSqlDestDriver *self, const gchar *table) { return (g_hash_table_lookup(self->syslogng_conform_tables, table) != NULL); } static inline void _remember_table_as_syslogng_conform(AFSqlDestDriver *self, const gchar *table) { g_hash_table_insert(self->syslogng_conform_tables, g_strdup(table), GUINT_TO_POINTER(TRUE)); } static gboolean _is_table_present(AFSqlDestDriver *self, const gchar *table, dbi_result *metadata) { gboolean res = FALSE; GString *query_string; if (!afsql_dd_begin_new_transaction(self)) { msg_error("Starting new transaction has failed"); return FALSE; } query_string = g_string_sized_new(32); g_string_printf(query_string, "SELECT * FROM %s%s%s WHERE 0=1", self->quote_as_string, table, self->quote_as_string); res = afsql_dd_run_query(self, query_string->str, TRUE, metadata); g_string_free(query_string, TRUE); afsql_dd_commit_transaction(self); return res; } static gboolean _ensure_table_is_syslogng_conform(AFSqlDestDriver *self, dbi_result db_res, const gchar *table) { gboolean success = TRUE; gboolean new_transaction_started = FALSE; gint i; GString *query_string = g_string_sized_new(32); for (i = 0; success && (i < self->fields_len); i++) { if (dbi_result_get_field_idx(db_res, self->fields[i].name) == 0) { GList *l; if (!new_transaction_started) { if (!afsql_dd_begin_new_transaction(self)) { msg_error("Starting new transaction for modifying(ALTER) table has failed", evt_tag_str("table", table)); success = FALSE; break; } new_transaction_started = TRUE; } /* field does not exist, add this column */ g_string_printf(query_string, "ALTER TABLE %s%s%s ADD %s %s", self->quote_as_string, table, self->quote_as_string, self->fields[i].name, self->fields[i].type); if (!afsql_dd_run_query(self, query_string->str, FALSE, NULL)) { msg_error("Error adding missing column, giving up", evt_tag_str("table", table), evt_tag_str("column", self->fields[i].name)); success = FALSE; break; } for (l = self->indexes; l; l = l->next) { if (strcmp((gchar *) l->data, self->fields[i].name) == 0) { /* this is an indexed column, create index */ afsql_dd_create_index(self, table, self->fields[i].name); } } } } if (new_transaction_started && ( !success || !afsql_dd_commit_transaction(self))) { afsql_dd_rollback_transaction(self); success = FALSE; } g_string_free(query_string, TRUE); return success; } static gboolean _table_create_indexes(AFSqlDestDriver *self, const gchar *table) { gboolean success = TRUE; GList *l; if (!afsql_dd_begin_new_transaction(self)) { msg_error("Starting new transaction for table creation has failed", evt_tag_str("table", table)); return FALSE; } for (l = self->indexes; l && success; l = l->next) { success = afsql_dd_create_index(self, table, (gchar *) l->data); } if (!success || !afsql_dd_commit_transaction(self)) { afsql_dd_rollback_transaction(self); } return success; } static gboolean _table_create(AFSqlDestDriver *self, const gchar *table) { gint i; GString *query_string = g_string_sized_new(32); gboolean success = FALSE; if (!afsql_dd_begin_new_transaction(self)) { msg_error("Starting new transaction for table creation has failed", evt_tag_str("table", table)); return FALSE; } g_string_printf(query_string, "CREATE TABLE %s%s%s (", self->quote_as_string, table, self->quote_as_string); for (i = 0; i < self->fields_len; i++) { g_string_append_printf(query_string, "%s %s", self->fields[i].name, self->fields[i].type); if (i != self->fields_len - 1) g_string_append(query_string, ", "); } g_string_append(query_string, ")"); if (self->create_statement_append) g_string_append(query_string, self->create_statement_append); if (afsql_dd_run_query(self, query_string->str, FALSE, NULL)) { success = TRUE; } else { msg_error("Error creating table, giving up", evt_tag_str("table", table)); } if (!success || !afsql_dd_commit_transaction(self)) { afsql_dd_rollback_transaction(self); } g_string_free(query_string, TRUE); return success; } /** * afsql_dd_validate_table: * * Check if the given table exists in the database. If it doesn't * create it, if it does, check if all the required fields are * present and create them if they don't. * * NOTE: This function can only be called from the database thread. **/ static gboolean afsql_dd_ensure_table_is_syslogng_conform(AFSqlDestDriver *self, GString *table) { dbi_result db_res = NULL; gboolean success = FALSE; if (self->flags & AFSQL_DDF_DONT_CREATE_TABLES) return TRUE; _sanitize_sql_identifier(table->str); if (_is_table_syslogng_conform(self, table->str)) return TRUE; if (_is_table_present(self, table->str, &db_res)) { /* table exists, check structure */ success = _ensure_table_is_syslogng_conform(self, db_res, table->str); if (db_res) dbi_result_free(db_res); } else { /* table does not exist, create it */ success = _table_create(self, table->str) && _table_create_indexes(self, table->str); } if (success) { /* we have successfully created/altered the destination table, record this information */ _remember_table_as_syslogng_conform(self, table->str); } return success; } static void afsql_dd_set_dbd_opt(gpointer key, gpointer value, gpointer user_data) { dbi_conn_set_option((dbi_conn)user_data, (gchar *)key, (gchar *)value); } static void afsql_dd_set_dbd_opt_numeric(gpointer key, gpointer value, gpointer user_data) { dbi_conn_set_option_numeric((dbi_conn)user_data, (gchar *)key, GPOINTER_TO_INT(value)); } /* * NOTE: there's a bug in libdbd-sqlite3 and this function basically works * that around. The issue is that the database path cannot be an empty * string as it causes an invalid read (it is using -1 as an index in that * case). What we do is that if database is a fully specified path to a * filename (e.g. starts with a slash), we use another slash, so it remains * a root-relative filename. Otherwise, we simply use the current * directory. */ static const gchar * _sqlite_db_dir(const gchar *database, gchar *buf, gsize buflen) { if (database[0] == '/') return strncpy(buf, "/", buflen); else return getcwd(buf, buflen); return buf; } static void _enable_database_specific_hacks(AFSqlDestDriver *self) { gchar buf[1024]; if (strcmp(self->type, "sqlite") == 0) dbi_conn_set_option(self->dbi_ctx, "sqlite_dbdir", _sqlite_db_dir(self->database, buf, sizeof(buf))); else if (strcmp(self->type, "sqlite3") == 0) dbi_conn_set_option(self->dbi_ctx, "sqlite3_dbdir", _sqlite_db_dir(self->database, buf, sizeof(buf))); else if (strcmp(self->type, s_oracle) == 0) dbi_conn_set_option_numeric(self->dbi_ctx, "oracle_ignore_tns_config", self->ignore_tns_config); } static gboolean afsql_dd_connect(LogThreadedDestDriver *s) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; self->dbi_ctx = dbi_conn_new_r(self->type, dbi_instance); if (!self->dbi_ctx) { msg_error("No such DBI driver", evt_tag_str("type", self->type)); return FALSE; } dbi_conn_set_option(self->dbi_ctx, "host", self->host); if (strcmp(self->type, "mysql")) dbi_conn_set_option(self->dbi_ctx, "port", self->port); else dbi_conn_set_option_numeric(self->dbi_ctx, "port", atoi(self->port)); dbi_conn_set_option(self->dbi_ctx, "username", self->user); dbi_conn_set_option(self->dbi_ctx, "password", self->password); dbi_conn_set_option(self->dbi_ctx, "dbname", self->database); dbi_conn_set_option(self->dbi_ctx, "encoding", self->encoding); dbi_conn_set_option(self->dbi_ctx, "auto-commit", self->flags & AFSQL_DDF_EXPLICIT_COMMITS ? "false" : "true"); _enable_database_specific_hacks(self); /* Set user-specified options */ g_hash_table_foreach(self->dbd_options, afsql_dd_set_dbd_opt, self->dbi_ctx); g_hash_table_foreach(self->dbd_options_numeric, afsql_dd_set_dbd_opt_numeric, self->dbi_ctx); if (dbi_conn_connect(self->dbi_ctx) < 0) { const gchar *dbi_error; dbi_conn_error(self->dbi_ctx, &dbi_error); msg_error("Error establishing SQL connection", evt_tag_str("type", self->type), evt_tag_str("host", self->host), evt_tag_str("port", self->port), evt_tag_str("username", self->user), evt_tag_str("database", self->database), evt_tag_str("error", dbi_error)); return FALSE; } if (self->session_statements != NULL) { GList *l; for (l = self->session_statements; l; l = l->next) { if (!afsql_dd_run_query(self, (gchar *) l->data, FALSE, NULL)) { msg_error("Error executing SQL connection statement", evt_tag_str("statement", (gchar *) l->data)); return FALSE; } } } return TRUE; } static void afsql_dd_disconnect(LogThreadedDestDriver *s) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; dbi_conn_close(self->dbi_ctx); self->dbi_ctx = NULL; } static GString * afsql_dd_ensure_accessible_database_table(AFSqlDestDriver *self, LogMessage *msg) { GString *table = g_string_sized_new(32); LogTemplateEvalOptions options = {&self->template_options, LTZ_LOCAL, 0, NULL, LM_VT_STRING}; log_template_format(self->table, msg, &options, table); if (!afsql_dd_ensure_table_is_syslogng_conform(self, table)) { /* If validate table is FALSE then close the connection and wait time_reopen time (next call) */ msg_error("Error checking table, disconnecting from database, trying again shortly", evt_tag_int("time_reopen", self->super.time_reopen)); g_string_free(table, TRUE); return NULL; } return table; } static void afsql_dd_append_quoted_value(AFSqlDestDriver *self, GString *value, GString *insert_command) { gchar *quoted = NULL; dbi_conn_quote_string_copy(self->dbi_ctx, value->str, "ed); if (quoted) g_string_append(insert_command, quoted); else g_string_append(insert_command, "''"); free(quoted); } static void afsql_dd_append_quoted_binary_value(AFSqlDestDriver *self, GString *value, GString *insert_command) { guchar *quoted = NULL; dbi_conn_quote_binary_copy(self->dbi_ctx, (guchar *) value->str, value->len, "ed); if (quoted) g_string_append(insert_command, (gchar *) quoted); else g_string_append(insert_command, "''"); free(quoted); } static gboolean afsql_dd_append_value_to_be_inserted(AFSqlDestDriver *self, AFSqlField *field, GString *value, LogMessageValueType type, GString *insert_command) { gboolean need_drop = FALSE; gboolean fallback = self->template_options.on_error & ON_ERROR_FALLBACK_TO_STRING; if (self->null_value && strcmp(self->null_value, value->str) == 0) { g_string_append(insert_command, "NULL"); return TRUE; } switch(type) { case LM_VT_INTEGER: { gint64 k; if (type_cast_to_int64(value->str, &k, NULL)) { g_string_append_len(insert_command, value->str, value->len); } else { need_drop = type_cast_drop_helper(self->template_options.on_error, value->str, "int"); if (fallback) afsql_dd_append_quoted_value(self, value, insert_command); } break; } case LM_VT_DOUBLE: { gdouble d; if (type_cast_to_double(value->str, &d, NULL)) { g_string_append_len(insert_command, value->str, value->len); } else { need_drop = type_cast_drop_helper(self->template_options.on_error, value->str, "double"); if (fallback) afsql_dd_append_quoted_value(self, value, insert_command); } break; } case LM_VT_BOOLEAN: { gboolean b; if (type_cast_to_boolean(value->str, &b, NULL)) { if (b) g_string_append(insert_command, "TRUE"); else g_string_append(insert_command, "FALSE"); } else { need_drop = type_cast_drop_helper(self->template_options.on_error, value->str, "boolean"); if (fallback) afsql_dd_append_quoted_value(self, value, insert_command); } } case LM_VT_NULL: g_string_append(insert_command, "NULL"); break; case LM_VT_BYTES: case LM_VT_PROTOBUF: afsql_dd_append_quoted_binary_value(self, value, insert_command); break; default: afsql_dd_append_quoted_value(self, value, insert_command); } if (need_drop) return FALSE; return TRUE; } static GString * afsql_dd_build_insert_command(AFSqlDestDriver *self, LogMessage *msg, GString *table) { GString *insert_command = g_string_sized_new(256); GString *value = g_string_sized_new(512); gint i, j; g_string_printf(insert_command, "INSERT INTO %s%s%s (", self->quote_as_string, table->str, self->quote_as_string); for (i = 0; i < self->fields_len; i++) { if ((self->fields[i].flags & AFSQL_FF_DEFAULT) == 0 && self->fields[i].value != NULL) { g_string_append(insert_command, self->fields[i].name); j = i + 1; while (j < self->fields_len && (self->fields[j].flags & AFSQL_FF_DEFAULT) == AFSQL_FF_DEFAULT) j++; if (j < self->fields_len) g_string_append(insert_command, ", "); } } g_string_append(insert_command, ") VALUES ("); for (i = 0; i < self->fields_len; i++) { if ((self->fields[i].flags & AFSQL_FF_DEFAULT) == 0 && self->fields[i].value != NULL) { LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, self->super.worker.instance.seq_num, NULL, LM_VT_STRING}; LogMessageValueType type; log_template_format_value_and_type(self->fields[i].value, msg, &options, value, &type); if (!afsql_dd_append_value_to_be_inserted(self, &self->fields[i], value, type, insert_command)) goto drop; j = i + 1; while (j < self->fields_len && (self->fields[j].flags & AFSQL_FF_DEFAULT) == AFSQL_FF_DEFAULT) j++; if (j < self->fields_len) g_string_append(insert_command, ", "); } } g_string_append(insert_command, ")"); g_string_free(value, TRUE); return insert_command; drop: g_string_free(value, TRUE); g_string_free(insert_command, TRUE); return NULL; } static inline gboolean afsql_dd_is_transaction_handling_enabled(const AFSqlDestDriver *self) { return !!(self->flags & AFSQL_DDF_EXPLICIT_COMMITS); } static inline gboolean afsql_dd_should_begin_new_transaction(const AFSqlDestDriver *self) { return afsql_dd_is_transaction_handling_enabled(self) && self->super.worker.instance.batch_size == 1; } static gint _batch_lines(const AFSqlDestDriver *self) { if (self->super.batch_lines <= 0) return DEFAULT_SQL_TX_SIZE; return self->super.batch_lines; } static LogThreadedResult afsql_dd_handle_insert_row_error_depending_on_connection_availability(AFSqlDestDriver *self) { const gchar *dbi_error, *error_message; if (dbi_conn_ping(self->dbi_ctx) == 1) { return LTR_ERROR; } if (afsql_dd_is_transaction_handling_enabled(self)) { error_message = "SQL connection lost in the middle of a transaction," " rewinding backlog and starting again"; } else { error_message = "Error, no SQL connection after failed query attempt"; } dbi_conn_error(self->dbi_ctx, &dbi_error); msg_error(error_message, evt_tag_str("type", self->type), evt_tag_str("host", self->host), evt_tag_str("port", self->port), evt_tag_str("username", self->user), evt_tag_str("database", self->database), evt_tag_str("error", dbi_error)); return LTR_ERROR; } static LogThreadedResult afsql_dd_flush(LogThreadedDestDriver *s) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; if (!afsql_dd_is_transaction_handling_enabled(self)) return LTR_SUCCESS; if (!afsql_dd_commit_transaction(self)) { /* Assuming that in case of error, the queue is rewound by afsql_dd_commit_transaction() */ afsql_dd_rollback_transaction(self); return LTR_ERROR; } return LTR_SUCCESS; } static LogThreadedResult afsql_dd_run_insert_query(AFSqlDestDriver *self, GString *table, LogMessage *msg) { GString *insert_command; gboolean drop_silently = self->template_options.on_error & ON_ERROR_SILENT; insert_command = afsql_dd_build_insert_command(self, msg, table); if (insert_command) { gboolean success = afsql_dd_run_query(self, insert_command->str, FALSE, NULL); g_string_free(insert_command, TRUE); if (!success) return afsql_dd_handle_insert_row_error_depending_on_connection_availability(self); return afsql_dd_is_transaction_handling_enabled(self) ? LTR_QUEUED : LTR_SUCCESS; } else { if (!drop_silently) { msg_error("Failed to format message for SQL, dropping message", evt_tag_str("type", self->type), evt_tag_str("host", self->host), evt_tag_str("port", self->port), evt_tag_str("username", self->user), evt_tag_str("database", self->database), evt_tag_str("error", "error converting name-value pair to the requested type")); } return LTR_DROP; } } /** * afsql_dd_insert_db: * * This function is running in the database thread * * Returns: FALSE to indicate that the connection should be closed and * this destination suspended for time_reopen() time. **/ static LogThreadedResult afsql_dd_insert(LogThreadedDestDriver *s, LogMessage *msg) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; GString *table = NULL; LogThreadedResult retval = LTR_ERROR; table = afsql_dd_ensure_accessible_database_table(self, msg); if (!table) goto error; if (afsql_dd_should_begin_new_transaction(self) && !afsql_dd_begin_transaction(self)) goto error; retval = afsql_dd_run_insert_query(self, table, msg); error: if (table != NULL) g_string_free(table, TRUE); return retval; } static const gchar * afsql_dd_format_stats_key(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", self->type)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", self->host)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("port", self->port)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("database", self->database)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("table", self->table->template_str)); return NULL; } static const gchar * afsql_dd_format_persist_name(const LogPipe *s) { AFSqlDestDriver *self = (AFSqlDestDriver *)s; static gchar persist_name[256]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "afsql_dd.%s", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "afsql_dd(%s,%s,%s,%s,%s)", self->type, self->host, self->port, self->database, self->table->template_str); return persist_name; } static const gchar * _afsql_dd_format_legacy_persist_name(const AFSqlDestDriver *self) { static gchar legacy_persist_name[256]; g_snprintf(legacy_persist_name, sizeof(legacy_persist_name), "afsql_dd_qfile(%s,%s,%s,%s,%s)", self->type, self->host, self->port, self->database, self->table->template_str); return legacy_persist_name; } static gboolean _update_legacy_persist_name_if_exists(AFSqlDestDriver *self) { GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super.super); const gchar *current_persist_name = afsql_dd_format_persist_name(&self->super.super.super.super); const gchar *legacy_persist_name = _afsql_dd_format_legacy_persist_name(self); if (persist_state_entry_exists(cfg->state, current_persist_name)) return TRUE; if (!persist_state_entry_exists(cfg->state, legacy_persist_name)) return TRUE; return persist_state_move_entry(cfg->state, legacy_persist_name, current_persist_name); } static gboolean _init_fields_from_columns_and_values(AFSqlDestDriver *self) { GList *col, *value; gint len_cols, len_values; gint i; if (self->fields) return TRUE; len_cols = g_list_length(self->columns); len_values = g_list_length(self->values); if (len_cols != len_values) { msg_error("The number of columns and values do not match", evt_tag_int("len_columns", len_cols), evt_tag_int("len_values", len_values)); return FALSE; } self->fields_len = len_cols; self->fields = g_new0(AFSqlField, len_cols); for (i = 0, col = self->columns, value = self->values; col && value; i++, col = col->next, value = value->next) { gchar *space; space = strchr(col->data, ' '); if (space) { self->fields[i].name = g_strndup(col->data, space - (gchar *) col->data); while (*space == ' ') space++; if (*space != '\0') self->fields[i].type = g_strdup(space); else self->fields[i].type = g_strdup("text"); } else { self->fields[i].name = g_strdup(col->data); self->fields[i].type = g_strdup("text"); } if (!_is_sql_identifier_sanitized(self->fields[i].name)) { msg_error("Column name is not a proper SQL name", evt_tag_str("column", self->fields[i].name)); return FALSE; } if (value->data == NULL) { self->fields[i].flags |= AFSQL_FF_DEFAULT; } else { log_template_unref(self->fields[i].value); self->fields[i].value = log_template_ref(value->data); } } return TRUE; } static gboolean _initialize_dbi(AFSqlDestDriver *self) { if (!dbi_initialized) { errno = 0; gint rc = dbi_initialize_r(self->dbi_driver_dir, &dbi_instance); if (rc < 0) { /* NOTE: errno might be unreliable, but that's all we have */ msg_error("Unable to initialize database access (DBI)", evt_tag_int("rc", rc), evt_tag_error("error")); return FALSE; } else if (rc == 0) { msg_error("The database access library (DBI) reports no usable SQL drivers, perhaps DBI drivers are not installed properly", evt_tag_str("dbi_driver_dir", self->dbi_driver_dir ? self->dbi_driver_dir : "")); return FALSE; } else { dbi_initialized = TRUE; } } return TRUE; } static gboolean afsql_dd_init(LogPipe *s) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!_update_legacy_persist_name_if_exists(self)) return FALSE; if (!_initialize_dbi(self)) return FALSE; if (!self->columns || !self->values) { msg_error("Default columns and values must be specified for database destinations", evt_tag_str("type", self->type)); return FALSE; } if (self->ignore_tns_config && strcmp(self->type, s_oracle) != 0) { msg_warning("WARNING: Option ignore_tns_config was skipped because database type is not Oracle", evt_tag_str("type", self->type)); } if (!_init_fields_from_columns_and_values(self)) return FALSE; if (!log_threaded_dest_driver_init_method(s)) return FALSE; log_template_options_init(&self->template_options, cfg); if (afsql_dd_is_transaction_handling_enabled(self)) log_threaded_dest_driver_set_batch_lines((LogDriver *)self, _batch_lines(self)); return TRUE; } static void afsql_dd_free(LogPipe *s) { AFSqlDestDriver *self = (AFSqlDestDriver *) s; gint i; log_template_options_destroy(&self->template_options); for (i = 0; i < self->fields_len; i++) { g_free(self->fields[i].name); g_free(self->fields[i].type); log_template_unref(self->fields[i].value); } g_free(self->fields); g_free(self->type); g_free(self->host); g_free(self->port); g_free(self->user); g_free(self->password); g_free(self->database); g_free(self->encoding); g_free(self->create_statement_append); if (self->null_value) g_free(self->null_value); string_list_free(self->columns); string_list_free(self->indexes); g_list_free_full(self->values, (GDestroyNotify)log_template_unref); log_template_unref(self->table); g_hash_table_destroy(self->syslogng_conform_tables); g_hash_table_destroy(self->dbd_options); g_hash_table_destroy(self->dbd_options_numeric); g_free(self->dbi_driver_dir); if (self->session_statements) string_list_free(self->session_statements); log_threaded_dest_driver_free(s); } LogDriver * afsql_dd_new(GlobalConfig *cfg) { AFSqlDestDriver *self = g_new0(AFSqlDestDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = afsql_dd_init; self->super.super.super.super.free_fn = afsql_dd_free; self->super.super.super.super.generate_persist_name = afsql_dd_format_persist_name; self->super.format_stats_key = afsql_dd_format_stats_key; self->super.worker.connect = afsql_dd_connect; self->super.worker.disconnect = afsql_dd_disconnect; self->super.worker.insert = afsql_dd_insert; self->super.worker.flush = afsql_dd_flush; self->type = g_strdup("mysql"); self->host = g_strdup(""); self->port = g_strdup(""); self->user = g_strdup("syslog-ng"); self->password = g_strdup(""); self->database = g_strdup("logs"); self->encoding = g_strdup("UTF-8"); self->transaction_active = FALSE; self->ignore_tns_config = FALSE; self->table = log_template_new(configuration, NULL); log_template_compile_literal_string(self->table, "messages"); self->failed_message_counter = 0; self->quote_as_string = g_strdup("");; self->session_statements = NULL; self->syslogng_conform_tables = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); self->dbd_options = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); self->dbd_options_numeric = g_hash_table_new_full(g_str_hash, g_int_equal, g_free, NULL); self->dbi_driver_dir = NULL; log_template_options_defaults(&self->template_options); self->super.stats_source = stats_register_type("sql"); return &self->super.super.super; } gint afsql_dd_lookup_flag(const gchar *flag) { if (strcmp(flag, "explicit-commits") == 0) return AFSQL_DDF_EXPLICIT_COMMITS; else if (strcmp(flag, "dont-create-tables") == 0) return AFSQL_DDF_DONT_CREATE_TABLES; else msg_warning("Unknown SQL flag", evt_tag_str("flag", flag)); return 0; } syslog-ng-syslog-ng-4.4.0/modules/afsql/afsql.h000066400000000000000000000100231450431004300214040ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSQL_H_INCLUDED #define AFSQL_H_INCLUDED #include "logthrdest/logthrdestdrv.h" #include "mainloop-worker.h" #include "string-list.h" #include /* field flags */ enum { AFSQL_FF_DEFAULT = 0x0001, }; /* destination driver flags */ enum { AFSQL_DDF_EXPLICIT_COMMITS = 0x0001, AFSQL_DDF_DONT_CREATE_TABLES = 0x0002, }; typedef struct _AFSqlField { guint32 flags; gchar *name; gchar *type; LogTemplate *value; } AFSqlField; /** * AFSqlDestDriver: * * This structure encapsulates an SQL destination driver. SQL insert * statements are generated from a separate thread because of the blocking * nature of the DBI API. It is ensured that while the thread is running, * the reference count to the driver structure is increased, thus the db * thread can read any of the fields in this structure. To do anything more * than simple reading out a value, some kind of locking mechanism shall be * used. **/ typedef struct _AFSqlDestDriver { LogThreadedDestDriver super; /* read by the db thread */ gchar *type; gchar *host; gchar *port; gchar *user; gchar *password; gchar *database; gchar *encoding; gchar *create_statement_append; GList *columns; GList *values; GList *indexes; LogTemplate *table; gint fields_len; AFSqlField *fields; gchar *null_value; gchar *quote_as_string; gint flags; gboolean ignore_tns_config; GList *session_statements; LogTemplateOptions template_options; GHashTable *dbd_options; GHashTable *dbd_options_numeric; /* used exclusively by the db thread */ dbi_conn dbi_ctx; gchar *dbi_driver_dir; GHashTable *syslogng_conform_tables; guint32 failed_message_counter; gboolean transaction_active; } AFSqlDestDriver; void afsql_dd_set_type(LogDriver *s, const gchar *type); void afsql_dd_set_host(LogDriver *s, const gchar *host); gboolean afsql_dd_check_port(const gchar *port); void afsql_dd_set_port(LogDriver *s, const gchar *port); void afsql_dd_set_user(LogDriver *s, const gchar *user); void afsql_dd_set_password(LogDriver *s, const gchar *password); void afsql_dd_set_database(LogDriver *s, const gchar *database); void afsql_dd_set_table(LogDriver *s, LogTemplate *table_template); void afsql_dd_set_columns(LogDriver *s, GList *columns); void afsql_dd_set_values(LogDriver *s, GList *values); void afsql_dd_set_null_value(LogDriver *s, const gchar *null); void afsql_dd_set_indexes(LogDriver *s, GList *indexes); void afsql_dd_set_session_statements(LogDriver *s, GList *session_statements); void afsql_dd_set_flags(LogDriver *s, gint flags); void afsql_dd_set_create_statement_append(LogDriver *s, const gchar *create_statement_append); LogDriver *afsql_dd_new(GlobalConfig *cfg); gint afsql_dd_lookup_flag(const gchar *flag); void afsql_dd_add_dbd_option(LogDriver *s, const gchar *name, const gchar *value); void afsql_dd_add_dbd_option_numeric(LogDriver *s, const gchar *name, gint value); void afsql_dd_set_dbi_driver_dir(LogDriver *s, const gchar *dbi_driver_dir); void afsql_dd_set_quote_char(LogDriver *s, const gchar *quote); void afsql_dd_set_ignore_tns_config(LogDriver *s, const gboolean ignore_tns_config); #endif syslog-ng-syslog-ng-4.4.0/modules/afstomp/000077500000000000000000000000001450431004300204745ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afstomp/CMakeLists.txt000066400000000000000000000005141450431004300232340ustar00rootroot00000000000000module_switch(ENABLE_STOMP "Enable STOMP destination") if (NOT ENABLE_STOMP) return() endif() set(AFSTOMP_SOURCES afstomp.c afstomp.h afstomp-parser.c afstomp-parser.h stomp.c stomp.h ) add_module( TARGET afstomp GRAMMAR afstomp-grammar SOURCES ${AFSTOMP_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/afstomp/Makefile.am000066400000000000000000000022401450431004300225260ustar00rootroot00000000000000if ENABLE_STOMP module_LTLIBRARIES += modules/afstomp/libafstomp.la modules_afstomp_libafstomp_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/afstomp \ -I$(top_builddir)/modules/afstomp modules_afstomp_libafstomp_la_SOURCES = \ modules/afstomp/afstomp-grammar.y \ modules/afstomp/afstomp.c \ modules/afstomp/afstomp.h \ modules/afstomp/afstomp-parser.c \ modules/afstomp/afstomp-parser.h \ modules/afstomp/stomp.c \ modules/afstomp/stomp.h modules_afstomp_libafstomp_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_afstomp_libafstomp_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afstomp_libafstomp_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) modules/afstomp modules/afstomp/ mod-afstomp mod-stomp: \ modules/afstomp/libafstomp.la else modules/afstomp modules/afstomp/ mod-afstomp mod-stomp: endif BUILT_SOURCES += \ modules/afstomp/afstomp-grammar.y \ modules/afstomp/afstomp-grammar.c \ modules/afstomp/afstomp-grammar.h EXTRA_DIST += \ modules/afstomp/afstomp-grammar.ym \ modules/afstomp/CMakeLists.txt .PHONY: modules/afstomp/ mod-afstomp mod-stomp include modules/afstomp/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/afstomp/afstomp-grammar.ym000066400000000000000000000053631450431004300241470ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2014 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #include "afstomp-parser.h" } %code { #include "cfg-parser.h" #include "cfg-grammar-internal.h" #include "plugin.h" #include "value-pairs/value-pairs.h" } %define api.prefix {afstomp_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_STOMP %token KW_STOMP_DESTINATION %token KW_PERSISTENT %token KW_ACK %token KW_BODY %token KW_PASSWORD %token KW_USERNAME %% start : LL_CONTEXT_DESTINATION KW_STOMP { last_driver = *instance = afstomp_dd_new(configuration); } '(' _inner_dest_context_push afstomp_options _inner_dest_context_pop ')' { YYACCEPT; } ; afstomp_options : afstomp_option afstomp_options | ; afstomp_option : KW_HOST '(' string ')' { afstomp_dd_set_host(last_driver, $3); free($3); } | KW_PORT '(' positive_integer ')' { afstomp_dd_set_port(last_driver, $3); } | KW_STOMP_DESTINATION '(' string ')' { afstomp_dd_set_destination(last_driver, $3); free($3); } | KW_BODY '(' template_content ')' { afstomp_dd_set_body(last_driver, $3); } | KW_PERSISTENT '(' yesno ')' { afstomp_dd_set_persistent(last_driver, $3); } | KW_ACK '(' yesno ')' { afstomp_dd_set_ack(last_driver, $3); } | KW_USERNAME '(' string ')' { afstomp_dd_set_user(last_driver, $3); free($3); } | KW_PASSWORD '(' string ')' { afstomp_dd_set_password(last_driver, $3); free($3); } | value_pair_option { afstomp_dd_set_value_pairs(last_driver, $1); } | threaded_dest_driver_general_option | { last_template_options = afstomp_dd_get_template_options(last_driver); } template_option ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afstomp/afstomp-parser.c000066400000000000000000000035351450431004300236110ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2013 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afstomp.h" #include "cfg-parser.h" #include "afstomp-grammar.h" extern int afstomp_debug; int afstomp_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afstomp_keywords[] = { { "stomp", KW_STOMP }, { "host", KW_HOST }, { "port", KW_PORT }, { "destination", KW_STOMP_DESTINATION }, { "persistent", KW_PERSISTENT }, { "ack", KW_ACK }, { "username", KW_USERNAME }, { "password", KW_PASSWORD }, { "body", KW_BODY }, { NULL } }; CfgParser afstomp_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afstomp_debug, #endif .name = "afstomp", .keywords = afstomp_keywords, .parse = (int (*)(CfgLexer *lexer, gpointer *instance, gpointer)) afstomp_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afstomp_, AFSTOMP_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afstomp/afstomp-parser.h000066400000000000000000000023161450431004300236120ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2013 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSTOMP_PARSER_H_INCLUDED #define AFSTOMP_PARSER_H_INCLUDED #include "cfg-parser.h" #include "afstomp.h" extern CfgParser afstomp_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afstomp_, AFSTOMP_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afstomp/afstomp.c000066400000000000000000000260631450431004300223200ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2014 Balabit * Copyright (c) 2013 Viktor Tusa * Copyright (c) 2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afstomp.h" #include "afstomp-parser.h" #include "plugin.h" #include "messages.h" #include "stats/stats-registry.h" #include "logmsg/nvtable.h" #include "logqueue.h" #include "scratch-buffers.h" #include "plugin-types.h" #include #include #include "logthrdest/logthrdestdrv.h" typedef struct { LogThreadedDestDriver super; gchar *destination; LogTemplate *body_template; gboolean persistent; gboolean ack_needed; gchar *host; gint port; gchar *user; gchar *password; LogTemplateOptions template_options; ValuePairs *vp; stomp_connection *conn; } STOMPDestDriver; /* * Configuration */ void afstomp_dd_set_user(LogDriver *d, const gchar *user) { STOMPDestDriver *self = (STOMPDestDriver *) d; g_free(self->user); self->user = g_strdup(user); } void afstomp_dd_set_password(LogDriver *d, const gchar *password) { STOMPDestDriver *self = (STOMPDestDriver *) d; g_free(self->password); self->password = g_strdup(password); } void afstomp_dd_set_host(LogDriver *d, const gchar *host) { STOMPDestDriver *self = (STOMPDestDriver *) d; g_free(self->host); self->host = g_strdup(host); } void afstomp_dd_set_port(LogDriver *d, gint port) { STOMPDestDriver *self = (STOMPDestDriver *) d; self->port = (int) port; } void afstomp_dd_set_destination(LogDriver *d, const gchar *destination) { STOMPDestDriver *self = (STOMPDestDriver *) d; g_free(self->destination); self->destination = g_strdup(destination); } void afstomp_dd_set_body(LogDriver *d, LogTemplate *body_template) { STOMPDestDriver *self = (STOMPDestDriver *) d; log_template_unref(self->body_template); self->body_template = body_template; } void afstomp_dd_set_persistent(LogDriver *s, gboolean persistent) { STOMPDestDriver *self = (STOMPDestDriver *) s; self->persistent = persistent; } void afstomp_dd_set_ack(LogDriver *s, gboolean ack_needed) { STOMPDestDriver *self = (STOMPDestDriver *) s; self->ack_needed = ack_needed; } void afstomp_dd_set_value_pairs(LogDriver *s, ValuePairs *vp) { STOMPDestDriver *self = (STOMPDestDriver *) s; value_pairs_unref(self->vp); self->vp = vp; } LogTemplateOptions * afstomp_dd_get_template_options(LogDriver *s) { STOMPDestDriver *self = (STOMPDestDriver *) s; return &self->template_options; } /* * Utilities */ static const gchar * afstomp_dd_format_stats_key(LogThreadedDestDriver *s, StatsClusterKeyBuilder *kb) { STOMPDestDriver *self = (STOMPDestDriver *) s; stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("driver", "afstomp")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("host", self->host)); gchar num[64]; g_snprintf(num, sizeof(num), "%u", self->port); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("port", num)); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("destination", self->destination)); return NULL; } static const gchar * afstomp_dd_format_persist_name(const LogPipe *s) { const STOMPDestDriver *self = (const STOMPDestDriver *)s; static gchar persist_name[1024]; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "afstomp.%s", s->persist_name); else g_snprintf(persist_name, sizeof(persist_name), "afstomp(%s,%u,%s)", self->host, self->port, self->destination); return persist_name; } static void afstomp_create_connect_frame(STOMPDestDriver *self, stomp_frame *frame) { stomp_frame_init(frame, "CONNECT", sizeof("CONNECT")); stomp_frame_add_header(frame, "login", self->user); stomp_frame_add_header(frame, "passcode", self->password); }; static gboolean afstomp_try_connect(STOMPDestDriver *self) { return stomp_connect(&self->conn, self->host, self->port); }; static gboolean afstomp_send_frame(STOMPDestDriver *self, stomp_frame *frame) { return stomp_write(self->conn, frame); } static gboolean afstomp_dd_connect(STOMPDestDriver *self, gboolean reconnect) { stomp_frame frame; if (reconnect && self->conn) return TRUE; if (!afstomp_try_connect(self)) return FALSE; afstomp_create_connect_frame(self, &frame); if (!afstomp_send_frame(self, &frame)) { msg_error("Sending CONNECT frame to STOMP server failed!"); return FALSE; } gboolean frame_read = stomp_receive_frame(self->conn, &frame); if (!frame_read || strcmp(frame.command, "CONNECTED") != 0) { msg_debug("Error connecting to STOMP server, stomp server did not accept CONNECT request"); stomp_frame_deinit(&frame); return FALSE; } msg_debug("Connecting to STOMP succeeded", evt_tag_str("driver", self->super.super.super.id)); stomp_frame_deinit(&frame); return TRUE; } static void afstomp_dd_disconnect(LogThreadedDestDriver *s) { STOMPDestDriver *self = (STOMPDestDriver *)s; stomp_disconnect(&self->conn); self->conn = NULL; } /* TODO escape '\0' when passing down the value */ static gboolean afstomp_vp_foreach(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { stomp_frame *frame = (stomp_frame *) (user_data); stomp_frame_add_header(frame, name, value); return FALSE; } static void afstomp_set_frame_body(STOMPDestDriver *self, GString *body, stomp_frame *frame, LogMessage *msg) { if (self->body_template) { LogTemplateEvalOptions options = {&self->template_options, LTZ_LOCAL, self->super.worker.instance.seq_num, NULL, LM_VT_STRING }; log_template_format(self->body_template, msg, &options, body); stomp_frame_set_body(frame, body->str, body->len); } } static gboolean afstomp_worker_publish(STOMPDestDriver *self, LogMessage *msg) { gboolean success = TRUE; GString *body = NULL; stomp_frame frame; stomp_frame recv_frame; if (!self->conn) { msg_error("STOMP server is not connected, not sending message!"); return FALSE; } body = scratch_buffers_alloc(); stomp_frame_init(&frame, "SEND", sizeof("SEND")); if (self->persistent) stomp_frame_add_header(&frame, "persistent", "true"); stomp_frame_add_header(&frame, "destination", self->destination); if (self->ack_needed) { /* * We check the server's response before sending a new frame to it. * Because of this, we do not need a unique receipt header. * * This changes if multiple workers and/or batching support is introduced. * Make sure to use a unique receipt-id if one of the above gets implemented. */ stomp_frame_add_header(&frame, "receipt", "0"); }; LogTemplateEvalOptions options = {&self->template_options, LTZ_SEND, self->super.worker.instance.seq_num, NULL, LM_VT_STRING}; value_pairs_foreach(self->vp, afstomp_vp_foreach, msg, &options, &frame); afstomp_set_frame_body(self, body, &frame, msg); if (!afstomp_send_frame(self, &frame)) { msg_error("Error while inserting into STOMP server"); success = FALSE; } if (success && self->ack_needed) success = stomp_receive_frame(self->conn, &recv_frame); return success; } static LogThreadedResult afstomp_worker_insert(LogThreadedDestDriver *s, LogMessage *msg) { STOMPDestDriver *self = (STOMPDestDriver *)s; if (!afstomp_dd_connect(self, TRUE)) return LTR_NOT_CONNECTED; if (!afstomp_worker_publish (self, msg)) return LTR_ERROR; return LTR_SUCCESS; } static void afstomp_worker_thread_init(LogThreadedDestDriver *s) { STOMPDestDriver *self = (STOMPDestDriver *) s; afstomp_dd_connect(self, FALSE); } static gboolean afstomp_dd_init(LogPipe *s) { STOMPDestDriver *self = (STOMPDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (!log_threaded_dest_driver_init_method(s)) return FALSE; log_template_options_init(&self->template_options, cfg); self->conn = NULL; msg_verbose("Initializing STOMP destination", evt_tag_str("host", self->host), evt_tag_int("port", self->port), evt_tag_str("destination", self->destination)); return TRUE; } static void afstomp_dd_free(LogPipe *d) { STOMPDestDriver *self = (STOMPDestDriver *) d; log_template_options_destroy(&self->template_options); g_free(self->destination); log_template_unref(self->body_template); g_free(self->user); g_free(self->password); g_free(self->host); value_pairs_unref(self->vp); log_threaded_dest_driver_free(d); } LogDriver * afstomp_dd_new(GlobalConfig *cfg) { STOMPDestDriver *self = g_new0(STOMPDestDriver, 1); log_threaded_dest_driver_init_instance(&self->super, cfg); self->super.super.super.super.init = afstomp_dd_init; self->super.super.super.super.free_fn = afstomp_dd_free; self->super.super.super.super.generate_persist_name = afstomp_dd_format_persist_name; self->super.worker.thread_init = afstomp_worker_thread_init; self->super.worker.disconnect = afstomp_dd_disconnect; self->super.worker.insert = afstomp_worker_insert; self->super.format_stats_key = afstomp_dd_format_stats_key; self->super.stats_source = stats_register_type("stomp"); afstomp_dd_set_host((LogDriver *) self, "127.0.0.1"); afstomp_dd_set_port((LogDriver *) self, 61613); afstomp_dd_set_destination((LogDriver *) self, "/topic/syslog"); afstomp_dd_set_persistent((LogDriver *) self, TRUE); afstomp_dd_set_ack((LogDriver *) self, FALSE); log_template_options_defaults(&self->template_options); afstomp_dd_set_value_pairs(&self->super.super.super, value_pairs_new_default(cfg)); return (LogDriver *) self; } extern CfgParser afstomp_dd_parser; static Plugin afstomp_plugin = { .type = LL_CONTEXT_DESTINATION, .name = "stomp", .parser = &afstomp_parser }; gboolean afstomp_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, &afstomp_plugin, 1); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afstomp", .version = SYSLOG_NG_VERSION, .description = "The afstomp module provides STOMP destination support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = &afstomp_plugin, .plugins_len = 1, }; syslog-ng-syslog-ng-4.4.0/modules/afstomp/afstomp.h000066400000000000000000000034131450431004300223170ustar00rootroot00000000000000/* * Copyright (c) 2012 Nagy, Attila * Copyright (c) 2014 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSTOMP_H_INCLUDED #define AFSTOMP_H_INCLUDED #include "driver.h" #include "value-pairs/value-pairs.h" LogDriver *afstomp_dd_new(GlobalConfig *cfg); void afstomp_dd_set_host(LogDriver *d, const gchar *host); void afstomp_dd_set_port(LogDriver *d, gint port); void afstomp_dd_set_destination(LogDriver *d, const gchar *destination); void afstomp_dd_set_body(LogDriver *d, LogTemplate *body_template); void afstomp_dd_set_persistent(LogDriver *d, gboolean persistent); void afstomp_dd_set_ack(LogDriver *d, gboolean ack); void afstomp_dd_set_user(LogDriver *d, const gchar *user); void afstomp_dd_set_password(LogDriver *d, const gchar *password); void afstomp_dd_set_value_pairs(LogDriver *d, ValuePairs *vp); LogTemplateOptions *afstomp_dd_get_template_options(LogDriver *s); #endif syslog-ng-syslog-ng-4.4.0/modules/afstomp/stomp.c000066400000000000000000000203721450431004300220060ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "stomp.h" #include "host-resolve.h" #include "str-utils.h" #include "messages.h" #include #include #include #include #include #include #define STOMP_PARSE_HEADER 1 #define STOMP_PARSE_DATA 2 #define STOMP_PARSE_ERROR 0 void stomp_frame_init(stomp_frame *frame, const char *command, int command_len) { frame->command = g_strndup(command, command_len); frame->headers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); frame->body_length = -1; frame->body = NULL; }; void stomp_frame_add_header(stomp_frame *frame, const char *name, const char *value) { msg_debug("Adding header", evt_tag_str("name", name), evt_tag_str("value", value)); g_hash_table_insert(frame->headers, g_strdup(name), g_strdup(value)); }; void stomp_frame_add_header_len(stomp_frame *frame, const char *name, int name_len, const char *value, int value_len) { char *name_slice = g_strndup(name, name_len); char *value_slice = g_strndup(value, value_len); msg_debug("Adding header", evt_tag_str("name", name_slice), evt_tag_str("value", value_slice)); g_hash_table_insert(frame->headers, name_slice, value_slice); }; void stomp_frame_set_body(stomp_frame *frame, const char *body, int body_len) { frame->body = g_strndup(body, body_len); frame->body_length = body_len; }; int stomp_frame_deinit(stomp_frame *frame) { g_hash_table_destroy(frame->headers); g_free(frame->command); g_free(frame->body); return TRUE; } static void _stomp_connection_free(stomp_connection *conn) { g_sockaddr_unref(conn->remote_sa); g_free(conn); } int stomp_connect(stomp_connection **connection_ref, char *hostname, int port) { stomp_connection *conn; conn = g_new0(stomp_connection, 1); conn->socket = socket(AF_INET, SOCK_STREAM, 0); if (conn->socket == -1) { msg_error("Failed to create socket!"); g_free(conn); return FALSE; } if (!resolve_hostname_to_sockaddr(&conn->remote_sa, AF_INET, hostname)) { msg_error("Failed to resolve hostname in stomp driver", evt_tag_str("hostname", hostname)); _stomp_connection_free(conn); return FALSE; } g_sockaddr_set_port(conn->remote_sa, port); if (!g_connect(conn->socket, conn->remote_sa)) { msg_error("Stomp connection failed", evt_tag_str("host", hostname)); _stomp_connection_free(conn); return FALSE; } (*connection_ref) = conn; return TRUE; }; int stomp_disconnect(stomp_connection **connection_ref) { stomp_connection *conn = *connection_ref; if (!conn) return TRUE; shutdown(conn->socket, SHUT_RDWR); close(conn->socket); _stomp_connection_free(conn); *connection_ref = NULL; return TRUE; }; static void write_header_into_gstring(gpointer key, gpointer value, gpointer userdata) { GString *str = (GString *) userdata; if (key == NULL || value == NULL) return; g_string_append(str, key); g_string_append_c(str, ':'); g_string_append(str, value); g_string_append_c(str, '\n'); } static int write_gstring_to_socket(int fd, GString *data) { int res = 0; int remaining = data->len; while ((remaining > 0) && (res >= 0)) { res = write(fd, data->str + (data->len - remaining), remaining); if (res > 0) remaining = remaining - res; } if (res < 0) { msg_error("Error happened during write", evt_tag_error("errno")); return FALSE; } return TRUE; } static int stomp_read_data(stomp_connection *connection, GString *buffer) { char tmp_buf[4096]; int res; res = read(connection->socket, tmp_buf, sizeof(tmp_buf)); if (res < 0) return FALSE; g_string_assign_len(buffer, tmp_buf, res); while (res == sizeof(tmp_buf)) { res = read(connection->socket, tmp_buf, sizeof(tmp_buf)); g_string_append_len(buffer, tmp_buf, res); } return TRUE; } static int stomp_parse_command(char *buffer, int buflen, stomp_frame *frame, char **out_pos) { char *pos; pos = g_strstr_len(buffer, buflen, "\n"); if (pos == NULL) return STOMP_PARSE_ERROR; stomp_frame_init(frame, buffer, pos - buffer); *out_pos = pos + 1; return STOMP_PARSE_HEADER; } static int stomp_parse_header(char *buffer, int buflen, stomp_frame *frame, char **out_pos) { char *pos, *colon; if (buflen <= 1) { *out_pos = buffer; return STOMP_PARSE_DATA; } pos = g_strstr_len(buffer, buflen, "\n"); if (!pos) return STOMP_PARSE_ERROR; if (pos == buffer) { *out_pos = pos + 1; return STOMP_PARSE_DATA; } colon = g_strstr_len(buffer, pos - buffer, ":"); if (!colon) return STOMP_PARSE_ERROR; stomp_frame_add_header_len(frame, buffer, colon - buffer, colon + 1, pos - colon - 1); *out_pos = pos + 1; return STOMP_PARSE_HEADER; }; int stomp_parse_frame(GString *data, stomp_frame *frame) { char *pos; int res; res = stomp_parse_command(data->str, data->len, frame, &pos); if (!res) return FALSE; res = stomp_parse_header(pos, data->str + data->len - pos, frame, &pos); while (res == STOMP_PARSE_HEADER) { res = stomp_parse_header(pos, data->str + data->len - pos, frame, &pos); } if (res == STOMP_PARSE_ERROR) return FALSE; frame->body = g_strndup(pos, data->len - (pos - data->str)); return TRUE; } int stomp_receive_frame(stomp_connection *connection, stomp_frame *frame) { GString *data = g_string_sized_new(4096); if (!stomp_read_data(connection, data)) { g_string_free(data, TRUE); return FALSE; } int res = stomp_parse_frame(data, frame); if (res) msg_debug("Frame received", evt_tag_str("command", frame->command)); g_string_free(data, TRUE); return res; } static int stomp_check_for_frame(stomp_connection *connection) { struct pollfd pfd; pfd.fd = connection->socket; pfd.events = POLLIN | POLLPRI; poll(&pfd, 1, 0); if (pfd.revents & ( POLLIN | POLLPRI)) { stomp_frame frame; if (!stomp_receive_frame(connection, &frame)) return FALSE; if (!strcmp(frame.command, "ERROR")) { msg_error("ERROR frame received from stomp_server"); stomp_frame_deinit(&frame); return FALSE; } /* According to stomp protocol, here only ERROR or RECEIPT frames can come, so we missed a RECEIPT frame here, our bad. */ stomp_frame_deinit(&frame); return TRUE; } return TRUE; } GString * create_gstring_from_frame(stomp_frame *frame) { GString *data = g_string_new(""); g_string_append(data, frame->command); g_string_append_c(data, '\n'); g_hash_table_foreach(frame->headers, write_header_into_gstring, data); g_string_append_c(data, '\n'); if (frame->body) g_string_append_len(data, frame->body, frame->body_length); g_string_append_c(data, 0); return data; } int stomp_write(stomp_connection *connection, stomp_frame *frame) { GString *data; if (!stomp_check_for_frame(connection)) return FALSE; data = create_gstring_from_frame(frame); if (!write_gstring_to_socket(connection->socket, data)) { msg_error("Write error, partial write"); stomp_frame_deinit(frame); g_string_free(data, TRUE); return FALSE; } g_string_free(data, TRUE); stomp_frame_deinit(frame); return TRUE; } syslog-ng-syslog-ng-4.4.0/modules/afstomp/stomp.h000066400000000000000000000040021450431004300220030ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef STOMP_H #define STOMP_H #include "gsocket.h" #include typedef struct stomp_connection { int socket; GSockAddr *remote_sa; char *remote_ip; } stomp_connection; typedef struct stomp_frame { char *command; GHashTable *headers; char *body; int body_length; } stomp_frame; void stomp_frame_init(stomp_frame *frame, const char *command, int command_len); void stomp_frame_add_header(stomp_frame *frame, const char *name, const char *value); void stomp_frame_set_body(stomp_frame *frame, const char *body, int body_len); int stomp_frame_deinit(stomp_frame *frame); int stomp_connect(stomp_connection **connection_ref, char *hostname, int port); int stomp_disconnect(stomp_connection **connection_ref); int stomp_write(stomp_connection *connection, stomp_frame *frame); int stomp_read(stomp_connection *connection, stomp_frame **frame); int stomp_parse_frame(GString *data, stomp_frame *frame); int stomp_receive_frame(stomp_connection *connection, stomp_frame *frame); GString *create_gstring_from_frame(stomp_frame *frame); #endif syslog-ng-syslog-ng-4.4.0/modules/afstomp/tests/000077500000000000000000000000001450431004300216365ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afstomp/tests/CMakeLists.txt000066400000000000000000000001531450431004300243750ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_stomp_proto DEPENDS afstomp INCLUDES "${AFSTOMP_INCLUDE_DIR}") syslog-ng-syslog-ng-4.4.0/modules/afstomp/tests/Makefile.am000066400000000000000000000010061450431004300236670ustar00rootroot00000000000000EXTRA_DIST += modules/afstomp/tests/CMakeLists.txt if ENABLE_STOMP modules_afstomp_tests_test_stomp_proto_CFLAGS = \ $(TEST_CFLAGS) \ -I$(top_srcdir)/modules/afstomp modules_afstomp_tests_test_stomp_proto_LDADD = \ $(TEST_LDADD) $(MODULE_DEPS_LIBS) modules_afstomp_tests_test_stomp_proto_LDFLAGS = \ -dlpreopen $(top_builddir)/modules/afstomp/libafstomp.la modules_afstomp_tests_TESTS = \ modules/afstomp/tests/test_stomp_proto check_PROGRAMS += \ $(modules_afstomp_tests_TESTS) endif syslog-ng-syslog-ng-4.4.0/modules/afstomp/tests/test_stomp_proto.c000066400000000000000000000063121450431004300254300ustar00rootroot00000000000000/* * Copyright (c) 2013 Balabit * Copyright (c) 2013 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "stomp.h" static void assert_stomp_header(stomp_frame *frame, char *key, char *value) { char *myvalue = g_hash_table_lookup(frame->headers, key); cr_assert_str_eq(myvalue, value, "Stomp header assertion failed!"); } static void assert_stomp_command(stomp_frame *frame, char *command) { cr_assert_str_eq(frame->command, command, "Stomp command assertion failed"); } static void assert_stomp_body(stomp_frame *frame, char *body) { cr_assert_str_eq(frame->body, body, "Stomp body assertion failed"); } Test(stomp_proto, test_only_command) { stomp_frame frame; stomp_parse_frame(g_string_new("CONNECTED\n\n"), &frame); assert_stomp_command(&frame, "CONNECTED"); stomp_frame_deinit(&frame); } Test(stomp_proto, test_command_and_data) { stomp_frame frame; stomp_parse_frame(g_string_new("CONNECTED\n\nalmafa"), &frame); assert_stomp_command(&frame, "CONNECTED"); assert_stomp_body(&frame, "almafa"); stomp_frame_deinit(&frame); }; Test(stomp_proto, test_command_and_header_and_data) { stomp_frame frame; stomp_parse_frame(g_string_new("CONNECTED\nheader_name:header_value\n\nbelafa"), &frame); assert_stomp_command(&frame, "CONNECTED"); assert_stomp_header(&frame, "header_name", "header_value"); assert_stomp_body(&frame, "belafa"); stomp_frame_deinit(&frame); }; Test(stomp_proto, test_command_and_header) { stomp_frame frame; stomp_parse_frame(g_string_new("CONNECTED\nsession:ID:tusa-38077-1378214843533-2:1\n"), &frame); assert_stomp_command(&frame, "CONNECTED"); assert_stomp_header(&frame, "session", "ID:tusa-38077-1378214843533-2:1"); stomp_frame_deinit(&frame); }; Test(stomp_proto, test_generate_gstring_from_frame) { stomp_frame frame; GString *actual; stomp_frame_init(&frame, "SEND", sizeof("SEND")); stomp_frame_add_header(&frame, "header_name", "header_value"); stomp_frame_set_body(&frame, "body", sizeof("body")); actual = create_gstring_from_frame(&frame); cr_assert_str_eq(actual->str, "SEND\nheader_name:header_value\n\nbody", "Generated stomp frame does not match"); stomp_frame_deinit(&frame); }; Test(stomp_proto, test_invalid_command) { stomp_frame frame; cr_assert_not(stomp_parse_frame(g_string_new("CONNECTED\n no-colon\n"), &frame)); stomp_frame_deinit(&frame); }; syslog-ng-syslog-ng-4.4.0/modules/afstreams/000077500000000000000000000000001450431004300210105ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afstreams/CMakeLists.txt000066400000000000000000000007171450431004300235550ustar00rootroot00000000000000set(AFSTREAMS_SOURCES afstreams.c afstreams.h afstreams-parser.c afstreams-parser.h afstreams-plugin.c ) include (CheckIncludeFile) check_include_file(sys/strlog.h HAVE_STRLOG) check_include_file(stropts.h HAVE_STROPTS) module_switch(ENABLE_SUN_STREAMS "Enable Sun Streams source" HAVE_STRLOG HAVE_STROPTS) if (ENABLE_SUN_STREAMS) add_module( TARGET afstreams GRAMMAR afstreams-grammar SOURCES ${AFSTREAMS_SOURCES} ) endif() syslog-ng-syslog-ng-4.4.0/modules/afstreams/Makefile.am000066400000000000000000000022331450431004300230440ustar00rootroot00000000000000if ENABLE_SUN_STREAMS module_LTLIBRARIES += modules/afstreams/libafstreams.la modules_afstreams_libafstreams_la_SOURCES = \ modules/afstreams/afstreams.c \ modules/afstreams/afstreams.h \ modules/afstreams/afstreams-grammar.y \ modules/afstreams/afstreams-parser.c \ modules/afstreams/afstreams-parser.h \ modules/afstreams/afstreams-plugin.c modules_afstreams_libafstreams_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/afstreams \ -I$(top_builddir)/modules/afstreams modules_afstreams_libafstreams_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_afstreams_libafstreams_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afstreams_libafstreams_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) modules/afstreams modules/afstreams/ mod-afstreams mod-streams: \ modules/afstreams/libafstreams.la else modules/afstreams modules/afstreams/ mod-afstreams mod-streams: endif BUILT_SOURCES += \ modules/afstreams/afstreams-grammar.y \ modules/afstreams/afstreams-grammar.c \ modules/afstreams/afstreams-grammar.h EXTRA_DIST += \ modules/afstreams/afstreams-grammar.ym \ modules/afstreams/CMakeLists.txt .PHONY: modules/afstreams/ mod-afstreams mod-streams syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams-grammar.ym000066400000000000000000000041561450431004300247760ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "afstreams-parser.h" } %code { #include "afstreams.h" #include "cfg-parser.h" #include "messages.h" extern LogDriver *last_driver; } %define api.prefix {afstreams_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_DOOR %token KW_SUN_STREAMS %type source_afstreams %type source_afstreams_params %% start : LL_CONTEXT_SOURCE source_afstreams { YYACCEPT; } ; source_afstreams : KW_SUN_STREAMS '(' _inner_src_context_push source_afstreams_params _inner_src_context_pop ')' { $$ = $4; } ; source_afstreams_params : string { last_driver = *instance = afstreams_sd_new($1, configuration); } source_afstreams_options { $$ = last_driver; free($1); } ; source_afstreams_options : source_afstreams_option source_afstreams_options | ; source_afstreams_option : KW_DOOR '(' string ')' { afstreams_sd_set_sundoor(last_driver, $3); free($3); } | source_driver_option ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams-parser.c000066400000000000000000000032231450431004300244330ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afstreams.h" #include "cfg-parser.h" #include "afstreams-grammar.h" extern int afstreams_debug; int afstreams_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afstreams_keywords[] = { { "sun_stream", KW_SUN_STREAMS }, { "sun_streams", KW_SUN_STREAMS }, { "door", KW_DOOR }, { NULL } }; CfgParser afstreams_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afstreams_debug, #endif .name = "afstreams", .keywords = afstreams_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) afstreams_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afstreams_, AFSTREAMS_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams-parser.h000066400000000000000000000022431450431004300244410ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSOCKET_PARSER_H_INCLUDED #define AFSOCKET_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser afstreams_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afstreams_, AFSTREAMS_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams-plugin.c000066400000000000000000000032531450431004300244400ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afstreams_parser; static Plugin afstreams_plugins[] = { { .type = LL_CONTEXT_SOURCE, .name = "sun-streams", .parser = &afstreams_parser, }, }; gboolean afstreams_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afstreams_plugins, G_N_ELEMENTS(afstreams_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afstreams", .version = SYSLOG_NG_VERSION, .description = "The afstreams module provides Solaris STREAMS logging device support for syslog-ng", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afstreams_plugins, .plugins_len = G_N_ELEMENTS(afstreams_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams.c000066400000000000000000000204241450431004300231430ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afstreams.h" #include "messages.h" #include "logreader.h" #include "fdhelpers.h" #include "apphook.h" #include "stats/stats-registry.h" #include "poll-fd-events.h" #include "logproto/logproto-dgram-server.h" #include "stats/stats-cluster-key-builder.h" typedef struct _AFStreamsSourceDriver { LogSrcDriver super; GString *dev_filename; GString *door_filename; gint door_fd; LogReader *reader; LogReaderOptions reader_options; } AFStreamsSourceDriver; #include #include #include #include #include #include #include #if SYSLOG_NG_HAVE_DOOR_H #include #endif static gssize log_transport_streams_read(LogTransport *self, void *buf, gsize buflen, GSockAddr **sa) { struct strbuf ctl, data; struct log_ctl lc; gint flags; gint res; gchar tmpbuf[buflen]; gint len; ctl.maxlen = ctl.len = sizeof(lc); ctl.buf = (char *) &lc; data.maxlen = buflen; data.len = 0; data.buf = tmpbuf; flags = 0; res = getmsg(self->fd, &ctl, &data, &flags); if (res == -1) return -1; else if ((res & (MORECTL+MOREDATA)) == 0) { len = g_snprintf(buf, buflen, "<%d>%.*s", lc.pri, data.len, data.buf); return MIN(len, buflen); } else { msg_error("Insufficient buffer space for retrieving STREAMS log message", evt_tag_printf("res", "%x", res)); } return 0; } LogTransport * log_transport_streams_new(gint fd) { LogTransport *self = g_new0(LogTransport, 1); log_transport_init_instance(self, fd); self->cond = G_IO_IN; self->read = log_transport_streams_read; self->free_fn = log_transport_free_method; return self; } void afstreams_sd_set_sundoor(LogDriver *s, gchar *filename) { AFStreamsSourceDriver *self = (AFStreamsSourceDriver *) s; self->door_filename = g_string_new(filename); } static void afstreams_sd_door_server_proc(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, uint_t n_desc) { door_return(NULL, 0, NULL, 0); return; } static void afstreams_init_door(int hook_type G_GNUC_UNUSED, gpointer user_data) { AFStreamsSourceDriver *self = (AFStreamsSourceDriver *) user_data; struct stat st; gint fd; if (stat(self->door_filename->str, &st) == -1) { /* file does not exist, create it */ fd = creat(self->door_filename->str, 0666); if (fd == -1) { msg_error("Error creating syslog door file", evt_tag_str(EVT_TAG_FILENAME, self->door_filename->str), evt_tag_error(EVT_TAG_OSERROR)); close(fd); return; } } fdetach(self->door_filename->str); self->door_fd = door_create(afstreams_sd_door_server_proc, NULL, 0); if (self->door_fd == -1) { msg_error("Error creating syslog door", evt_tag_str(EVT_TAG_FILENAME, self->door_filename->str), evt_tag_error(EVT_TAG_OSERROR)); return; } g_fd_set_cloexec(self->door_fd, TRUE); if (fattach(self->door_fd, self->door_filename->str) == -1) { msg_error("Error attaching syslog door", evt_tag_str(EVT_TAG_FILENAME, self->door_filename->str), evt_tag_error(EVT_TAG_OSERROR)); close(self->door_fd); self->door_fd = -1; return; } } static gboolean afstreams_sd_init(LogPipe *s) { AFStreamsSourceDriver *self = (AFStreamsSourceDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); gint fd; if (!log_src_driver_init_method(s)) return FALSE; log_reader_options_init(&self->reader_options, cfg, self->super.super.group); fd = open(self->dev_filename->str, O_RDONLY | O_NOCTTY | O_NONBLOCK); if (fd != -1) { struct strioctl ioc; g_fd_set_cloexec(fd, TRUE); memset(&ioc, 0, sizeof(ioc)); ioc.ic_cmd = I_CONSLOG; if (ioctl(fd, I_STR, &ioc) < 0) { msg_error("Error in ioctl(I_STR, I_CONSLOG)", evt_tag_str(EVT_TAG_FILENAME, self->dev_filename->str), evt_tag_error(EVT_TAG_OSERROR)); close(fd); return FALSE; } g_fd_set_nonblock(fd, TRUE); self->reader = log_reader_new(cfg); log_pipe_set_options(&self->reader->super.super, &self->super.super.super.options); log_reader_open(self->reader, log_proto_dgram_server_new(log_transport_streams_new(fd), &self->reader_options.proto_options.super), poll_fd_events_new(fd)); StatsClusterKeyBuilder *kb = stats_cluster_key_builder_new(); stats_cluster_key_builder_add_label(kb, stats_cluster_label("driver", "sun-streams")); stats_cluster_key_builder_add_legacy_label(kb, stats_cluster_label("filename", self->dev_filename->str)); log_reader_set_options(self->reader, s, &self->reader_options, self->super.super.id, kb); log_pipe_append((LogPipe *) self->reader, s); if (self->door_filename) { /* door creation is deferred, because it creates threads which is * not inherited through forks, and syslog-ng forks during * startup, but _after_ the configuration was initialized */ register_application_hook(AH_POST_DAEMONIZED, afstreams_init_door, self, AHM_RUN_ONCE); } if (!log_pipe_init((LogPipe *) self->reader)) { msg_error("Error initializing log_reader, closing fd", evt_tag_int("fd", fd)); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; close(fd); return FALSE; } } else { msg_error("Error opening syslog device", evt_tag_str(EVT_TAG_FILENAME, self->dev_filename->str), evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } return TRUE; } static gboolean afstreams_sd_deinit(LogPipe *s) { AFStreamsSourceDriver *self = (AFStreamsSourceDriver *) s; if (self->reader) { log_pipe_deinit((LogPipe *) self->reader); log_pipe_unref((LogPipe *) self->reader); self->reader = NULL; } if (self->door_fd != -1) { door_revoke(self->door_fd); close(self->door_fd); } if (!log_src_driver_deinit_method(s)) return FALSE; return TRUE; } static void afstreams_sd_free(LogPipe *s) { AFStreamsSourceDriver *self = (AFStreamsSourceDriver *) s; log_reader_options_destroy(&self->reader_options); if (self->dev_filename) g_string_free(self->dev_filename, TRUE); if (self->door_filename) g_string_free(self->door_filename, TRUE); log_src_driver_free(s); } LogDriver * afstreams_sd_new(gchar *filename, GlobalConfig *cfg) { AFStreamsSourceDriver *self = g_new0(AFStreamsSourceDriver, 1); log_src_driver_init_instance(&self->super, cfg); self->dev_filename = g_string_new(filename); self->super.super.super.init = afstreams_sd_init; self->super.super.super.deinit = afstreams_sd_deinit; self->super.super.super.free_fn = afstreams_sd_free; log_reader_options_defaults(&self->reader_options); self->reader_options.parse_options.flags |= LP_LOCAL; self->reader_options.parse_options.flags &= ~LP_EXPECT_HOSTNAME; self->reader_options.super.stats_level = STATS_LEVEL1; self->reader_options.super.stats_source = stats_register_type("sun-streams"); return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/afstreams/afstreams.h000066400000000000000000000022261450431004300231500ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFSTREAMS_H_INCLUDED #define AFSTREAMS_H_INCLUDED #include "driver.h" LogDriver *afstreams_sd_new(gchar *filename, GlobalConfig *cfg); void afstreams_sd_set_sundoor(LogDriver *self, gchar *filename); #endif syslog-ng-syslog-ng-4.4.0/modules/afuser/000077500000000000000000000000001450431004300203105ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/afuser/CMakeLists.txt000066400000000000000000000004401450431004300230460ustar00rootroot00000000000000module_switch(ENABLE_AFUSER "Enable afuser module") if (NOT ENABLE_AFUSER) return() endif() set(AFUSER_SOURCES "afuser-parser.h" "afuser.h" "afuser-plugin.c" "afuser.c" "afuser-parser.c" ) add_module( TARGET afuser GRAMMAR afuser-grammar SOURCES ${AFUSER_SOURCES} ) syslog-ng-syslog-ng-4.4.0/modules/afuser/Makefile.am000066400000000000000000000016701450431004300223500ustar00rootroot00000000000000module_LTLIBRARIES += modules/afuser/libafuser.la modules_afuser_libafuser_la_SOURCES = \ modules/afuser/afuser.c \ modules/afuser/afuser.h \ modules/afuser/afuser-grammar.y \ modules/afuser/afuser-parser.c \ modules/afuser/afuser-parser.h \ modules/afuser/afuser-plugin.c modules_afuser_libafuser_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/afuser \ -I$(top_builddir)/modules/afuser modules_afuser_libafuser_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_afuser_libafuser_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_afuser_libafuser_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) BUILT_SOURCES += \ modules/afuser/afuser-grammar.y \ modules/afuser/afuser-grammar.c \ modules/afuser/afuser-grammar.h EXTRA_DIST += \ modules/afuser/afuser-grammar.ym \ modules/afuser/CMakeLists.txt modules/afuser modules/afuser/ mod-afuser mod-usertty: \ modules/afuser/libafuser.la .PHONY: modules/afuser/ mod-afuser mod-usertty syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser-grammar.ym000066400000000000000000000036251450431004300235760ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #pragma GCC diagnostic ignored "-Wswitch-default" #include "afuser-parser.h" } %code { #include "afuser.h" #include "cfg-parser.h" #include "syslog-names.h" #include "messages.h" extern LogDriver *last_driver; } %define api.prefix {afuser_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriver **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %type dest_afuser %token KW_USERTTY %% start : LL_CONTEXT_DESTINATION dest_afuser { last_driver = *instance = $2; YYACCEPT; } ; dest_afuser : KW_USERTTY '(' string { last_driver = afuser_dd_new($3, configuration); } afuser_opts ')' { $$ = last_driver; free($3); } ; afuser_opts : afuser_opt afuser_opts | ; afuser_opt : KW_TIME_REOPEN '(' positive_integer ')' { afuser_dd_set_time_reopen(last_driver, $3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser-parser.c000066400000000000000000000030361450431004300232350ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afuser.h" #include "cfg-parser.h" #include "afuser-grammar.h" extern int afuser_debug; int afuser_parse(CfgLexer *lexer, LogDriver **instance, gpointer arg); static CfgLexerKeyword afuser_keywords[] = { { "usertty", KW_USERTTY }, { NULL } }; CfgParser afuser_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &afuser_debug, #endif .name = "afuser", .keywords = afuser_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) afuser_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(afuser_, AFUSER_, LogDriver **) syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser-parser.h000066400000000000000000000022261450431004300232420ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFUSER_PARSER_H_INCLUDED #define AFUSER_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser afuser_parser; CFG_PARSER_DECLARE_LEXER_BINDING(afuser_, AFUSER_, LogDriver **) #endif syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser-plugin.c000066400000000000000000000032011450431004300232310ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser afuser_parser; static Plugin afuser_plugins[] = { { .type = LL_CONTEXT_DESTINATION, .name = "usertty", .parser = &afuser_parser, }, }; gboolean afuser_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, afuser_plugins, G_N_ELEMENTS(afuser_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "afuser", .version = SYSLOG_NG_VERSION, .description = "The afuser module provides the usertty() destination for syslog-ng", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = afuser_plugins, .plugins_len = G_N_ELEMENTS(afuser_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser.c000066400000000000000000000135451450431004300217510ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "afuser.h" #include "messages.h" #include "compat/getutent.h" #include "timeutils/format.h" #include #include #include #include typedef struct _AFUserDestDriver { LogDestDriver super; GString *username; time_t disable_until; time_t time_reopen; } AFUserDestDriver; #ifdef SYSLOG_NG_HAVE_UTMPX_H typedef struct utmpx UtmpEntry; static UtmpEntry * _fetch_utmp_entry(void) { return getutxent(); } static void _close_utmp(void) { endutxent(); } #else typedef struct utmp UtmpEntry; static UtmpEntry * _fetch_utmp_entry(void) { return getutent(); } static void _close_utmp(void) { endutent(); } #endif static gboolean _utmp_entry_matches(UtmpEntry *ut, GString *username) { #ifdef SYSLOG_NG_HAVE_MODERN_UTMP if (ut->ut_type != USER_PROCESS) return FALSE; #endif if (strcmp(username->str, "*") == 0) return TRUE; /* ut_user/ut_name may not be null-terminated */ #ifdef SYSLOG_NG_HAVE_MODERN_UTMP if (strncmp(username->str, ut->ut_user, G_N_ELEMENTS(ut->ut_user)) == 0) #else if (strncmp(username->str, ut->ut_name, G_N_ELEMENTS(ut->ut_name)) == 0) #endif return TRUE; return FALSE; } G_LOCK_DEFINE_STATIC(utmp_lock); void afuser_dd_set_time_reopen(LogDriver *s, time_t time_reopen) { AFUserDestDriver *self = (AFUserDestDriver *) s; self->time_reopen = time_reopen; } static EVTTAG * _evt_tag_utmp_username(UtmpEntry *ut) { /* ut_user/ut_name may not be null-terminated */ #ifdef SYSLOG_NG_HAVE_MODERN_UTMP return evt_tag_mem("user", ut->ut_user, G_N_ELEMENTS(ut->ut_user)); #else return evt_tag_mem("user", ut->ut_name, G_N_ELEMENTS(ut->ut_name)); #endif } static void afuser_dd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { AFUserDestDriver *self = (AFUserDestDriver *) s; gchar buf[8192]; GString *timestamp; UtmpEntry *ut; time_t now; now = msg->timestamps[LM_TS_RECVD].ut_sec; if (self->disable_until && self->disable_until > now) goto finish; timestamp = g_string_sized_new(0); format_unix_time(&msg->timestamps[LM_TS_STAMP], timestamp, TS_FMT_FULL, -1, 0); g_snprintf(buf, sizeof(buf), "%s %s %s\n", timestamp->str, log_msg_get_value(msg, LM_V_HOST, NULL), log_msg_get_value(msg, LM_V_MESSAGE, NULL)); g_string_free(timestamp, TRUE); G_LOCK(utmp_lock); while ((ut = _fetch_utmp_entry())) { if (_utmp_entry_matches(ut, self->username)) { gchar line[5 + G_N_ELEMENTS(ut->ut_line) + 1]; /* /dev/ prefix, line device name, null terminator */ gchar *p = line; int fd; if (ut->ut_line[0] != '/') { strcpy(line, "/dev/"); p = line + 5; } /* ut_line may not be null-terminated. Copy it and ensure it's null-terminated. */ strncpy(p, ut->ut_line, G_N_ELEMENTS(ut->ut_line)); p[G_N_ELEMENTS(ut->ut_line)] = 0; msg_debug("Posting message to user terminal", _evt_tag_utmp_username(ut), evt_tag_str("line", line)); fd = open(line, O_NOCTTY | O_APPEND | O_WRONLY | O_NONBLOCK); if (fd == -1) { msg_error("Opening tty device failed, disabling usertty() for time-reopen seconds", _evt_tag_utmp_username(ut), evt_tag_str("line", line), evt_tag_int("time_reopen", self->time_reopen), evt_tag_error("errno")); self->disable_until = now + self->time_reopen; continue; } if (write(fd, buf, strlen(buf)) < 0 && errno == EAGAIN) { msg_notice("Writing to the user terminal has blocked for writing, disabling for time-reopen seconds", evt_tag_str("user", self->username->str), evt_tag_int("time_reopen", self->time_reopen)); self->disable_until = now + self->time_reopen; } close(fd); } } _close_utmp(); G_UNLOCK(utmp_lock); finish: log_dest_driver_queue_method(s, msg, path_options); } void afuser_dd_free(LogPipe *s) { AFUserDestDriver *self = (AFUserDestDriver *) s; g_string_free(self->username, TRUE); log_dest_driver_free(s); } static gboolean afuser_dd_init(LogPipe *s) { AFUserDestDriver *self = (AFUserDestDriver *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (self->time_reopen == -1) self->time_reopen = cfg->time_reopen; return log_dest_driver_init_method(s); } LogDriver * afuser_dd_new(gchar *user, GlobalConfig *cfg) { AFUserDestDriver *self = g_new0(AFUserDestDriver, 1); log_dest_driver_init_instance(&self->super, cfg); self->super.super.super.init = afuser_dd_init; self->super.super.super.queue = afuser_dd_queue; self->super.super.super.free_fn = afuser_dd_free; self->username = g_string_new(user); self->time_reopen = -1; return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/afuser/afuser.h000066400000000000000000000022121450431004300217430ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AFUSER_H_INCLUDED #define AFUSER_H_INCLUDED #include "driver.h" LogDriver *afuser_dd_new(gchar *user, GlobalConfig *cfg); void afuser_dd_set_time_reopen(LogDriver *s, time_t time_reopen); #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/000077500000000000000000000000001450431004300206245ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/appmodel/CMakeLists.txt000066400000000000000000000005571450431004300233730ustar00rootroot00000000000000module_switch(ENABLE_APPMODEL "Enable AppModel") if (NOT ENABLE_APPMODEL) return() endif() set (APPMODEL_SOURCES appmodel.c appmodel-parser.c appmodel-plugin.c appmodel-context.c app-parser-generator.c application.c ) add_module( TARGET appmodel GRAMMAR appmodel-grammar SOURCES ${APPMODEL_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/appmodel/Makefile.am000066400000000000000000000024441450431004300226640ustar00rootroot00000000000000 appmodel_sources = module_LTLIBRARIES += modules/appmodel/libappmodel.la modules_appmodel_libappmodel_la_SOURCES = \ modules/appmodel/appmodel.c \ modules/appmodel/appmodel.h \ modules/appmodel/appmodel-parser.c \ modules/appmodel/appmodel-parser.h \ modules/appmodel/appmodel-plugin.c \ modules/appmodel/appmodel-context.c \ modules/appmodel/appmodel-context.h \ modules/appmodel/app-parser-generator.c \ modules/appmodel/app-parser-generator.h \ modules/appmodel/application.c \ modules/appmodel/application.h \ modules/appmodel/appmodel-grammar.y modules_appmodel_libappmodel_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/appmodel \ -I$(top_builddir)/modules/appmodel modules_appmodel_libappmodel_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_appmodel_libappmodel_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_appmodel_libappmodel_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) BUILT_SOURCES += \ modules/appmodel/appmodel-grammar.y \ modules/appmodel/appmodel-grammar.c \ modules/appmodel/appmodel-grammar.h EXTRA_DIST += \ modules/appmodel/appmodel-grammar.ym \ modules/appmodel/CMakeLists.txt modules/appmodel modules/appmodel/ mod-tags-parser: modules/appmodel/libappmodel.la .PHONY: modules/appmodel/ mod-tags-parser include modules/appmodel/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/appmodel/app-parser-generator.c000066400000000000000000000150701450431004300250310ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "app-parser-generator.h" #include "appmodel.h" #include typedef struct _AppParserGenerator { CfgBlockGenerator super; GString *block; const gchar *topic; const gchar *included_apps; const gchar *excluded_apps; gboolean is_parsing_enabled; } AppParserGenerator; static const gchar * _get_filter_expr(Application *app, Application *base_app) { if (app->filter_expr) return app->filter_expr; if (base_app) return base_app->filter_expr; return NULL; } static const gchar * _get_parser_expr(Application *app, Application *base_app) { if (app->parser_expr) return app->parser_expr; if (base_app) return base_app->parser_expr; return NULL; } static void _generate_filter(AppParserGenerator *self, const gchar *filter_expr) { if (filter_expr) g_string_append_printf(self->block, " filter { %s };\n", filter_expr); } static void _generate_parser(AppParserGenerator *self, const gchar *parser_expr) { if (parser_expr) g_string_append_printf(self->block, " parser { %s };\n", parser_expr); } static void _generate_action(AppParserGenerator *self, Application *app) { g_string_append_printf(self->block, " rewrite {\n" " set-tag('.app.%s');\n" " set('%s' value('.app.name'));\n" " };\n" " flags(final);\n", app->name, app->name); } static gboolean _is_application_included(AppParserGenerator *self, Application *app) { /* include everything if we don't have the option */ if (!self->included_apps) return TRUE; return strstr(self->included_apps, app->name) != NULL; } static gboolean _is_application_excluded(AppParserGenerator *self, Application *app) { if (!self->excluded_apps) return FALSE; return strstr(self->excluded_apps, app->name) != NULL; } static void _generate_application(Application *app, Application *base_app, gpointer user_data) { AppParserGenerator *self = (AppParserGenerator *) user_data; if (strcmp(self->topic, app->topic) != 0) return; if (!_is_application_included(self, app)) return; if (_is_application_excluded(self, app)) return; g_string_append_printf(self->block, "\n#Start Application %s\n", app->name); g_string_append(self->block, "channel {\n"); _generate_filter(self, _get_filter_expr(app, base_app)); _generate_parser(self, _get_parser_expr(app, base_app)); _generate_action(self, app); g_string_append(self->block, "};\n"); g_string_append_printf(self->block, "\n#End Application %s\n", app->name); } static void _generate_applications(AppParserGenerator *self, AppModelContext *appmodel) { appmodel_context_iter_applications(appmodel, _generate_application, self); } static void _generate_empty_frame(AppParserGenerator *self) { g_string_append(self->block, "\nchannel { filter { tags('.app.doesnotexist'); }; flags(final); };"); } static void _generate_framing(AppParserGenerator *self, AppModelContext *appmodel) { g_string_append(self->block, "\nchannel {\n" " junction {\n"); _generate_applications(self, appmodel); _generate_empty_frame(self); g_string_append(self->block, " };\n"); g_string_append(self->block, "}"); } static gboolean _parse_auto_parse_arg(AppParserGenerator *self, CfgArgs *args, const gchar *reference) { const gchar *v = cfg_args_get(args, "auto-parse"); if (v) self->is_parsing_enabled = cfg_process_yesno(v); else self->is_parsing_enabled = TRUE; return TRUE; } static gboolean _parse_auto_parse_exclude_arg(AppParserGenerator *self, CfgArgs *args, const gchar *reference) { const gchar *v = cfg_args_get(args, "auto-parse-exclude"); if (!v) return TRUE; self->excluded_apps = g_strdup(v); return TRUE; } static gboolean _parse_auto_parse_include_arg(AppParserGenerator *self, CfgArgs *args, const gchar *reference) { const gchar *v = cfg_args_get(args, "auto-parse-include"); if (!v) return TRUE; self->included_apps = g_strdup(v); return TRUE; } static gboolean _parse_topic_arg(AppParserGenerator *self, CfgArgs *args, const gchar *reference) { self->topic = cfg_args_get(args, "topic"); if (!self->topic) { msg_error("app-parser() requires a topic() argument", evt_tag_str("reference", reference)); return FALSE; } return TRUE; } static gboolean _parse_arguments(AppParserGenerator *self, CfgArgs *args, const gchar *reference) { g_assert(args != NULL); if (!_parse_topic_arg(self, args, reference)) return FALSE; if (!_parse_auto_parse_arg(self, args, reference)) return FALSE; if (!_parse_auto_parse_exclude_arg(self, args, reference)) return FALSE; if (!_parse_auto_parse_include_arg(self, args, reference)) return FALSE; return TRUE; } static gboolean _generate(CfgBlockGenerator *s, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference) { AppParserGenerator *self = (AppParserGenerator *) s; AppModelContext *appmodel = appmodel_get_context(cfg); CfgArgs *cfgargs = (CfgArgs *)args; if (!_parse_arguments(self, cfgargs, reference)) return FALSE; self->block = result; if (self->is_parsing_enabled) _generate_framing(self, appmodel); else _generate_empty_frame(self); self->block = NULL; return TRUE; } CfgBlockGenerator * app_parser_generator_new(gint context, const gchar *name) { AppParserGenerator *self = g_new0(AppParserGenerator, 1); cfg_block_generator_init_instance(&self->super, context, name); self->super.generate = _generate; return &self->super; } syslog-ng-syslog-ng-4.4.0/modules/appmodel/app-parser-generator.h000066400000000000000000000023151450431004300250340ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPMODEL_APPPARSER_GENERATOR_H_INCLUDED #define APPMODEL_APPPARSER_GENERATOR_H_INCLUDED #include "plugin.h" CfgBlockGenerator *app_parser_generator_new(gint context, const gchar *name); #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/application.c000066400000000000000000000031621450431004300232750ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "application.h" void application_set_filter(Application *self, const gchar *filter_expr) { g_free(self->filter_expr); self->filter_expr = g_strdup(filter_expr); } void application_set_parser(Application *self, const gchar *parser_expr) { g_free(self->parser_expr); self->parser_expr = g_strdup(parser_expr); } Application * application_new(const gchar *name, const gchar *topic) { Application *self = g_new0(Application, 1); self->name = g_strdup(name); self->topic = g_strdup(topic); return self; } void application_free(Application *self) { g_free(self->name); g_free(self->topic); g_free(self->filter_expr); g_free(self->parser_expr); g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/appmodel/application.h000066400000000000000000000026471450431004300233110ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPMODEL_APPLICATION_H_INCLUDED #define APPMODEL_APPLICATION_H_INCLUDED #include "syslog-ng.h" typedef struct _Application { gchar *name; gchar *topic; gchar *filter_expr; gchar *parser_expr; } Application; void application_set_filter(Application *self, const gchar *filter_expr); void application_set_parser(Application *self, const gchar *parser_expr); Application *application_new(const gchar *name, const gchar *topic); void application_free(Application *s); #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-context.c000066400000000000000000000073141450431004300242600ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * Copyright (c) 2015 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "appmodel.h" #include struct _AppModelContext { /* the context structure is registered into GlobalConfig, thus it must be * derived from ModuleConfig */ ModuleConfig super; GHashTable *applications; GPtrArray *application_ptrs; }; static gboolean _application_equal(gconstpointer v1, gconstpointer v2) { Application *r1 = (Application *) v1; Application *r2 = (Application *) v2; if (strcmp(r1->name, r2->name) != 0) return FALSE; if (strcmp(r1->topic, r2->topic) != 0) return FALSE; return TRUE; } static guint _application_hash(gconstpointer v) { Application *r = (Application *) v; return g_str_hash(r->name) + g_str_hash(r->topic); } void appmodel_context_register_application(AppModelContext *self, Application *app) { Application *orig_app; orig_app = g_hash_table_lookup(self->applications, app); if (!orig_app) { g_hash_table_insert(self->applications, app, app); g_ptr_array_add(self->application_ptrs, app); } else { g_hash_table_replace(self->applications, app, app); g_ptr_array_remove(self->application_ptrs, orig_app); g_ptr_array_add(self->application_ptrs, app); } } Application * appmodel_context_lookup_application(AppModelContext *self, const gchar *name, const gchar *topic) { Application lookup_app = { 0 }; lookup_app.name = (gchar *) name; lookup_app.topic = (gchar *) topic; return (Application *) g_hash_table_lookup(self->applications, &lookup_app); } void appmodel_context_iter_applications(AppModelContext *self, void (*foreach)(Application *app, Application *base_app, gpointer user_data), gpointer user_data) { gint i; for (i = 0; i < self->application_ptrs->len; i++) { Application *app = g_ptr_array_index(self->application_ptrs, i); if (strcmp(app->topic, "*") == 0) continue; Application *base_app = appmodel_context_lookup_application(self, app->name, "*"); foreach(app, base_app, user_data); } } void appmodel_context_free_method(ModuleConfig *s) { AppModelContext *self = (AppModelContext *) s; g_hash_table_destroy(self->applications); g_ptr_array_free(self->application_ptrs, TRUE); module_config_free_method(s); } AppModelContext * appmodel_context_new(void) { AppModelContext *self = g_new0(AppModelContext, 1); self->super.free_fn = appmodel_context_free_method; self->applications = g_hash_table_new_full(_application_hash, _application_equal, NULL, (GDestroyNotify) application_free); self->application_ptrs = g_ptr_array_new(); return self; } void appmodel_context_free(AppModelContext *self) { return module_config_free(&self->super); } syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-context.h000066400000000000000000000032401450431004300242570ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPMODEL_CONTEXT_H_INCLUDED #define APPMODEL_CONTEXT_H_INCLUDED 1 #include "module-config.h" #include "application.h" typedef struct _AppModelContext AppModelContext; void appmodel_context_iter_applications(AppModelContext *self, void (*foreach)(Application *app, Application *base_app, gpointer user_data), gpointer user_data); Application *appmodel_context_lookup_application(AppModelContext *self, const gchar *name, const gchar *topic); void appmodel_context_register_application(AppModelContext *self, Application *app); void appmodel_context_free(AppModelContext *self); AppModelContext *appmodel_context_new(void); #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-grammar.ym000066400000000000000000000045401450431004300244230ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "appmodel.h" #include "appmodel-parser.h" } %code { #include "cfg-parser.h" #include "cfg-grammar-internal.h" #include "messages.h" Application *last_application; } %define api.prefix {appmodel_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {gpointer *instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_APPLICATION %type application_definition %% start : LL_CONTEXT_ROOT application_definition { appmodel_register_application(configuration, last_application); *instance = last_application; YYACCEPT; } ; application_definition : KW_APPLICATION string '[' string ']' { last_application = application_new($2, $4); } '{' application_options '}' { $$ = last_application; free($2); free($4); } ; application_options : application_option semicolons application_options | ; application_option : KW_FILTER _block_content_context_push LL_BLOCK _block_content_context_pop { application_set_filter(last_application, $3); free($3); } | KW_PARSER _block_content_context_push LL_BLOCK _block_content_context_pop { application_set_parser(last_application, $3); free($3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-parser.c000066400000000000000000000030151450431004300240620ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "appmodel.h" #include "cfg-parser.h" #include "appmodel-grammar.h" extern int appmodel_debug; int appmodel_parse(CfgLexer *lexer, gpointer *instance, gpointer arg); static CfgLexerKeyword appmodel_keywords[] = { { "application", KW_APPLICATION }, { NULL } }; CfgParser appmodel_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &appmodel_debug, #endif .name = "appmodel", .keywords = appmodel_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) appmodel_parse, .cleanup = NULL, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(appmodel_, APPMODEL_, gpointer *) syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-parser.h000066400000000000000000000022411450431004300240670ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPMODEL_PARSER_H_INCLUDED #define APPMODEL_PARSER_H_INCLUDED #include "cfg-parser.h" #include "cfg-lexer.h" extern CfgParser appmodel_parser; CFG_PARSER_DECLARE_LEXER_BINDING(appmodel_, APPMODEL_, gpointer *) #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel-plugin.c000066400000000000000000000040371450431004300240710ustar00rootroot00000000000000/* * Copyright (c) 2002-2015 Balabit * Copyright (c) 1998-2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "appmodel-parser.h" #include "app-parser-generator.h" #include "block-ref-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser appmodel_parser; static gpointer app_parser_construct(Plugin *p) { return app_parser_generator_new(p->type, p->name); } static Plugin appmodel_plugins[] = { { .type = LL_CONTEXT_ROOT, .name = "application", .parser = &appmodel_parser, }, { .type = LL_CONTEXT_PARSER | LL_CONTEXT_FLAG_GENERATOR, .name = "app-parser", .construct = app_parser_construct, .parser = &block_ref_parser } }; gboolean appmodel_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, appmodel_plugins, G_N_ELEMENTS(appmodel_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "appmodel", .version = SYSLOG_NG_VERSION, .description = "The appmodel module provides parsing support for restoring message tags as produced by the TAGS macro.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = appmodel_plugins, .plugins_len = G_N_ELEMENTS(appmodel_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel.c000066400000000000000000000030721450431004300225730ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "appmodel.h" #include "cfg.h" #define MODULE_CONFIG_KEY "appmodel" AppModelContext * appmodel_get_context(GlobalConfig *cfg) { AppModelContext *ac = g_hash_table_lookup(cfg->module_config, MODULE_CONFIG_KEY); if (!ac) { ac = appmodel_context_new(); g_hash_table_insert(cfg->module_config, g_strdup(MODULE_CONFIG_KEY), ac); } return ac; } void appmodel_register_application(GlobalConfig *cfg, Application *application) { AppModelContext *ac = appmodel_get_context(cfg); appmodel_context_register_application(ac, application); } syslog-ng-syslog-ng-4.4.0/modules/appmodel/appmodel.h000066400000000000000000000023271450431004300226020ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef APPMODEL_H_INCLUDED #define APPMODEL_H_INCLUDED 1 #include "module-config.h" #include "appmodel-context.h" AppModelContext *appmodel_get_context(GlobalConfig *cfg); void appmodel_register_application(GlobalConfig *cfg, Application *application); #endif syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/000077500000000000000000000000001450431004300217665ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/CMakeLists.txt000066400000000000000000000006571450431004300245360ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_appmodel INCLUDES "${APPMODEL_INCLUDE_DIR}" DEPENDS appmodel) add_unit_test(CRITERION TARGET test_appmodel_context INCLUDES "${APPMODEL_INCLUDE_DIR}" DEPENDS appmodel) add_unit_test(LIBTEST CRITERION TARGET test_app_parser_generator INCLUDES "${APPMODEL_INCLUDE_DIR}" DEPENDS appmodel) add_unit_test(CRITERION TARGET test_application INCLUDES "${APPMODEL_INCLUDE_DIR}" DEPENDS appmodel) syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/Makefile.am000066400000000000000000000040331450431004300240220ustar00rootroot00000000000000EXTRA_DIST += modules/appmodel/tests/CMakeLists.txt modules_appmodel_tests_TESTS = \ modules/appmodel/tests/test_appmodel \ modules/appmodel/tests/test_appmodel_context \ modules/appmodel/tests/test_app_parser_generator \ modules/appmodel/tests/test_application check_PROGRAMS += \ ${modules_appmodel_tests_TESTS} modules_appmodel_tests_test_appmodel_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/appmodel modules_appmodel_tests_test_appmodel_LDADD = \ $(TEST_LDADD) modules_appmodel_tests_test_appmodel_LDFLAGS = \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_appmodel_DEPENDENCIES = \ $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_appmodel_context_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/appmodel modules_appmodel_tests_test_appmodel_context_LDADD = \ $(TEST_LDADD) modules_appmodel_tests_test_appmodel_context_LDFLAGS = \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_appmodel_context_DEPENDENCIES = \ $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_app_parser_generator_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/appmodel modules_appmodel_tests_test_app_parser_generator_LDADD = \ $(TEST_LDADD) modules_appmodel_tests_test_app_parser_generator_LDFLAGS = \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_app_parser_generator_DEPENDENCIES = \ $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_application_CFLAGS = \ $(TEST_CFLAGS) -I$(top_srcdir)/modules/appmodel modules_appmodel_tests_test_application_LDADD = \ $(TEST_LDADD) modules_appmodel_tests_test_application_LDFLAGS = \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/appmodel/libappmodel.la modules_appmodel_tests_test_application_DEPENDENCIES = \ $(top_builddir)/modules/appmodel/libappmodel.la syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/test_app_parser_generator.c000066400000000000000000000220311450431004300273710ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/config_parse_lib.h" #include "app-parser-generator.h" #include "apphook.h" #include "plugin-types.h" static CfgBlockGenerator *app_parser; static GString *result; void _register_application(const char *appmodel) { cr_assert(parse_config(appmodel, LL_CONTEXT_ROOT, NULL, NULL), "Parsing the given configuration failed: %s", appmodel); } void _register_sample_application(const gchar *name, const gchar *topic) { gchar *app; app = g_strdup_printf("application %s[%s] {\n" " filter { program('%s'); };\n" " parser { kv-parser(prefix('%s.')); };\n" "};", name, topic, name, name); _register_application(app); g_free(app); } static CfgBlockGenerator * _construct_app_parser(void) { return app_parser_generator_new(LL_CONTEXT_PARSER, "app-parser"); } static CfgArgs * _build_cfg_args(const gchar *key, const gchar *value, ...) { CfgArgs *args = cfg_args_new(); va_list va; va_start(va, value); while (key) { cfg_args_set(args, key, value); key = va_arg(va, gchar *); if (!key) break; value = va_arg(va, gchar *); } va_end(va); return args; } static GString * _remove_comments(const GString *str) { GString *prune = g_string_new(""); gboolean is_inside_comment = FALSE; for (gint i=0; i < str->len; ++i) { const gchar curr = str->str[i]; const gboolean is_comment_start = '#' == curr; const gboolean is_comment_end = curr == '\n'; const gboolean does_comment_continue_next_line = is_comment_end && (i+1) < str->len && '#' == str->str[i+1]; if (is_comment_start || does_comment_continue_next_line) { is_inside_comment = TRUE; } if (!is_inside_comment) { g_string_append_c(prune, str->str[i]); } if (is_comment_end) { is_inside_comment = FALSE; } } return prune; } static void _app_parser_generate_with_args(const gchar *topic, CfgArgs *args) { GString *tmp = g_string_new(""); cfg_args_set(args, "topic", topic); cfg_block_generator_generate(app_parser, configuration, args, tmp, "dummy-reference"); result = _remove_comments(tmp); g_string_free(tmp, TRUE); cfg_args_unref(args); } static void _app_parser_generate(const gchar *topic) { _app_parser_generate_with_args(topic, cfg_args_new()); } static void _assert_config_is_valid(const gchar *topic, const gchar *varargs) { const gchar *config_fmt = "" "parser p_test {\n" " app-parser(topic(\"%s\") %s);\n" "};\n"; gchar *config; config = g_strdup_printf(config_fmt, topic, varargs ? : ""); cr_assert(parse_config(config, LL_CONTEXT_ROOT, NULL, NULL), "Parsing the given configuration failed: %s", config); g_free(config); } static void _assert_snippet_is_present(const gchar *snippet) { cr_assert(strstr(result->str, snippet), "Can't find config snippet in generated output: %s, config: >>>%s<<<", snippet, result->str); } static void _assert_snippet_is_not_present(const gchar *snippet) { cr_assert(strstr(result->str, snippet) == NULL, "Could find config snippet which shouldn't be there in generated output: %s, config: >>>%s<<<", snippet, result->str); } static void _assert_application_is_present(const gchar *application) { const gchar *settag_fmt = "set-tag('.app.%s');"; gchar *settag_snippet = g_strdup_printf(settag_fmt, application); cr_assert(strstr(result->str, settag_snippet), "Can't find set-tag() invocation for this application: %s, snippet: %s, config: >>>%s<<<", application, settag_snippet, result->str); g_free(settag_snippet); } static void _assert_parser_framing_is_present(void) { cr_assert(g_str_has_prefix(result->str, "\nchannel"), "Cannot find app-parser() framing (prefix) >>>%s<<<", result->str); cr_assert(g_str_has_suffix(result->str, "};\n}"), "Cannot find app-parser() framing (suffix): >>>%s<<<", result->str); } static void startup(void) { app_startup(); configuration = cfg_new_snippet(); cfg_load_module(configuration, "appmodel"); app_parser = _construct_app_parser(); result = g_string_new(""); } static void teardown(void) { g_string_free(result, TRUE); app_shutdown(); } Test(app_parser_generator, app_parser_with_no_apps_registered_generates_empty_framing) { _app_parser_generate("port514"); _assert_parser_framing_is_present(); _assert_snippet_is_present("tags('.app.doesnotexist')"); _assert_config_is_valid("port514", NULL); } Test(app_parser_generator, app_parser_generates_references_to_apps) { _register_sample_application("foo", "port514"); _register_sample_application("bar", "port514"); _app_parser_generate("port514"); _assert_parser_framing_is_present(); _assert_application_is_present("foo"); _assert_application_is_present("bar"); _assert_config_is_valid("port514", NULL); } Test(app_parser_generator, app_parser_uses_filter_or_parser_from_base_topics) { _register_application("application foo[port514] {\n" "};"); _register_sample_application("foo", "*"); _app_parser_generate("port514"); _assert_parser_framing_is_present(); _assert_application_is_present("foo"); _assert_snippet_is_present("program('foo')"); _assert_snippet_is_present("kv-parser(prefix('foo.'))"); _assert_config_is_valid("port514", NULL); } Test(app_parser_generator, app_parser_base_topics_are_skipped) { _register_sample_application("foo", "*"); _register_sample_application("bar", "*"); _app_parser_generate("port514"); _assert_parser_framing_is_present(); _assert_snippet_is_not_present("program('foo')"); _assert_snippet_is_not_present("program('bar')"); _assert_config_is_valid("port514", NULL); } Test(app_parser_generator, app_parser_is_disabled_if_auto_parse_is_set_to_no) { _register_sample_application("foo", "port514"); _register_sample_application("bar", "port514"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse", "no", NULL)); _assert_snippet_is_present("tags('.app.doesnotexist')"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse", "yes", NULL)); _assert_parser_framing_is_present(); _assert_snippet_is_present("program('foo')"); _assert_snippet_is_present("program('bar')"); _assert_config_is_valid("port514", "auto-parse(yes)"); } Test(app_parser_generator, app_parser_excludes_apps) { _register_sample_application("foo", "port514"); _register_sample_application("bar", "port514"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse-exclude", "foo", NULL)); _assert_parser_framing_is_present(); _assert_snippet_is_not_present("program('foo')"); _assert_snippet_is_present("program('bar')"); } Test(app_parser_generator, app_parser_includes_apps) { _register_sample_application("foo", "port514"); _register_sample_application("bar", "port514"); _register_sample_application("baz", "port514"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse-include", "foo", NULL)); _assert_parser_framing_is_present(); _assert_snippet_is_present("program('foo')"); _assert_snippet_is_not_present("program('bar')"); _assert_snippet_is_not_present("program('baz')"); } Test(app_parser_generator, app_parser_includes_and_excludes_apps) { _register_sample_application("foo", "port514"); _register_sample_application("bar", "port514"); _register_sample_application("baz", "port514"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse-include", "foo,bar", "auto-parse-exclude", "bar", NULL)); _assert_parser_framing_is_present(); _assert_snippet_is_present("program('foo')"); _assert_snippet_is_not_present("program('bar')"); _assert_snippet_is_not_present("program('baz')"); } TestSuite(app_parser_generator, .init = startup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/test_application.c000066400000000000000000000040411450431004300254730ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "application.h" Test(application, empty_application_can_be_created_and_freed) { Application *app; app = application_new("foobar", "*"); application_free(app); } Test(application, filter_can_be_set_and_queried) { Application *app; const gchar *filter_expr = "'1' eq '1'"; const gchar *filter_expr2 = "'2' eq '2'"; app = application_new("foobar", "*"); application_set_filter(app, filter_expr); cr_assert_str_eq(app->filter_expr, filter_expr); application_set_filter(app, filter_expr2); cr_assert_str_eq(app->filter_expr, filter_expr2); application_free(app); } Test(application, parser_can_be_set_and_queried) { Application *app; const gchar *parser_expr = "kv-parser();"; const gchar *parser_expr2 = "csv-parser();"; app = application_new("foobar", "*"); application_set_parser(app, parser_expr); cr_assert_str_eq(app->parser_expr, parser_expr); application_set_parser(app, parser_expr2); cr_assert_str_eq(app->parser_expr, parser_expr2); application_free(app); } syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/test_appmodel.c000066400000000000000000000064171450431004300250020ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/config_parse_lib.h" #include "appmodel.h" #include "application.h" #include "plugin.h" #include "apphook.h" #include "cfg-grammar.h" Application * _parse_application(const char *appmodel, const gchar *name, const gchar *topic) { AppModelContext *ac; cfg_load_module(configuration, "appmodel"); cr_assert(parse_config(appmodel, LL_CONTEXT_ROOT, NULL, NULL), "Parsing the given configuration failed: %s", appmodel); ac = appmodel_get_context(configuration); return appmodel_context_lookup_application(ac, name, topic); } Test(appmodel, empty_application_can_be_parsed_properly) { Application *app; app = _parse_application("application foobar[*] {};", "foobar", "*"); cr_assert(app != NULL); cr_assert_str_eq(app->name, "foobar"); cr_assert_str_eq(app->topic, "*"); } Test(appmodel, name_is_parsed_into_name_member) { Application *app; app = _parse_application("application name[*] {};", "name", "*"); cr_assert(app != NULL); } Test(appmodel, topic_in_brackets_is_parsed_into_topic) { Application *app; app = _parse_application("application name[port514] {};", "name", "port514"); cr_assert(app != NULL); cr_assert_str_eq(app->topic, "port514"); } Test(appmodel, filter_expressions_can_be_specified_with_a_filter_keyword) { Application *app; app = _parse_application( "application name[port514] {" " filter { program(\"kernel\"); };" " parser { kv-parser(); };" "};", "name", "port514"); cr_assert(app != NULL); cr_assert_str_eq(app->topic, "port514"); cr_assert_str_eq(app->filter_expr, " program(\"kernel\"); "); } Test(appmodel, parser_expressions_can_be_specified_with_a_parser_keyword) { Application *app; app = _parse_application( "application name[port514] {" " parser { kv-parser(); };" " filter { program(\"kernel\"); };" "};", "name", "port514"); cr_assert(app != NULL); cr_assert_str_eq(app->topic, "port514"); cr_assert_str_eq(app->parser_expr, " kv-parser(); "); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); } void teardown(void) { cfg_free(configuration); app_shutdown(); } TestSuite(appmodel, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/appmodel/tests/test_appmodel_context.c000066400000000000000000000061311450431004300265370ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "appmodel.h" static AppModelContext *ac; static void startup(void) { ac = appmodel_context_new(); } static void teardown(void) { appmodel_context_free(ac); ac = NULL; } Test(appmodel_context, register_application_makes_the_app_available) { appmodel_context_register_application(ac, application_new("foobar", "*")); appmodel_context_lookup_application(ac, "foobar", "*"); } static void _foreach_app(Application *app, Application *base_app, gpointer user_data) { GString *result = (GString *) user_data; g_string_append(result, app->name); } Test(appmodel_context, iter_applications_enumerates_apps_without_asterisk) { GString *result = g_string_sized_new(128); appmodel_context_register_application(ac, application_new("foo", "*")); appmodel_context_register_application(ac, application_new("foo", "port514")); appmodel_context_register_application(ac, application_new("bar", "*")); appmodel_context_register_application(ac, application_new("bar", "port514")); appmodel_context_register_application(ac, application_new("baz", "*")); appmodel_context_register_application(ac, application_new("baz", "port514")); appmodel_context_iter_applications(ac, _foreach_app, result); cr_assert_str_eq(result->str, "foobarbaz"); g_string_free(result, TRUE); } Test(appmodel_context, iter_applications_enumerates_apps_in_the_order_of_registration) { GString *result = g_string_sized_new(128); appmodel_context_register_application(ac, application_new("baz", "*")); appmodel_context_register_application(ac, application_new("baz", "port514")); appmodel_context_register_application(ac, application_new("bar", "*")); appmodel_context_register_application(ac, application_new("bar", "port514")); appmodel_context_register_application(ac, application_new("foo", "*")); appmodel_context_register_application(ac, application_new("foo", "port514")); appmodel_context_iter_applications(ac, _foreach_app, result); cr_assert_str_eq(result->str, "bazbarfoo"); g_string_free(result, TRUE); } TestSuite(appmodel_context, .init = startup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/000077500000000000000000000000001450431004300223365ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/CMakeLists.txt000066400000000000000000000007201450431004300250750ustar00rootroot00000000000000module_switch(ENABLE_AZURE_AUTH_HEADER "Enable azure-auth-header module") if (NOT ENABLE_AZURE_AUTH_HEADER) return() endif() set(AZURE_AUTH_HEADER_SOURCES "azure-auth-header-parser.h" "azure-auth-header.h" "azure-auth-header-plugin.c" "azure-auth-header-parser.c" "azure-auth-header.c" ) add_module( TARGET azure-auth-header GRAMMAR azure-auth-header-grammar INCLUDES ${PROJECT_SOURCE_DIR} SOURCES ${AZURE_AUTH_HEADER_SOURCES} ) syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/Makefile.am000066400000000000000000000026621450431004300244000ustar00rootroot00000000000000module_LTLIBRARIES += modules/azure-auth-header/libazure-auth-header.la modules_azure_auth_header_libazure_auth_header_la_SOURCES = \ modules/azure-auth-header/azure-auth-header-grammar.y \ modules/azure-auth-header/azure-auth-header-parser.c \ modules/azure-auth-header/azure-auth-header-parser.h \ modules/azure-auth-header/azure-auth-header-plugin.c \ modules/azure-auth-header/azure-auth-header.c \ modules/azure-auth-header/azure-auth-header.h BUILT_SOURCES += \ modules/azure-auth-header/azure-auth-header-grammar.y \ modules/azure-auth-header/azure-auth-header-grammar.c \ modules/azure-auth-header/azure-auth-header-grammar.h EXTRA_DIST += \ modules/azure-auth-header/azure-auth-header-grammar.ym \ modules/azure-auth-header/CMakeLists.txt modules_azure_auth_header_libazure_auth_header_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/modules/azure-auth-header -I$(top_builddir)/modules/azure-auth-header modules_azure_auth_header_libazure_auth_header_la_LIBADD = $(MODULE_DEPS_LIBS) modules_azure_auth_header_libazure_auth_header_la_LDFLAGS = $(MODULE_LDFLAGS) modules_azure_auth_header_libazure_auth_header_la_DEPENDENCIES = $(MODULE_DEPS_LIBS) modules/azure-auth-header modules/azure-auth-header/ mod-azure-auth-header: modules/azure-auth-header/libazure-auth-header.la .PHONY: modules/azure-auth-header/ mod-azure-auth-header syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header-grammar.ym000066400000000000000000000050671450431004300276540ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "driver.h" #include "cfg-lexer.h" #include "azure-auth-header-parser.h" } %code { #pragma GCC diagnostic ignored "-Wswitch-default" #include "azure-auth-header.h" AzureAuthHeaderPlugin *last_header; } %define api.prefix {azure_auth_header_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogDriverPlugin **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_AZURE_AUTH %token KW_WORKSPACE_ID %token KW_SECRET %token KW_METHOD %token KW_PATH %token KW_CONTENT_TYPE %% start : LL_CONTEXT_INNER_DEST azure_auth_header_start { YYACCEPT; } ; azure_auth_header_start : KW_AZURE_AUTH '(' { last_header = azure_auth_header_plugin_new(); *instance = (LogDriverPlugin *) last_header; } azure_auth_opts ')' ; azure_auth_opts : azure_auth_opt azure_auth_opts | ; azure_auth_opt : KW_WORKSPACE_ID '(' string ')' { azure_auth_header_workspace_id_set(last_header, $3); free($3); } | KW_SECRET '(' string ')' { CHECK_ERROR(azure_auth_header_secret_set_from_b64str(last_header, $3), @3, "Failed to set secret from string: %s. Secret should be a valid base64 string.", $3); free($3); } | KW_METHOD '(' string ')' { azure_auth_header_method_set(last_header, $3); free($3); } | KW_PATH '(' string ')' { azure_auth_header_path_set(last_header, $3); free($3); } | KW_CONTENT_TYPE '(' string ')' { azure_auth_header_content_type_set(last_header, $3); free($3); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header-parser.c000066400000000000000000000035201450431004300273070ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "azure-auth-header.h" #include "azure-auth-header-grammar.h" extern int azure_auth_header_debug; int azure_auth_header_parse(CfgLexer *lexer, LogDriverPlugin **instance, gpointer arg); static CfgLexerKeyword azure_auth_header_keywords[] = { { "azure_auth_header", KW_AZURE_AUTH }, { "workspace_id", KW_WORKSPACE_ID }, { "secret", KW_SECRET }, { "method", KW_METHOD }, { "path", KW_PATH }, { "content_type", KW_CONTENT_TYPE }, { NULL } }; CfgParser azure_auth_header_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &azure_auth_header_debug, #endif .name = "azure_auth_header", .keywords = azure_auth_header_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) azure_auth_header_parse, .cleanup = (void (*)(gpointer)) log_driver_plugin_free, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(azure_auth_header_, AZURE_AUTH_HEADER_, LogDriverPlugin **) syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header-parser.h000066400000000000000000000022501450431004300273130ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AZURE_AUTH_HEADER_PARSER_H_INCLUDED #define AZURE_AUTH_HEADER_PARSER_H_INCLUDED #include "cfg-parser.h" #include "driver.h" extern CfgParser azure_auth_header_parser; CFG_PARSER_DECLARE_LEXER_BINDING(azure_auth_header_, AZURE_AUTH_HEADER_, LogDriverPlugin **); #endif syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header-plugin.c000066400000000000000000000032571450431004300273200ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser azure_auth_header_parser; static Plugin azure_auth_header_plugins[] = { { .type = LL_CONTEXT_INNER_DEST, .name = "azure-auth-header", .parser = &azure_auth_header_parser, }, }; gboolean azure_auth_header_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, azure_auth_header_plugins, G_N_ELEMENTS(azure_auth_header_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "azure_auth_header", .version = SYSLOG_NG_VERSION, .description = "HTTP authentication header support for Azure APIs", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = azure_auth_header_plugins, .plugins_len = G_N_ELEMENTS(azure_auth_header_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header.c000066400000000000000000000131601450431004300260160ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "azure-auth-header.h" #include "driver.h" #include "modules/http/http-signals.h" #include "messages.h" #include "compat/openssl_support.h" #include "compat/glib.h" #define AZURE_AUTH_HEADER_PLUGIN "azure-auth-header" #define MAX_DATE_LEN 64 struct _AzureAuthHeaderPlugin { LogDriverPlugin super; gsize secret_len; guchar *secret; gchar *workspace_id; gchar *method; gchar *path; gchar *content_type; }; static gsize _get_rfc1123date(gchar *buf, gsize buf_len) { time_t now = time(NULL); struct tm gmt; gmtime_r(&now, &gmt); gchar format[] = "%a, %d %b %Y %H:%M:%S GMT"; gsize len = strftime(buf, buf_len, format, &gmt); g_assert(len); return len; } static GString * _azure_auth_header_get_str_to_hash(AzureAuthHeaderPlugin *self, glong content_len, const gchar *date) { #define X_MS_DATE_FORMAT "%s\n%ld\n%s\nx-ms-date:%s\n%s" GString *str = g_string_new(NULL); g_string_append_printf(str, X_MS_DATE_FORMAT, self->method, content_len, self->content_type, date, self->path); return str; } static guint _azure_auth_header_get_digest(AzureAuthHeaderPlugin *self, GString *input, guchar *digest) { guint md_len = 0; if (!HMAC(EVP_sha256(), self->secret, self->secret_len, (const guchar *)input->str, input->len, digest, &md_len)) { msg_error("Failed to generate Azure Auth Header HMAC", evt_tag_str("str", input->str), evt_tag_int("len", input->len)); return 0; } return md_len; } static void _azure_auth_header_format_headers(AzureAuthHeaderPlugin *self, List *headers, const gchar *digest, const gchar *date) { GString *auth_hdr = g_string_new(NULL); GString *date_hdr = g_string_new(NULL); g_string_printf(auth_hdr, "Authorization: SharedKey %s:%s", self->workspace_id, digest); g_string_printf(date_hdr, "x-ms-date: %s", date); list_append(headers, auth_hdr->str); list_append(headers, date_hdr->str); g_string_free(auth_hdr, TRUE); g_string_free(date_hdr, TRUE); } static gboolean _append_headers(AzureAuthHeaderPlugin *self, List *headers, GString *body) { g_return_val_if_fail(self->secret, FALSE); gchar date[MAX_DATE_LEN] = {0}; _get_rfc1123date(date, MAX_DATE_LEN); GString *rawstr = _azure_auth_header_get_str_to_hash(self, body->len, date); guchar digest[EVP_MAX_MD_SIZE] = {0}; gsize digest_len = _azure_auth_header_get_digest(self, rawstr, digest); if (digest_len == 0) { g_string_free(rawstr, TRUE); return FALSE; } gchar *digest_str = g_base64_encode(digest, digest_len); _azure_auth_header_format_headers(self, headers, digest_str, date); g_free(digest_str); g_string_free(rawstr, TRUE); return TRUE; } gboolean azure_auth_header_secret_set_from_b64str(AzureAuthHeaderPlugin *self, const gchar *b64secret) { g_free(self->secret); self->secret = g_base64_decode(b64secret, &self->secret_len); return (self->secret != NULL) && (self->secret_len > 0); } void azure_auth_header_workspace_id_set(AzureAuthHeaderPlugin *self, const gchar *workspace_id) { g_free(self->workspace_id); self->workspace_id = g_strdup(workspace_id); } void azure_auth_header_method_set(AzureAuthHeaderPlugin *self, const gchar *method) { g_free(self->method); self->method = g_strdup(method); } void azure_auth_header_path_set(AzureAuthHeaderPlugin *self, const gchar *path) { g_free(self->path); self->path = g_strdup(path); } void azure_auth_header_content_type_set(AzureAuthHeaderPlugin *self, const gchar *content_type) { g_free(self->content_type); self->content_type = g_strdup(content_type); } static void _slot_append_headers(AzureAuthHeaderPlugin *self, HttpHeaderRequestSignalData *data) { _append_headers(self, data->request_headers, data->request_body); } static gboolean _attach(LogDriverPlugin *s, LogDriver *driver) { AzureAuthHeaderPlugin *self = (AzureAuthHeaderPlugin *)s; SignalSlotConnector *ssc = driver->super.signal_slot_connector; msg_debug("AzureAuthHeaderPlugin::attach()", evt_tag_printf("SignalSlotConnector", "%p", ssc), evt_tag_printf("AzureAuthHeaderPlugin", "%p", s)); CONNECT(ssc, signal_http_header_request, _slot_append_headers, self); return TRUE; } static void _free(LogDriverPlugin *s) { AzureAuthHeaderPlugin *self = (AzureAuthHeaderPlugin *) s; g_free(self->workspace_id); g_free(self->secret); g_free(self->method); g_free(self->path); g_free(self->content_type); log_driver_plugin_free_method(s); } AzureAuthHeaderPlugin * azure_auth_header_plugin_new(void) { AzureAuthHeaderPlugin *self = g_new0(AzureAuthHeaderPlugin, 1); log_driver_plugin_init_instance(&self->super, AZURE_AUTH_HEADER_PLUGIN); self->super.attach = _attach; self->super.free_fn = _free; return self; } syslog-ng-syslog-ng-4.4.0/modules/azure-auth-header/azure-auth-header.h000066400000000000000000000030571450431004300260270ustar00rootroot00000000000000/* * Copyright (c) 2020 One Identity * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef AZURE_AUTH_HEADER_H #define AZURE_AUTH_HEADER_H #include "driver.h" typedef struct _AzureAuthHeaderPlugin AzureAuthHeaderPlugin; AzureAuthHeaderPlugin *azure_auth_header_plugin_new(void); gboolean azure_auth_header_secret_set_from_b64str(AzureAuthHeaderPlugin *self, const gchar *b64secret); void azure_auth_header_workspace_id_set(AzureAuthHeaderPlugin *self, const gchar *workspace_id); void azure_auth_header_method_set(AzureAuthHeaderPlugin *self, const gchar *method); void azure_auth_header_path_set(AzureAuthHeaderPlugin *self, const gchar *path); void azure_auth_header_content_type_set(AzureAuthHeaderPlugin *self, const gchar *content_type); #endif syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/000077500000000000000000000000001450431004300211435ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/CMakeLists.txt000066400000000000000000000002271450431004300237040ustar00rootroot00000000000000set (BASICFUNCS_SOURCES basic-funcs.c ) add_module( TARGET basicfuncs SOURCES ${BASICFUNCS_SOURCES} DEPENDS m ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/Makefile.am000066400000000000000000000022671450431004300232060ustar00rootroot00000000000000module_LTLIBRARIES += modules/basicfuncs/libbasicfuncs.la modules_basicfuncs_libbasicfuncs_la_SOURCES = \ modules/basicfuncs/basic-funcs.c modules_basicfuncs_libbasicfuncs_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/basicfuncs modules_basicfuncs_libbasicfuncs_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_basicfuncs_libbasicfuncs_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_basicfuncs_libbasicfuncs_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) EXTRA_DIST += \ modules/basicfuncs/urlencode.c \ modules/basicfuncs/cond-funcs.c \ modules/basicfuncs/context-funcs.c \ modules/basicfuncs/numeric-funcs.c \ modules/basicfuncs/str-funcs.c \ modules/basicfuncs/fname-funcs.c \ modules/basicfuncs/ip-funcs.c \ modules/basicfuncs/misc-funcs.c \ modules/basicfuncs/list-funcs.c \ modules/basicfuncs/tf-template.c \ modules/basicfuncs/tf-iterate.c \ modules/basicfuncs/tf-map.c \ modules/basicfuncs/tf-filter.c \ modules/basicfuncs/vp-funcs.c \ modules/basicfuncs/CMakeLists.txt modules/basicfuncs modules/basicfuncs/ mod-basicfuncs: modules/basicfuncs/libbasicfuncs.la .PHONY: modules/basicfuncs/ mod-basicfuncs include modules/basicfuncs/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/basic-funcs.c000066400000000000000000000131301450431004300235020ustar00rootroot00000000000000/* * Copyright (c) 2010-2015 Balabit * Copyright (c) 2010-2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "plugin.h" #include "template/simple-function.h" #include "filter/filter-expr.h" #include "filter/filter-expr-parser.h" #include "cfg.h" #include "parse-number.h" #include "str-format.h" #include "plugin-types.h" #include "scratch-buffers.h" #include #include #include /* helper functions available for all modules */ void _append_args_with_separator(gint argc, GString *argv[], GString *result, gchar separator) { gint i; for (i = 0; i < argc; i++) { g_string_append_len(result, argv[i]->str, argv[i]->len); if (i < argc - 1) g_string_append_c(result, separator); } } /* in order to avoid having to declare all construct functions, we * include them all here. If it causes compilation times to increase * drastically, we should probably make them into separate compilation * units. (Bazsi) */ #include "urlencode.c" #include "numeric-funcs.c" #include "str-funcs.c" #include "cond-funcs.c" #include "ip-funcs.c" #include "misc-funcs.c" #include "list-funcs.c" #include "tf-template.c" #include "context-funcs.c" #include "fname-funcs.c" #include "tf-iterate.c" #include "tf-map.c" #include "tf-filter.c" #include "vp-funcs.c" static Plugin basicfuncs_plugins[] = { /* cond-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_grep, "grep"), TEMPLATE_FUNCTION_PLUGIN(tf_if, "if"), TEMPLATE_FUNCTION_PLUGIN(tf_or, "or"), /* context related funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_context_lookup, "context-lookup"), TEMPLATE_FUNCTION_PLUGIN(tf_context_length, "context-length"), TEMPLATE_FUNCTION_PLUGIN(tf_context_values, "context-values"), /* str-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_echo, "echo"), TEMPLATE_FUNCTION_PLUGIN(tf_length, "length"), TEMPLATE_FUNCTION_PLUGIN(tf_substr, "substr"), TEMPLATE_FUNCTION_PLUGIN(tf_strip, "strip"), TEMPLATE_FUNCTION_PLUGIN(tf_sanitize, "sanitize"), TEMPLATE_FUNCTION_PLUGIN(tf_lowercase, "lowercase"), TEMPLATE_FUNCTION_PLUGIN(tf_uppercase, "uppercase"), TEMPLATE_FUNCTION_PLUGIN(tf_replace_delimiter, "replace-delimiter"), TEMPLATE_FUNCTION_PLUGIN(tf_string_padding, "padding"), TEMPLATE_FUNCTION_PLUGIN(tf_binary, "binary"), TEMPLATE_FUNCTION_PLUGIN(tf_implode, "implode"), TEMPLATE_FUNCTION_PLUGIN(tf_explode, "explode"), /* vp-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_value_pairs, "values"), TEMPLATE_FUNCTION_PLUGIN(tf_value_pairs, "names"), /* fname-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_dirname, "dirname"), TEMPLATE_FUNCTION_PLUGIN(tf_basename, "basename"), /* list-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_list_concat, "list-concat"), TEMPLATE_FUNCTION_PLUGIN(tf_list_head, "list-head"), TEMPLATE_FUNCTION_PLUGIN(tf_list_nth, "list-nth"), TEMPLATE_FUNCTION_PLUGIN(tf_list_tail, "list-tail"), TEMPLATE_FUNCTION_PLUGIN(tf_list_slice, "list-slice"), TEMPLATE_FUNCTION_PLUGIN(tf_list_count, "list-count"), TEMPLATE_FUNCTION_PLUGIN(tf_list_append, "list-append"), TEMPLATE_FUNCTION_PLUGIN(tf_list_search, "list-search"), /* numeric-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_num_plus, "+"), TEMPLATE_FUNCTION_PLUGIN(tf_num_minus, "-"), TEMPLATE_FUNCTION_PLUGIN(tf_num_multi, "*"), TEMPLATE_FUNCTION_PLUGIN(tf_num_div, "/"), TEMPLATE_FUNCTION_PLUGIN(tf_num_mod, "%"), TEMPLATE_FUNCTION_PLUGIN(tf_num_sum, "sum"), TEMPLATE_FUNCTION_PLUGIN(tf_num_min, "min"), TEMPLATE_FUNCTION_PLUGIN(tf_num_max, "max"), TEMPLATE_FUNCTION_PLUGIN(tf_num_average, "average"), TEMPLATE_FUNCTION_PLUGIN(tf_num_round, "round"), TEMPLATE_FUNCTION_PLUGIN(tf_num_ceil, "ceil"), TEMPLATE_FUNCTION_PLUGIN(tf_num_floor, "floor"), /* ip-funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_ipv4_to_int, "ipv4-to-int"), TEMPLATE_FUNCTION_PLUGIN(tf_indent_multi_line, "indent-multi-line"), TEMPLATE_FUNCTION_PLUGIN(tf_dns_resolve_ip, "dns-resolve-ip"), /* misc funcs */ TEMPLATE_FUNCTION_PLUGIN(tf_env, "env"), TEMPLATE_FUNCTION_PLUGIN(tf_template, "template"), TEMPLATE_FUNCTION_PLUGIN(tf_urlencode, "url-encode"), TEMPLATE_FUNCTION_PLUGIN(tf_urldecode, "url-decode"), TEMPLATE_FUNCTION_PLUGIN(tf_base64encode, "base64-encode"), /* functional */ TEMPLATE_FUNCTION_PLUGIN(tf_iterate, "iterate"), TEMPLATE_FUNCTION_PLUGIN(tf_map, "map"), TEMPLATE_FUNCTION_PLUGIN(tf_filter, "filter"), }; gboolean basicfuncs_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, basicfuncs_plugins, G_N_ELEMENTS(basicfuncs_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "basicfuncs", .version = SYSLOG_NG_VERSION, .description = "The basicfuncs module provides various template functions for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = basicfuncs_plugins, .plugins_len = G_N_ELEMENTS(basicfuncs_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/cond-funcs.c000066400000000000000000000143311450431004300233500ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2013-2014 Gergely Nagy * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ typedef struct _TFCondState { TFSimpleFuncState super; FilterExprNode *filter; gint grep_max_count; } TFCondState; gboolean tf_cond_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFCondState *state = (TFCondState *) s; CfgLexer *lexer; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); lexer = cfg_lexer_new_buffer(parent->cfg, argv[1], strlen(argv[1])); if (!cfg_run_parser_with_main_context(parent->cfg, lexer, &filter_expr_parser, (gpointer *) &state->filter, NULL, "conditional filter")) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(%s) Error parsing conditional filter expression", argv[0]); return FALSE; } if (!filter_expr_init(state->filter, parent->cfg)) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(%s) Error initializing conditional filter expression", argv[0]); return FALSE; } memmove(&argv[1], &argv[2], sizeof(argv[0]) * (argc - 2)); if (!tf_simple_func_prepare(self, s, parent, argc - 1, argv, error)) return FALSE; return TRUE; } static void tf_cond_free_state(gpointer s) { TFCondState *state = (TFCondState *) s; if (state->filter) filter_expr_unref(state->filter); tf_simple_func_free_state(&state->super); } gboolean tf_grep_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFCondState *state = (TFCondState *) s; GOptionContext *ctx; gint max_count = 0; GOptionEntry grep_options[] = { { "max-count", 'm', 0, G_OPTION_ARG_INT, &max_count, NULL, NULL }, { NULL } }; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); ctx = g_option_context_new(argv[0]); g_option_context_add_main_entries(ctx, grep_options, NULL); if (!g_option_context_parse(ctx, &argc, &argv, error)) { g_option_context_free(ctx); g_free(argv); return FALSE; } g_option_context_free(ctx); if (argc < 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(%s) requires at least two arguments", argv[0]); return FALSE; } state->grep_max_count = max_count; return tf_cond_prepare(self, s, parent, argc, argv, error); } /* * $(grep [opts] filter $nv1 $n2 ...) * * Options: * --max-count or -m The maximum number of matches, 0 for unlimited */ void tf_grep_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { gint i, msg_ndx; gboolean first = TRUE; TFCondState *state = (TFCondState *) s; gint count = 0; *type = LM_VT_STRING; for (msg_ndx = 0; msg_ndx < args->num_messages; msg_ndx++) { LogMessage *msg = args->messages[msg_ndx]; if (filter_expr_eval(state->filter, msg)) { count++; for (i = 0; i < state->super.argc; i++) { if (!first) g_string_append_c(result, ','); /* NOTE: not recursive, as the message context is just one message */ log_template_append_format(state->super.argv_templates[i], msg, args->options, result); first = FALSE; } if (state->grep_max_count && count >= state->grep_max_count) break; } } } TEMPLATE_FUNCTION(TFCondState, tf_grep, tf_grep_prepare, NULL, tf_grep_call, tf_cond_free_state, NULL); gboolean tf_if_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (argc != 4) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(if) requires three arguments"); return FALSE; } return tf_cond_prepare(self, s, parent, argc, argv, error); } void tf_if_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFCondState *state = (TFCondState *) s; if (filter_expr_eval_with_context(state->filter, args->messages, args->num_messages, args->options)) { log_template_append_format_value_and_type_with_context(state->super.argv_templates[0], args->messages, args->num_messages, args->options, result, type); } else { log_template_append_format_value_and_type_with_context(state->super.argv_templates[1], args->messages, args->num_messages, args->options, result, type); } } TEMPLATE_FUNCTION(TFCondState, tf_if, tf_if_prepare, NULL, tf_if_call, tf_cond_free_state, NULL); static void tf_or (LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { if (argv[i]->len == 0) continue; g_string_append_len (result, argv[i]->str, argv[i]->len); break; } } TEMPLATE_FUNCTION_SIMPLE(tf_or); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/context-funcs.c000066400000000000000000000102451450431004300241110ustar00rootroot00000000000000/* * Copyright (c) 2012-2016 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ static gboolean tf_context_length_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { return TRUE; } static void tf_context_length_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { g_string_append_printf(result, "%d", args->num_messages); *type = LM_VT_INTEGER; } static void tf_context_length_free_state(gpointer s) { } TEMPLATE_FUNCTION(NULL, tf_context_length, tf_context_length_prepare, NULL, tf_context_length_call, tf_context_length_free_state, NULL); /* * $(context-lookup [opts] filter $nv1 $n2 ...) * * Options: * --max-count or -m The maximum number of matches, 0 for unlimited * * Returns in a syslog-ng style list of all elements */ void tf_context_lookup_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { gboolean first = TRUE; TFCondState *state = (TFCondState *) s; gint count = 0; GString *buf = g_string_sized_new(64); *type = LM_VT_LIST; for (gint msg_ndx = 0; msg_ndx < args->num_messages; msg_ndx++) { LogMessage *msg = args->messages[msg_ndx]; if (filter_expr_eval(state->filter, msg)) { count++; for (gint i = 0; i < state->super.argc; i++) { if (!first) g_string_append_c(result, ','); /* NOTE: not recursive, as the message context is just one message */ log_template_format(state->super.argv_templates[i], msg, args->options, buf); str_repr_encode_append(result, buf->str, buf->len, ","); first = FALSE; } if (state->grep_max_count && count >= state->grep_max_count) break; } } g_string_free(buf, TRUE); } TEMPLATE_FUNCTION(TFCondState, tf_context_lookup, tf_grep_prepare, NULL, tf_context_lookup_call, tf_cond_free_state, NULL); /* * $(context-values $nv1 $n2 ...) * * Returns in a syslog-ng style list of all specified name value pairs in the entire context. */ void tf_context_values_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { gboolean first = TRUE; TFSimpleFuncState *state = (TFSimpleFuncState *) s; GString *buf = g_string_sized_new(64); *type = LM_VT_LIST; for (gint msg_ndx = 0; msg_ndx < args->num_messages; msg_ndx++) { LogMessage *msg = args->messages[msg_ndx]; for (gint i = 0; i < state->argc; i++) { if (!first) g_string_append_c(result, ','); /* NOTE: not recursive, as the message context is just one message */ log_template_format(state->argv_templates[i], msg, args->options, buf); str_repr_encode_append(result, buf->str, buf->len, ","); first = FALSE; } } g_string_free(buf, TRUE); } TEMPLATE_FUNCTION(TFSimpleFuncState, tf_context_values, tf_simple_func_prepare, tf_simple_func_eval, tf_context_values_call, tf_simple_func_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/fname-funcs.c000066400000000000000000000030301450431004300235050ustar00rootroot00000000000000/* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include static void tf_basename(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gchar *base; *type = LM_VT_STRING; base = g_path_get_basename(argv[0]->str); g_string_append(result, base); g_free(base); } TEMPLATE_FUNCTION_SIMPLE(tf_basename); static void tf_dirname(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gchar *dir; *type = LM_VT_STRING; dir = g_path_get_dirname(argv[0]->str); g_string_append(result, dir); g_free(dir); } TEMPLATE_FUNCTION_SIMPLE(tf_dirname); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/ip-funcs.c000066400000000000000000000125251450431004300230400ustar00rootroot00000000000000/* * Copyright (c) 2002-2012 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "gsocket.h" #include "host-resolve.h" #include "cfg-parser.h" static void tf_ipv4_to_int(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { struct in_addr ina; g_inet_aton(argv[i]->str, &ina); g_string_append_printf(result, "%lu", (gulong) ntohl(ina.s_addr)); if (i < argc - 1) g_string_append_c(result, ','); } } TEMPLATE_FUNCTION_SIMPLE(tf_ipv4_to_int); typedef struct _DnsResolveIpState { TFSimpleFuncState super; HostResolveOptions host_resolve_options; } DnsResolveIpState; static gboolean _process_use_fqdn(const gchar *option_name, const gchar *value, gpointer data, GError **error) { HostResolveOptions *host_resolve_options = (HostResolveOptions *)data; host_resolve_options->use_fqdn = cfg_process_yesno(value); return TRUE; } static gboolean _process_use_dns(const gchar *option_name, const gchar *value, gpointer data, GError **error) { HostResolveOptions *host_resolve_options = (HostResolveOptions *)data; host_resolve_options->use_dns = cfg_process_yesno(value); return TRUE; } static gboolean _process_dns_cache(const gchar *option_name, const gchar *value, gpointer data, GError **error) { HostResolveOptions *host_resolve_options = (HostResolveOptions *)data; host_resolve_options->use_dns_cache = cfg_process_yesno(value); return TRUE; } static gboolean _process_normalize_hostnames(const gchar *option_name, const gchar *value, gpointer data, GError **error) { HostResolveOptions *host_resolve_options = (HostResolveOptions *)data; host_resolve_options->normalize_hostnames = cfg_process_yesno(value); return TRUE; } static gboolean _parse_host_resolve_options(gint *argc, gchar **argv[], HostResolveOptions *host_resolve_options, GError **error) { gboolean result = FALSE; GOptionEntry entries[] = { { "use-fqdn", 'f', 0, G_OPTION_ARG_CALLBACK, _process_use_fqdn, NULL, NULL }, { "use-dns", 'd', 0, G_OPTION_ARG_CALLBACK, _process_use_dns, NULL, NULL }, { "dns-cache", 'c', 0, G_OPTION_ARG_CALLBACK, _process_dns_cache, NULL, NULL }, { "normalize-hostnames", 'n', 0, G_OPTION_ARG_CALLBACK, _process_normalize_hostnames, NULL, NULL }, { NULL } }; GOptionContext *ctx = g_option_context_new(*argv[0]); GOptionGroup *group = g_option_group_new("host-resolve-options", NULL, NULL, host_resolve_options, NULL); g_option_group_add_entries(group, entries); g_option_context_set_main_group(ctx, group); if (!g_option_context_parse(ctx, argc, argv, error)) goto exit; result = TRUE; exit: g_option_context_free(ctx); return result; } static gboolean _setup_host_resolve_options(DnsResolveIpState *state, LogTemplate *parent, gint *argc, gchar **argv[], GError **error) { host_resolve_options_defaults(&state->host_resolve_options); if (!_parse_host_resolve_options(argc, argv, &state->host_resolve_options, error)) return FALSE; host_resolve_options_init(&state->host_resolve_options, &parent->cfg->host_resolve_options); return TRUE; } static gboolean tf_dns_resolve_ip_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { DnsResolveIpState *state = (DnsResolveIpState *)s; if (!_setup_host_resolve_options(state, parent, &argc, &argv, error)) return FALSE; if (argc > 2) { g_set_error(error, LOG_TEMPLATE_ERROR, 0, "dns-resolve-ip: too many arguments provided. usage: $(dns-resolve-ip [OPTIONS] IP)"); return FALSE; } if (!tf_simple_func_prepare(self, s, parent, argc, argv, error)) return FALSE; return TRUE; } static void tf_dns_resolve_ip_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { DnsResolveIpState *state = (DnsResolveIpState *)s; const gchar *hostname; gsize result_len; *type = LM_VT_STRING; gchar *ip = args->argv[0]->str; GSockAddr *addr = g_sockaddr_inet_or_inet6_new(ip, 0); if (!addr) return; hostname = resolve_sockaddr_to_hostname(&result_len, addr, &state->host_resolve_options); g_string_append_len(result, hostname, result_len); g_sockaddr_unref(addr); } TEMPLATE_FUNCTION(DnsResolveIpState, tf_dns_resolve_ip, tf_dns_resolve_ip_prepare, tf_simple_func_eval, tf_dns_resolve_ip_call, tf_simple_func_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/list-funcs.c000066400000000000000000000406241450431004300234040ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "scanner/list-scanner/list-scanner.h" #include "str-repr/encode.h" #include "compat/pcre.h" static void _append_comma_between_list_elements_if_needed(GString *result, gsize initial_len) { /* we won't insert a comma at the very first position we were invoked at */ if (result->len == initial_len) return; if (result->str[result->len - 1] != ',') g_string_append_c(result, ','); } static void tf_list_concat(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { ListScanner scanner; gsize initial_len = result->len; *type = LM_VT_LIST; list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, argc, argv); while (list_scanner_scan_next(&scanner)) { _append_comma_between_list_elements_if_needed(result, initial_len); str_repr_encode_append(result, list_scanner_get_current_value(&scanner), -1, ","); } list_scanner_deinit(&scanner); } TEMPLATE_FUNCTION_SIMPLE(tf_list_concat); static void tf_list_append(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gsize initial_len = result->len; *type = LM_VT_LIST; if (argc == 0) return; g_string_append_len(result, argv[0]->str, argv[0]->len); for (gint i = 1; i < argc; i++) { _append_comma_between_list_elements_if_needed(result, initial_len); str_repr_encode_append(result, argv[i]->str, argv[i]->len, ","); } } TEMPLATE_FUNCTION_SIMPLE(tf_list_append); static gint _list_count(gint argc, GString *argv[]) { ListScanner scanner; gint count = 0; if (argc != 0) { list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, argc, argv); while (list_scanner_scan_next(&scanner)) count++; list_scanner_deinit(&scanner); } return count; } static void _translate_negative_list_slice_indices(gint argc, GString *argv[], gint *first_ndx, gint *last_ndx) { gint count = -1; if (*first_ndx < 0 || *last_ndx < 0) count = _list_count(argc, argv); if (*first_ndx < 0) *first_ndx += count; if (*last_ndx < 0) *last_ndx += count; } static void _list_slice(gint argc, GString *argv[], GString *result, gint first_ndx, gint last_ndx) { ListScanner scanner; gsize initial_len = result->len; gint i; if (argc == 0) return; _translate_negative_list_slice_indices(argc, argv, &first_ndx, &last_ndx); /* NOTE: first_ndx and last_ndx may be negative, so these loops must cover * that case, by interpreting negative first_ndx as "0", and negative * last_ndx as "0". * * $(list-slice -100: a,b,c) - should return "a,b,c" * $(list-slice :-100 a,b,c) - should return "" */ list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, argc, argv); i = 0; while (i < first_ndx && list_scanner_scan_next(&scanner)) i++; while (i >= first_ndx && i < last_ndx && list_scanner_scan_next(&scanner)) { _append_comma_between_list_elements_if_needed(result, initial_len); str_repr_encode_append(result, list_scanner_get_current_value(&scanner), -1, ","); i++; } list_scanner_deinit(&scanner); } static void _translate_negative_list_index(gint argc, GString *argv[], gint *ndx) { if (*ndx < 0) *ndx += _list_count(argc, argv); } static void _list_nth(gint argc, GString *argv[], GString *result, gint ndx) { ListScanner scanner; gint i; if (argc == 0) return; list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, argc, argv); _translate_negative_list_index(argc, argv, &ndx); i = 0; while (i < ndx && list_scanner_scan_next(&scanner)) i++; if (i == ndx && list_scanner_scan_next(&scanner)) { g_string_append(result, list_scanner_get_current_value(&scanner)); } list_scanner_deinit(&scanner); } /* * Take off the first item of the list, unencoded. */ static void tf_list_head(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { *type = LM_VT_STRING; _list_nth(argc, argv, result, 0); } TEMPLATE_FUNCTION_SIMPLE(tf_list_head); static void tf_list_nth(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint64 ndx = 0; const gchar *ndx_spec; *type = LM_VT_STRING; if (argc < 1) return; ndx_spec = argv[0]->str; /* get start position from first argument */ if (!parse_int64(ndx_spec, &ndx)) { msg_error("$(list-nth) parsing failed, index must be the first argument", evt_tag_str("ndx", ndx_spec)); return; } _list_nth(argc - 1, &argv[1], result, ndx); } TEMPLATE_FUNCTION_SIMPLE(tf_list_nth); static void tf_list_tail(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { *type = LM_VT_STRING; if (argc == 0) return; _list_slice(argc, argv, result, 1, INT_MAX); } TEMPLATE_FUNCTION_SIMPLE(tf_list_tail); static void tf_list_count(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint count = _list_count(argc, argv); *type = LM_VT_INTEGER; format_uint32_padded(result, -1, ' ', 10, count); } TEMPLATE_FUNCTION_SIMPLE(tf_list_count); /* $(list-slice FIRST:LAST list ...) */ static void tf_list_slice(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint64 first_ndx = 0, last_ndx = INT_MAX; const gchar *slice_spec, *first_spec, *last_spec; gchar *colon; *type = LM_VT_LIST; if (argc < 1) return; slice_spec = argv[0]->str; first_spec = slice_spec; colon = strchr(first_spec, ':'); if (colon) { last_spec = colon + 1; *colon = 0; } else last_spec = NULL; /* get start position from first argument */ if (first_spec && first_spec[0] && !parse_int64(first_spec, &first_ndx)) { msg_error("$(list-slice) parsing failed, first could not be parsed", evt_tag_str("start", first_spec)); return; } /* get last position from second argument */ if (last_spec && last_spec[0] && !parse_int64(last_spec, &last_ndx)) { msg_error("$(list-slice) parsing failed, last could not be parsed", evt_tag_str("last", last_spec)); return; } _list_slice(argc - 1, &argv[1], result, (gint) first_ndx, (gint) last_ndx); } TEMPLATE_FUNCTION_SIMPLE(tf_list_slice); static void tf_explode(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gsize initial_len = result->len; GString *separator; *type = LM_VT_LIST; if (argc < 1) return; separator = argv[0]; for (gint i = 1; i < argc; i++) { gchar **strv = g_strsplit(argv[i]->str, separator->str, -1); for (gchar **str = &strv[0]; *str != NULL; str++) { _append_comma_between_list_elements_if_needed(result, initial_len); str_repr_encode_append(result, *str, -1, ","); } g_strfreev(strv); } } TEMPLATE_FUNCTION_SIMPLE(tf_explode); static void tf_implode(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { ListScanner scanner; gsize initial_len = result->len; GString *separator; *type = LM_VT_STRING; if (argc < 1) return; separator = argv[0]; list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, argc - 1, &argv[1]); while (list_scanner_scan_next(&scanner)) { if (result->len > initial_len) g_string_append_len(result, separator->str, separator->len); g_string_append_len(result, list_scanner_get_current_value(&scanner), list_scanner_get_current_value_len(&scanner)); } list_scanner_deinit(&scanner); } TEMPLATE_FUNCTION_SIMPLE(tf_implode); typedef enum _StringMatchMode { SMM_LITERAL = 0, SMM_PREFIX, SMM_SUBSTRING, SMM_GLOB, SMM_PCRE } StringMatchMode; typedef struct _StringMatcher { StringMatchMode mode; gchar *pattern; GPatternSpec *glob; pcre2_code *pcre; } StringMatcher; static gboolean string_matcher_prepare_glob(StringMatcher *self) { self->glob = g_pattern_spec_new(self->pattern); return TRUE; } static gboolean string_matcher_prepare_pcre(StringMatcher *self) { PCRE2_SIZE erroffset; gint rc; self->pcre = pcre2_compile((PCRE2_SPTR) self->pattern, PCRE2_ZERO_TERMINATED, PCRE2_ANCHORED, &rc, &erroffset, NULL); if (!self->pcre) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); msg_error("Error while compiling regular expression", evt_tag_str("regular_expression", self->pattern), evt_tag_str("error_at", &self->pattern[erroffset]), evt_tag_int("error_offset", erroffset), evt_tag_str("error_message", (gchar *) error_message), evt_tag_int("error_code", rc)); return FALSE; } /* optimize regexp */ rc = pcre2_jit_compile(self->pcre, PCRE2_JIT_COMPLETE); if (rc < 0) { PCRE2_UCHAR error_message[128]; pcre2_get_error_message(rc, error_message, sizeof(error_message)); msg_warning("$(list-search): Failed to JIT compile regular expression", evt_tag_str("regexp", self->pattern), evt_tag_str("error", (gchar *) error_message)); } return TRUE; } static gboolean string_matcher_prepare(StringMatcher *self) { switch (self->mode) { case SMM_GLOB: return string_matcher_prepare_glob(self); case SMM_PCRE: return string_matcher_prepare_pcre(self); default: return TRUE; } } static gboolean string_matcher_match_pcre(StringMatcher *self, const char *string, gsize string_len) { pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(self->pcre, NULL); gint rc = pcre2_match(self->pcre, (PCRE2_SPTR) string, (PCRE2_SIZE) string_len, 0, 0, match_data, NULL); pcre2_match_data_free(match_data); if (rc == PCRE2_ERROR_NOMATCH) { return FALSE; } if (rc < 0) { msg_error("Error while matching pcre", evt_tag_int("error_code", rc)); return FALSE; } return TRUE; } static gboolean string_matcher_match(StringMatcher *self, const char *string, gsize string_len) { switch (self->mode) { case SMM_LITERAL: return (strcmp(string, self->pattern) == 0); case SMM_PREFIX: return (strncmp(string, self->pattern, strlen(self->pattern)) == 0); case SMM_SUBSTRING: return (strstr(string, self->pattern) != NULL); case SMM_GLOB: return (g_pattern_match_string(self->glob, string)); case SMM_PCRE: return (string_matcher_match_pcre(self, string, string_len)); default: g_assert_not_reached(); } } static StringMatcher * string_matcher_new(StringMatchMode mode, const gchar *pattern) { StringMatcher *self = g_new0(StringMatcher, 1); self->mode = mode; self->pattern = g_strdup(pattern); return self; } static void string_matcher_free(StringMatcher *self) { if (self->pattern) g_free(self->pattern); if (self->glob) g_pattern_spec_free(self->glob); if (self->pcre) pcre2_code_free(self->pcre); g_free(self); } typedef struct _ListSearchState { TFSimpleFuncState super; StringMatcher *matcher; gint start_index; } ListSearchState; static void list_search_state_free(gpointer s) { ListSearchState *self = (ListSearchState *)s; if (self->matcher) string_matcher_free(self->matcher); tf_simple_func_free_state(&self->super); } static gboolean _list_search_mode_str_to_string_match_mode(const gchar *mode_str, StringMatchMode *string_match_mode) { gboolean result = TRUE; if (mode_str == NULL || strcmp(mode_str, "literal") == 0) *string_match_mode = SMM_LITERAL; else if (strcmp(mode_str, "prefix") == 0) *string_match_mode = SMM_PREFIX; else if (strcmp(mode_str, "substring") == 0) *string_match_mode = SMM_SUBSTRING; else if (strcmp(mode_str, "glob") == 0) *string_match_mode = SMM_GLOB; else if (strcmp(mode_str, "pcre") == 0) *string_match_mode = SMM_PCRE; else result = FALSE; return result; } static gboolean _list_search_parse_options(StringMatchMode *mode, gint *start_index, gint *argc, gchar **argv[], GError **error) { gboolean result = FALSE; GOptionContext *ctx; gchar *mode_str = NULL; GOptionEntry list_search_options[] = { { "mode", 0, 0, G_OPTION_ARG_STRING, &mode_str, NULL, NULL }, { "start-index", 0, 0, G_OPTION_ARG_INT, start_index, NULL, NULL }, { NULL } }; ctx = g_option_context_new((*argv)[0]); g_option_context_add_main_entries(ctx, list_search_options, NULL); if (!g_option_context_parse(ctx, argc, argv, error)) { goto exit; } if (!_list_search_mode_str_to_string_match_mode(mode_str, mode)) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(list-search) Invalid list-search mode: %s. " "Valid modes are: literal, prefix, substring, glob, pcre", mode_str); goto exit; } result = TRUE; exit: g_free(mode_str); g_option_context_free(ctx); return result; } static gboolean _list_search_init_matcher(ListSearchState *state, StringMatchMode mode, gint argc, gchar *argv[], GError **error) { if (argc < 2) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(list-search) Pattern is missing. Usage: $(list-search [options] ${list})"); return FALSE; } else if (argc < 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(list-search) List is missing. Usage: $(list-search [options] ${list}"); return FALSE; } gchar *pattern = argv[1]; state->matcher = string_matcher_new(mode, pattern); if (!string_matcher_prepare(state->matcher)) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(list-search) Failed to prepare pattern: %s", pattern); return FALSE; } return TRUE; } static gboolean tf_list_search_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { ListSearchState *state = (ListSearchState *)s; StringMatchMode mode; if (!_list_search_parse_options(&mode, &state->start_index, &argc, &argv, error)) return FALSE; if (!_list_search_init_matcher(state, mode, argc, argv, error)) return FALSE; if (!tf_simple_func_prepare(self, state, parent, argc, argv, error)) return FALSE; return TRUE; } static void tf_list_search_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { ListSearchState *state = (ListSearchState *)s; ListScanner scanner; gint index = state->start_index; *type = LM_VT_INTEGER; list_scanner_init(&scanner); list_scanner_input_gstring_array(&scanner, state->super.argc - 1, &args->argv[1]); list_scanner_skip_n(&scanner, index); while (list_scanner_scan_next(&scanner)) { if (string_matcher_match(state->matcher, list_scanner_get_current_value(&scanner), list_scanner_get_current_value_len(&scanner))) { format_int32_padded(result, -1, ' ', 10, index); break; } index++; } list_scanner_deinit(&scanner); } TEMPLATE_FUNCTION(ListSearchState, tf_list_search, tf_list_search_prepare, tf_simple_func_eval, tf_list_search_call, list_search_state_free, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/misc-funcs.c000066400000000000000000000024311450431004300233560ustar00rootroot00000000000000/* * Copyright (c) 2012 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ static void tf_env(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { char *val = getenv(argv[i]->str); if (!val) continue; g_string_append(result, val); if (i < argc - 1) g_string_append_c(result, ' '); } } TEMPLATE_FUNCTION_SIMPLE(tf_env); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/numeric-funcs.c000066400000000000000000000336531450431004300240770ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "generic-number.h" #include typedef gboolean (*AggregateFunc)(gpointer, gint64); void format_number(GString *result, LogMessageValueType *type, const GenericNumber *n) { if (n->type == GN_INT64) { *type = LM_VT_INTEGER; format_int64_padded(result, 0, ' ', 10, gn_as_int64(n)); return; } *type = LM_VT_DOUBLE; g_string_append_printf(result, "%.*f", n->precision, gn_as_double(n)); } void format_nan(GString *result, LogMessageValueType *type) { g_string_append_len(result, "NaN", 3); *type = LM_VT_DOUBLE; } static gboolean tf_num_parse(gint argc, GString *argv[], const gchar *func_name, GenericNumber *n, GenericNumber *m) { if (argc != 2) { msg_debug("Template function requires two arguments.", evt_tag_str("function", func_name)); return FALSE; } if (!parse_generic_number(argv[0]->str, n)) { msg_debug("Parsing failed, template function's first argument is not a number", evt_tag_str("function", func_name), evt_tag_str("arg1", argv[0]->str)); return FALSE; } if (!parse_generic_number(argv[1]->str, m)) { msg_debug("Parsing failed, template function's second argument is not a number", evt_tag_str("function", func_name), evt_tag_str("arg2", argv[1]->str)); return FALSE; } return TRUE; } static void tf_num_plus(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n, m, res; if (!tf_num_parse(argc, argv, "+", &n, &m)) { format_nan(result, type); return; } if (n.type == GN_INT64 && m.type == GN_INT64) { gn_set_int64(&res, gn_as_int64(&n) + gn_as_int64(&m)); } else { gn_set_double(&res, gn_as_double(&n) + gn_as_double(&m), -1); } format_number(result, type, &res); } TEMPLATE_FUNCTION_SIMPLE(tf_num_plus); static void tf_num_minus(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n, m, res; if (!tf_num_parse(argc, argv, "-", &n, &m)) { format_nan(result, type); return; } if (n.type == GN_INT64 && m.type == GN_INT64) { gn_set_int64(&res, gn_as_int64(&n) - gn_as_int64(&m)); } else { gn_set_double(&res, gn_as_double(&n) - gn_as_double(&m), -1); } format_number(result, type, &res); } TEMPLATE_FUNCTION_SIMPLE(tf_num_minus); static void tf_num_multi(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n, m, res; if (!tf_num_parse(argc, argv, "*", &n, &m)) { format_nan(result, type); return; } if (n.type == GN_INT64 && m.type == GN_INT64) { gn_set_int64(&res, gn_as_int64(&n) * gn_as_int64(&m)); } else { gn_set_double(&res, gn_as_double(&n) * gn_as_double(&m), -1); } format_number(result, type, &res); } TEMPLATE_FUNCTION_SIMPLE(tf_num_multi); static void tf_num_div(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n, m, res; if (!tf_num_parse(argc, argv, "/", &n, &m) || gn_is_zero(&m)) { format_nan(result, type); return; } if (n.type == GN_INT64 && m.type == GN_INT64) { gn_set_int64(&res, gn_as_int64(&n) / gn_as_int64(&m)); } else { gn_set_double(&res, gn_as_double(&n) / gn_as_double(&m), -1); } format_number(result, type, &res); } TEMPLATE_FUNCTION_SIMPLE(tf_num_div); static void tf_num_mod(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n, m, res; if (!tf_num_parse(argc, argv, "%", &n, &m) || gn_is_zero(&m)) { format_nan(result, type); return; } if (n.type == GN_INT64 && m.type == GN_INT64) { gn_set_int64(&res, gn_as_int64(&n) % gn_as_int64(&m)); } else { gn_set_double(&res, fmod(gn_as_double(&n), gn_as_double(&m)), -1); } format_number(result, type, &res); } TEMPLATE_FUNCTION_SIMPLE(tf_num_mod); static void tf_num_round(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n; gint64 precision = 0; if (argc < 1 || argc > 2) { msg_debug("Template function requires exactly one or two arguments.", evt_tag_str("function", "round")); format_nan(result, type); return; } if (!parse_generic_number(argv[0]->str, &n)) { msg_debug("Parsing failed, template function's first argument is not a number", evt_tag_str("function", "round"), evt_tag_str("arg1", argv[0]->str)); format_nan(result, type); return; } if (argc > 1) { if (!parse_int64(argv[1]->str, &precision)) { msg_debug("Parsing failed, template function's second argument is not a number", evt_tag_str("function", "round"), evt_tag_str("arg2", argv[1]->str)); format_nan(result, type); return; } if (precision < 0 || precision > 20) { msg_debug("Parsing failed, precision is not in the supported range (0..20)", evt_tag_str("function", "round"), evt_tag_str("arg2", argv[1]->str)); format_nan(result, type); return; } } double multiplier = pow(10, precision); double res = round(gn_as_double(&n) * multiplier) / multiplier; gn_set_double(&n, res, -1); /* * gn_set_double() resets the precision, so assign it now. */ n.precision = precision; format_number(result, type, &n); } TEMPLATE_FUNCTION_SIMPLE(tf_num_round); static void tf_num_ceil(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n; if (argc != 1) { msg_debug("Template function requires one argument.", evt_tag_str("function", "ceil")); format_nan(result, type); return; } if (!parse_generic_number(argv[0]->str, &n)) { msg_debug("Parsing failed, template function's first argument is not a number", evt_tag_str("function", "ceil"), evt_tag_str("arg1", argv[0]->str)); format_nan(result, type); return; } *type = LM_VT_INTEGER; gdouble number = ceil(gn_as_double(&n)); gn_set_int64(&n, (gint64) number); format_number(result, type, &n); } TEMPLATE_FUNCTION_SIMPLE(tf_num_ceil); static void tf_num_floor(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { GenericNumber n; if (argc != 1) { msg_debug("Template function requires one argument.", evt_tag_str("function", "floor")); format_nan(result, type); return; } if (!parse_generic_number(argv[0]->str, &n)) { msg_debug("Parsing failed, template function's first argument is not a number", evt_tag_str("function", "floor"), evt_tag_str("arg1", argv[0]->str)); format_nan(result, type); return; } *type = LM_VT_INTEGER; gdouble number = floor(gn_as_double(&n)); gn_set_int64(&n, (gint64) number); format_number(result, type, &n); } TEMPLATE_FUNCTION_SIMPLE(tf_num_floor); static gboolean _tf_num_parse_arg_with_message(const TFSimpleFuncState *state, LogMessage *message, const LogTemplateInvokeArgs *args, gint64 *number) { GString *formatted_template = scratch_buffers_alloc(); gint on_error = args->options->opts->on_error; log_template_format(state->argv_templates[0], message, args->options, formatted_template); if (!parse_int64(formatted_template->str, number)) { if (!(on_error & ON_ERROR_SILENT)) msg_error("Parsing failed, template function's argument is not a number", evt_tag_str("arg", formatted_template->str)); return FALSE; } return TRUE; } static gboolean tf_num_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (argc != 2) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(%s) requires only one argument", argv[0]); return FALSE; } return tf_simple_func_prepare(self, s, parent, argc, argv, error); } static gint _tf_num_filter_iterate(const TFSimpleFuncState *state, const LogTemplateInvokeArgs *args, gint message_index, AggregateFunc aggregate, gpointer accumulator) { for (; message_index < args->num_messages; message_index++) { LogMessage *message = args->messages[message_index]; gint64 number; if ((_tf_num_parse_arg_with_message(state, message, args, &number) && (!aggregate(accumulator, number)))) return message_index; } return -1; } static gboolean _tf_num_filter(const TFSimpleFuncState *state, const LogTemplateInvokeArgs *args, AggregateFunc start, AggregateFunc aggregate, gpointer accumulator) { gint first = _tf_num_filter_iterate(state, args, 0, start, accumulator); if (first < 0) return FALSE; _tf_num_filter_iterate(state, args, first + 1, aggregate, accumulator); return TRUE; } static gboolean _tf_num_store_first(gpointer accumulator, gint64 element) { gint64 *acc = (gint64 *)accumulator; *acc = element; return FALSE; } static void _tf_num_aggregation(TFSimpleFuncState *state, const LogTemplateInvokeArgs *args, AggregateFunc aggregate, GString *result, LogMessageValueType *type) { gint64 accumulator; if (!_tf_num_filter(state, args, _tf_num_store_first, aggregate, &accumulator)) { /* invalid arguments, empty string */ *type = LM_VT_NULL; return; } *type = LM_VT_INTEGER; format_int64_padded(result, 0, ' ', 10, accumulator); } static gboolean _tf_num_sum(gpointer accumulator, gint64 element) { gint64 *acc = (gint64 *)accumulator; *acc += element; return TRUE; } static void tf_num_sum_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { _tf_num_aggregation((TFSimpleFuncState *) s, args, _tf_num_sum, result, type); } TEMPLATE_FUNCTION(TFSimpleFuncState, tf_num_sum, tf_num_prepare, NULL, tf_num_sum_call, tf_simple_func_free_state, NULL); static gboolean _tf_num_minimum(gpointer accumulator, gint64 element) { gint64 *acc = (gint64 *)accumulator; if (element < *acc) *acc = element; return TRUE; } static void tf_num_min_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { _tf_num_aggregation((TFSimpleFuncState *) s, args, _tf_num_minimum, result, type); } TEMPLATE_FUNCTION(TFSimpleFuncState, tf_num_min, tf_num_prepare, NULL, tf_num_min_call, tf_simple_func_free_state, NULL); static gboolean _tf_num_maximum(gpointer accumulator, gint64 element) { gint64 *acc = (gint64 *)accumulator; if (element > *acc) *acc = element; return TRUE; } static void tf_num_max_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { _tf_num_aggregation((TFSimpleFuncState *) s, args, _tf_num_maximum, result, type); } TEMPLATE_FUNCTION(TFSimpleFuncState, tf_num_max, tf_num_prepare, NULL, tf_num_max_call, tf_simple_func_free_state, NULL); typedef struct _AverageState { gint count; gint64 sum; } AverageState; static gboolean _tf_num_store_average_first(gpointer accumulator, gint64 element) { AverageState *state = (AverageState *) accumulator; state->count = 1; state->sum = element; return FALSE; } static gboolean _tf_num_average(gpointer accumulator, gint64 element) { AverageState *state = (AverageState *) accumulator; ++state->count; state->sum += element; return TRUE; } static void tf_num_average_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFSimpleFuncState *state = (TFSimpleFuncState *)s; AverageState accumulator = {0, 0}; if (!_tf_num_filter(state, args, _tf_num_store_average_first, _tf_num_average, &accumulator)) { *type = LM_VT_NULL; return; } /* _tf_num_filter() would return FALSE if there are no elements, so * handling this case with assert is fine */ g_assert(accumulator.count > 0); *type = LM_VT_INTEGER; gint64 mean = accumulator.sum / accumulator.count; format_int64_padded(result, 0, ' ', 10, mean); } TEMPLATE_FUNCTION(TFSimpleFuncState, tf_num_average, tf_num_prepare, NULL, tf_num_average_call, tf_simple_func_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/str-funcs.c000066400000000000000000000435631450431004300232460ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2012 Balázs Scheidler * Copyright (c) 2014 Viktor Tusa * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include static void tf_echo(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { *type = LM_VT_STRING; _append_args_with_separator(argc, argv, result, ' '); } TEMPLATE_FUNCTION_SIMPLE(tf_echo); static void tf_length(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_INTEGER; for (i = 0; i < argc; i++) { format_uint32_padded(result, 0, 0, 10, argv[i]->len); if (i < argc - 1) g_string_append_c(result, ' '); } } TEMPLATE_FUNCTION_SIMPLE(tf_length); /* * $(substr $arg START [LEN]) */ static void tf_substr(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint64 start, len; *type = LM_VT_STRING; /* * We need to cast argv[0]->len, which is gsize (so unsigned) type, to a * signed type, so we can compare negative offsets/lengths with string * length. But if argv[0]->len is bigger than G_MAXLONG, this can lead to * completely wrong calculations, so we'll just return nothing (alternative * would be to return original string and perhaps print an error...) */ if (argv[0]->len >= G_MAXLONG) { msg_error("$(substr) error: string is too long"); return; } /* check number of arguments */ if (argc < 2 || argc > 3) return; /* get offset position from second argument */ if (!parse_int64(argv[1]->str, &start)) { msg_error("$(substr) parsing failed, start could not be parsed", evt_tag_str("start", argv[1]->str)); return; } /* if we were called with >2 arguments, third was desired length */ if (argc > 2) { if (!parse_int64(argv[2]->str, &len)) { msg_error("$(substr) parsing failed, length could not be parsed", evt_tag_str("length", argv[2]->str)); return; } } else len = (glong)argv[0]->len; /* * if requested substring length is negative and beyond string start, do nothing; * also if it is greater than string length, limit it to string length */ if (len < 0 && -(len) > (glong)argv[0]->len) return; else if (len > (glong)argv[0]->len) len = (glong)argv[0]->len; /* * if requested offset is beyond string length, do nothing; * also, if offset is negative and "before" string beginning, do nothing * (or should we perhaps align start with the beginning instead?) */ if (start >= (glong)argv[0]->len) return; else if (start < 0 && -(start) > (glong)argv[0]->len) return; /* with negative length, see if we don't end up with start > end */ if (len < 0 && ((start < 0 && start > len) || (start >= 0 && (len + ((glong)argv[0]->len) - start) < 0))) return; /* if requested offset is negative, move start it accordingly */ if (start < 0) { start = start + (glong)argv[0]->len; /* * this shouldn't actually happen, as earlier we tested for * (start < 0 && -start > argv0len), but better safe than sorry */ if (start < 0) start = 0; } /* * if requested length is negative, "resize" len to include exactly as many * characters as needed from the end of the string, given our start position. * (start is always non-negative here already) */ if (len < 0) { len = ((glong)argv[0]->len) - start + len; /* this also shouldn't happen, but - again - better safe than sorry */ if (len < 0) return; } /* if we're beyond string end, do nothing */ if (start >= (glong)argv[0]->len) return; /* if we want something beyond string end, do it only till the end */ if (start + len > (glong)argv[0]->len) len = ((glong)argv[0]->len) - start; /* skip g_string_append_len if we ended up having to extract 0 chars */ if (len == 0) return; g_string_append_len(result, argv[0]->str + start, len); } TEMPLATE_FUNCTION_SIMPLE(tf_substr); /* * $(strip $arg1 $arg2 ...) */ static void tf_strip(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gsize initial_len = result->len; gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { if (argv[i]->len == 0) continue; gint spaces_end = 0; while (isspace(argv[i]->str[argv[i]->len - spaces_end - 1]) && spaces_end < argv[i]->len) spaces_end++; if (argv[i]->len == spaces_end) continue; gint spaces_start = 0; while (isspace(argv[i]->str[spaces_start])) spaces_start++; if (result->len > initial_len) g_string_append_c(result, ' '); g_string_append_len(result, &argv[i]->str[spaces_start], argv[i]->len - spaces_end - spaces_start); } } TEMPLATE_FUNCTION_SIMPLE(tf_strip); /* * $(sanitize [opts] $arg1 $arg2 ...) * * Options: * --ctrl-chars or -c Filter control characters (default) * --no-ctrl-chars or -C Don't filter control characters * --invalid-chars or -i Set of characters to be translated, default "/" * --replacement or -r Single character replacement for invalid chars. */ typedef struct _TFSanitizeState { TFSimpleFuncState super; gboolean ctrl_chars; gchar replacement; gchar *invalid_chars; } TFSanitizeState; static gboolean tf_sanitize_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFSanitizeState *state = (TFSanitizeState *) s; gboolean ctrl_chars = TRUE; gchar *invalid_chars = NULL; gchar *replacement = NULL; GOptionContext *ctx; GOptionEntry stize_options[] = { { "ctrl-chars", 'c', 0, G_OPTION_ARG_NONE, &ctrl_chars, NULL, NULL }, { "no-ctrl-chars", 'C', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &ctrl_chars, NULL, NULL }, { "invalid-chars", 'i', 0, G_OPTION_ARG_STRING, &invalid_chars, NULL, NULL }, { "replacement", 'r', 0, G_OPTION_ARG_STRING, &replacement, NULL, NULL }, { NULL } }; gboolean result = FALSE; ctx = g_option_context_new("sanitize-file"); g_option_context_add_main_entries(ctx, stize_options, NULL); if (!g_option_context_parse(ctx, &argc, &argv, error)) { g_option_context_free(ctx); goto exit; } g_option_context_free(ctx); invalid_chars = invalid_chars ? : g_strdup("/"); replacement = replacement ? : g_strdup("_"); if (!tf_simple_func_prepare(self, state, parent, argc, argv, error)) { goto exit; } state->ctrl_chars = ctrl_chars; state->invalid_chars = g_strdup(invalid_chars); state->replacement = replacement[0]; result = TRUE; exit: /* glib supplies us with duplicated strings that we are responsible for! */ g_free(invalid_chars); g_free(replacement); return result; } static void tf_sanitize_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFSanitizeState *state = (TFSanitizeState *) s; gint argc; gint i, pos; *type = LM_VT_STRING; argc = state->super.argc; for (i = 0; i < argc; i++) { for (pos = 0; pos < args->argv[i]->len; pos++) { guchar last_char = args->argv[i]->str[pos]; if ((state->ctrl_chars && last_char < 32) || (strchr(state->invalid_chars, (gchar) last_char) != NULL)) g_string_append_c(result, state->replacement); else g_string_append_c(result, last_char); } if (i < argc - 1) g_string_append_c(result, '/'); } } static void tf_sanitize_free_state(gpointer s) { TFSanitizeState *state = (TFSanitizeState *) s; g_free(state->invalid_chars); tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(TFSanitizeState, tf_sanitize, tf_sanitize_prepare, tf_simple_func_eval, tf_sanitize_call, tf_sanitize_free_state, NULL); void tf_indent_multi_line(LogMessage *msg, gint argc, GString *argv[], GString *text, LogMessageValueType *type) { gchar *p, *new_line; *type = LM_VT_STRING; /* append the message text(s) to the template string */ _append_args_with_separator(argc, argv, text, ' '); /* look up the \n-s and insert a \t after them */ p = text->str; new_line = memchr(p, '\n', text->len); while(new_line) { if (*(gchar *)(new_line + 1) != '\t') { g_string_insert_c(text, new_line - p + 1, '\t'); } new_line = memchr(new_line + 1, '\n', p + text->len - new_line); } } TEMPLATE_FUNCTION_SIMPLE(tf_indent_multi_line); void tf_lowercase(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { gchar *new = g_utf8_strdown(argv[i]->str, argv[i]->len); g_string_append(result, new); if (i < argc - 1) g_string_append_c(result, ' '); g_free(new); } } TEMPLATE_FUNCTION_SIMPLE(tf_lowercase); void tf_uppercase(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { gchar *new = g_utf8_strup(argv[i]->str, argv[i]->len); g_string_append(result, new); if (i < argc - 1) g_string_append_c(result, ' '); g_free(new); } } TEMPLATE_FUNCTION_SIMPLE(tf_uppercase); void tf_replace_delimiter(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gchar *haystack, *delimiters, new_delimiter; *type = LM_VT_STRING; if (argc != 3) { msg_error("$(replace-delimiter) parsing failed, wrong number of arguments"); return; } delimiters = argv[0]->str; new_delimiter = argv[1]->str[0]; haystack = g_strdup(argv[2]->str); g_string_append(result, g_strdelimit(haystack, delimiters, new_delimiter)); g_free(haystack); } TEMPLATE_FUNCTION_SIMPLE(tf_replace_delimiter); typedef struct _TFStringPaddingState { TFSimpleFuncState super; GString *padding_pattern; gint64 width; } TFStringPaddingState; static gboolean _padding_prepare_parse_state(TFStringPaddingState *state, gint argc, gchar **argv, GError **error) { if (argc < 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(padding) Not enough arguments, usage $(padding [padding string])"); return FALSE; } if (!parse_int64(argv[2], &state->width)) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Padding template function requires a number as second argument!"); return FALSE; } return TRUE; } static void _padding_prepare_fill_padding_pattern(TFStringPaddingState *state, gint argc, gchar **argv) { state->padding_pattern = g_string_sized_new(state->width); if (argc < 4) { g_string_printf(state->padding_pattern, "%*s", (int)(state->width), ""); } else { gint len = strlen(argv[3]); if (len < 1) { g_string_printf(state->padding_pattern, "%*s", (int)(state->width), ""); } else { gint repeat = state->width / len; // integer division! for (gint i = 0; i < repeat; i++) { g_string_append_len(state->padding_pattern, argv[3], len); } g_string_append_len(state->padding_pattern, argv[3], state->width - (repeat * len)); } } } static gboolean tf_string_padding_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFStringPaddingState *state = (TFStringPaddingState *) s; if (!_padding_prepare_parse_state(state, argc, argv, error)) return FALSE; _padding_prepare_fill_padding_pattern(state, argc, argv); if (!tf_simple_func_prepare(self, state, parent, 2, argv, error)) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "padding: prepare failed"); return FALSE; } return TRUE; } static void tf_string_padding_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFStringPaddingState *state = (TFStringPaddingState *) s; *type = LM_VT_STRING; if (args->argv[0]->len > state->width) { g_string_append_len(result, args->argv[0]->str, args->argv[0]->len); } else { g_string_append_len(result, state->padding_pattern->str, state->width - args->argv[0]->len); g_string_append_len(result, args->argv[0]->str, args->argv[0]->len); } } static void tf_string_padding_free_state(gpointer s) { TFStringPaddingState *state = (TFStringPaddingState *) s; if (state->padding_pattern) g_string_free(state->padding_pattern, TRUE); tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(TFStringPaddingState, tf_string_padding, tf_string_padding_prepare, tf_simple_func_eval, tf_string_padding_call, tf_string_padding_free_state, NULL); typedef struct _TFBinaryState { TFSimpleFuncState super; GString *octets; } TFBinaryState; static void tf_binary_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFBinaryState *state = (TFBinaryState *) s; *type = LM_VT_STRING; g_string_append_len(result, state->octets->str, state->octets->len); } static gboolean tf_binary_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFBinaryState *state = (TFBinaryState *) s; GString *octets = g_string_new(""); if (argc < 2) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(binary) Incorrect parameters, usage $(binary ...)"); goto error; } for (gint i = 1; i < argc; i++) { gint64 number; gchar *token = argv[i]; if (!parse_int64_base_any(token, &number)) { gchar *base = "dec"; if (token[0] == '0') { base = token[1] == 'x' ? "hex" : "oct"; } g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(binary) template function requires list of dec/hex/oct numbers as arguments, unable to parse %s as a %s number", token, base); goto error; } if (number > 0xFF) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(binary) template function only supports 8 bit values as characters, %" G_GUINT64_FORMAT " is above 255", number); goto error; } g_string_append_c(octets, (gchar) number); } if (!tf_simple_func_prepare(self, state, parent, argc, argv, error)) { goto error; } state->octets = octets; return TRUE; error: g_string_free(octets, TRUE); return FALSE; } static void tf_binary_free_state(gpointer s) { TFBinaryState *state = (TFBinaryState *) s; if (state->octets) g_string_free(state->octets, TRUE); tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(TFBinaryState, tf_binary, tf_binary_prepare, tf_simple_func_eval, tf_binary_call, tf_binary_free_state, NULL); static inline gsize _get_base64_encoded_size(gsize len) { return (len / 3 + 1) * 4 + 4; } static void tf_base64encode(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { gint i; gint state = 0; gint save = 0; gsize out_len = 0; gsize init_len = result->len; *type = LM_VT_STRING; for (i = 0; i < argc; i++) { /* expand the buffer and add space for the base64 encoded string */ g_string_set_size(result, init_len + out_len + _get_base64_encoded_size(argv[i]->len)); out_len += g_base64_encode_step((guchar *) argv[i]->str, argv[i]->len, FALSE /* break_lines */, result->str + init_len + out_len, &state, &save); } g_string_set_size(result, init_len + out_len + _get_base64_encoded_size(0)); #if !GLIB_CHECK_VERSION(2, 54, 0) /* NOTE: this is an ugly workaround for glib versions < 2.54 (which is * pretty recent and not widely available yet) to fix an encoding issue. * * This is the bug: * https://bugzilla.gnome.org/show_bug.cgi?id=780066 * * This is the fix: * https://gitlab.gnome.org/GNOME/glib/commits/35c0dd2755dbcea2539117cf33959a1a9e497f12 * * We basically set the c2 byte used in a base64 encode to zero, if only 1 * remaining byte is there. Read the bugreport for reasons. * * Yes, I've actually stumbled into this in the unit test and could easily * anyone. */ if (((unsigned char *) &save)[0] == 1) ((unsigned char *) &save)[2] = 0; #endif out_len += g_base64_encode_close(FALSE, result->str + init_len + out_len, &state, &save); g_string_set_size(result, init_len + out_len); }; TEMPLATE_FUNCTION_SIMPLE(tf_base64encode); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tests/000077500000000000000000000000001450431004300223055ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tests/CMakeLists.txt000066400000000000000000000001301450431004300250370ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test_basicfuncs DEPENDS syslogformat basicfuncs) syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tests/Makefile.am000066400000000000000000000005711450431004300243440ustar00rootroot00000000000000modules_basicfuncs_tests_TESTS = \ modules/basicfuncs/tests/test_basicfuncs EXTRA_DIST += modules/basicfuncs/tests/CMakeLists.txt check_PROGRAMS += ${modules_basicfuncs_tests_TESTS} modules_basicfuncs_tests_test_basicfuncs_CFLAGS = $(TEST_CFLAGS) modules_basicfuncs_tests_test_basicfuncs_LDADD = \ $(TEST_LDADD) \ $(PREOPEN_SYSLOGFORMAT) $(PREOPEN_BASICFUNCS) syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tests/test_basicfuncs.c000066400000000000000000000750571450431004300256460ustar00rootroot00000000000000/* * Copyright (c) 2010-2018 Balabit * Copyright (c) 2010-2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include #include "libtest/cr_template.h" #include "libtest/grab-logging.h" #include "apphook.h" #include "plugin.h" #include "cfg.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" static void add_dummy_template_to_configuration(void) { LogTemplate *dummy = log_template_new(configuration, "dummy"); cr_assert(log_template_compile(dummy, "dummy template expanded $HOST", NULL), "Unexpected error compiling dummy template"); cfg_tree_add_template(&configuration->tree, dummy); } static void _log_msg_free(gpointer data, gpointer user_data) { log_msg_unref((LogMessage *) data); } static GPtrArray * create_log_messages_with_values(const gchar *name, const gchar **values) { LogMessage *message; GPtrArray *messages = g_ptr_array_new(); const gchar **value; for (value = values; *value != NULL; ++value) { message = create_empty_message(); log_msg_set_value_by_name(message, name, *value, -1); g_ptr_array_add(messages, message); } return messages; } static void free_log_message_array(GPtrArray *messages) { g_ptr_array_foreach(messages, _log_msg_free, NULL); g_ptr_array_free(messages, TRUE); } const gchar * resolve_sockaddr_to_hostname(gsize *result_len, GSockAddr *saddr, const HostResolveOptions *host_resolve_options) { static const gchar *test_hostname = "resolved-TEST-host"; static const gchar *test_hostname_normalized = "resolved-test-host"; static const gchar *test_hostname_fqdn = "resolved-TEST-host.syslog.ng"; static const gchar *test_hostname_fqdn_normalized = "resolved-test-host.syslog.ng"; static const gchar *test_ip = "123.123.123.123"; const gchar *hostname; if (host_resolve_options->use_dns) { if (host_resolve_options->use_fqdn) { if (host_resolve_options->normalize_hostnames) hostname = test_hostname_fqdn_normalized; else hostname = test_hostname_fqdn; } else { if (host_resolve_options->normalize_hostnames) hostname = test_hostname_normalized; else hostname = test_hostname; } } else { hostname = test_ip; } *result_len = strlen(hostname); return hostname; } void setup(void) { app_startup(); init_template_tests(); add_dummy_template_to_configuration(); cfg_load_module(configuration, "basicfuncs"); } void teardown(void) { deinit_template_tests(); scratch_buffers_explicit_gc(); app_shutdown(); } TestSuite(basicfuncs, .init = setup, .fini = teardown); Test(basicfuncs, test_cond_funcs) { assert_template_format_with_context("$(grep 'facility(local3)' $PID)", "23323,23323"); assert_template_format_with_context("$(grep -m 1 'facility(local3)' $PID)", "23323"); assert_template_format_with_context("$(grep 'facility(local3)' $PID $PROGRAM)", "23323,syslog-ng,23323,syslog-ng"); assert_template_format_with_context("$(grep 'facility(local4)' $PID)", ""); assert_template_format_with_context("$(grep ('$FACILITY' eq 'local4') $PID)", ""); assert_template_format_with_context("$(grep ('$FACILITY(' eq 'local3(') $PID)", "23323,23323"); assert_template_format_with_context("$(grep ('$FACILITY(' eq 'local4)') $PID)", ""); assert_template_format_with_context("$(grep \\'$FACILITY\\'\\ eq\\ \\'local4\\' $PID)", ""); assert_template_format_with_context("$(if 'facility(local4)' alma korte)", "korte"); assert_template_format_with_context("$(if 'facility(local3)' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY\" lt \"local3\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY\" le \"local3\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY\" eq \"local3\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY\" ne \"local3\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY\" gt \"local3\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY\" ge \"local3\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" < \"19\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" <= \"19\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" == \"19\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" != \"19\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" > \"19\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" >= \"19\"' alma korte)", "alma"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" >= \"19\" and \"kicsi\" eq \"nagy\"' alma korte)", "korte"); assert_template_format_with_context("$(if '\"$FACILITY_NUM\" >= \"19\" or \"kicsi\" eq \"nagy\"' alma korte)", "alma"); assert_template_format_with_context("$(if program(\"slog-ng\" type(pcre)) alma korte)", "alma"); assert_template_format_with_context("$(grep 'facility(local3)' $PID)@0", "23323"); assert_template_format_with_context("$(grep 'facility(local3)' $PID)@1", "23323"); assert_template_format_with_context("$(grep 'facility(local3)' $PID)@2", ""); assert_template_format_with_context("$(or 1 \"\" 2)", "1"); assert_template_format_with_context("$(or \"\" 2)", "2"); assert_template_format_with_context("$(or \"\" \"\")", ""); assert_template_format_with_context("$(or)", ""); } Test(basicfuncs, test_str_funcs) { assert_template_format("$(ipv4-to-int $SOURCEIP)", "168496141"); assert_template_format("$(dns-resolve-ip --use-dns=no --dns-cache=no 123.123.123.123)", "123.123.123.123"); assert_template_format("$(dns-resolve-ip --use-dns=yes --dns-cache=yes 123.123.123.123)", "resolved-TEST-host"); assert_template_format("$(dns-resolve-ip --use-dns=yes --dns-cache=yes " "--normalize-hostnames=yes 123.123.123.123)", "resolved-test-host"); assert_template_format("$(dns-resolve-ip --use-dns=yes --dns-cache=yes " "--use-fqdn=yes 123.123.123.123)", "resolved-TEST-host.syslog.ng"); assert_template_format("$(dns-resolve-ip --use-dns=yes --dns-cache=yes " "--use-fqdn=yes --normalize-hostnames=yes 123.123.123.123)", "resolved-test-host.syslog.ng"); assert_template_format("$(dns-resolve-ip \"123.123.123.123\")", "resolved-TEST-host"); assert_template_format("$(dns-resolve-ip '123.123.123.123')", "resolved-TEST-host"); assert_template_format("$(dns-resolve-ip !!!invalid-ip-address!!!)", ""); #if SYSLOG_NG_ENABLE_IPV6 assert_template_format("$(dns-resolve-ip 1996::04:30)", "resolved-TEST-host"); #endif start_grabbing_messages(); assert_template_format("$(dns-resolve-ip --use-dns=no --dns-cache=yes 123.123.123.123)", "123.123.123.123"); assert_grabbed_log_contains("WARNING: With use-dns(no), dns-cache() will be forced to 'no' too!"); stop_grabbing_messages(); assert_template_format("$(length $HOST $PID)", "5 5"); assert_template_format("$(length $HOST)", "5"); assert_template_format("$(length)", ""); assert_template_format("$(substr $HOST 1 3)", "zor"); assert_template_format("$(substr $HOST 1)", "zorp"); assert_template_format("$(substr $HOST -1)", "p"); assert_template_format("$(substr $HOST -2 1)", "r"); assert_template_format("$(substr 'ssstring-shorter-than-the-specified-length' 2 1400)", "string-shorter-than-the-specified-length"); assert_template_format("$(strip ${APP.STRIP1})", "value"); assert_template_format("$(strip ${APP.STRIP2})", "value"); assert_template_format("$(strip ${APP.STRIP3})", "value"); assert_template_format("$(strip ${APP.STRIP4})", "value"); assert_template_format("$(strip ${APP.STRIP5})", ""); assert_template_format("$(strip ${APP.STRIP5} ${APP.STRIP1} ${APP.STRIP5})", "value"); assert_template_format("$(strip ${APP.STRIP1} ${APP.STRIP2} ${APP.STRIP3} ${APP.STRIP4} ${APP.STRIP5})", "value value value value"); assert_template_format("$(strip ŐRÜLT_ÍRÓ)", "ŐRÜLT_ÍRÓ"); /* Wide characters are accepted */ assert_template_format("$(strip ' \n\t\r a b \n\t\r ')", "a b"); assert_template_format("$(sanitize alma/bela)", "alma_bela"); assert_template_format("$(sanitize -r @ alma/bela)", "alma@bela"); assert_template_format("$(sanitize -i @ alma@bela)", "alma_bela"); assert_template_format("$(sanitize -i '@/l ' alma@/bela)", "a_ma__be_a"); assert_template_format("$(sanitize alma\x1b_bela)", "alma__bela"); assert_template_format("$(sanitize -C alma\x1b_bela)", "alma\x1b_bela"); assert_template_format("$(sanitize $HOST $PROGRAM)", "bzorp/syslog-ng"); assert_template_failure("$(sanitize ${missingbrace)", "Invalid macro, '}' is missing, error_pos='14'"); assert_template_format("$(indent-multi-line 'foo\nbar')", "foo\n\tbar"); assert_template_format("$(lowercase ŐRÜLT ÍRÓ)", "őrült író"); assert_template_format("$(uppercase őrült író)", "ŐRÜLT ÍRÓ"); assert_template_format("$(replace-delimiter \"\t\" \",\" \"hello\tworld\")", "hello,world"); assert_template_format("$(padding foo 10)", " foo"); assert_template_format("$(padding foo 10 x)", "xxxxxxxfoo"); assert_template_format("$(padding foo 10 abc)", "abcabcafoo"); assert_template_format("$(padding foo 2)", "foo"); // longer macro than padding assert_template_format("$(padding foo 3)", "foo"); // len(macro) == padding length assert_template_format("$(padding foo 6 abc)", "abcfoo"); // len(padding string) == padding length assert_template_format("$(padding foo 4 '')", " foo"); // padding string == '' assert_template_failure("$(binary)", "Incorrect parameters"); assert_template_failure("$(binary abc)", "unable to parse abc"); assert_template_failure("$(binary 256)", "256 is above 255"); assert_template_failure("$(binary 08)", "unable to parse 08"); assert_template_format("$(binary 1)", "\1"); assert_template_format("$(binary 1 0x1)", "\1\1"); assert_template_format("$(binary 0xFF 255 0377)", "\xFF\xFF\xFF"); assert_template_format_with_len("$(binary 0xFF 0x00 0x40)", "\xFF\000@", 3); assert_template_format("[$(base64-encode)]", "[]"); assert_template_format("[$(base64-encode abc)]", "[YWJj]"); assert_template_format("[$(base64-encode abcxyz)]", "[YWJjeHl6]"); assert_template_format("[$(base64-encode abcd)]", "[YWJjZA==]"); assert_template_format("[$(base64-encode abcdabcdabcdabcd)]", "[YWJjZGFiY2RhYmNkYWJjZA==]"); assert_template_format("[$(base64-encode abcd abcd abcd abcd)]", "[YWJjZGFiY2RhYmNkYWJjZA==]"); assert_template_format("[$(base64-encode 'X X')]", "[WCBY]"); assert_template_format("[$(base64-encode xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)]", "[eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4" "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4" "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHg=]"); } Test(basicfuncs, test_numeric_funcs) { assert_template_format("$(+ $FACILITY_NUM 1)", "20"); assert_template_format("$(+ -1 -1)", "-2"); assert_template_format("$(- $FACILITY_NUM 1)", "18"); assert_template_format("$(- $FACILITY_NUM 20)", "-1"); assert_template_format("$(* $FACILITY_NUM 2)", "38"); assert_template_format("$(/ $FACILITY_NUM 2)", "9"); assert_template_format("$(% $FACILITY_NUM 3)", "1"); assert_template_format("$(/ $FACILITY_NUM 0)", "NaN"); assert_template_format("$(% $FACILITY_NUM 0)", "NaN"); assert_template_format("$(+ foo bar)", "NaN"); assert_template_format("$(/ 2147483648 1)", "2147483648"); assert_template_format("$(+ 5000000000 5000000000)", "10000000000"); assert_template_format("$(% 10000000000 5000000001)", "4999999999"); assert_template_format("$(* 5000000000 2)", "10000000000"); assert_template_format("$(- 10000000000 5000000000)", "5000000000"); assert_template_format("$(+ 1.5 .25)", "1.75000000000000000000"); assert_template_format("$(- -1.5 .25)", "-1.75000000000000000000"); assert_template_format("$(/ 3 2)", "1"); assert_template_format("$(/ 3.0 2)", "1.50000000000000000000"); assert_template_format("$(/ 3 2.0)", "1.50000000000000000000"); assert_template_format("$(* 1.5 2.0)", "3.00000000000000000000"); assert_template_format("$(% 3.14 0.7)", "0.34000000000000030198"); assert_template_format("$(+ 5e-1 0)", "0.50000000000000000000"); assert_template_format("$(round 2.0)", "2"); assert_template_format("$(round 2.123456 3)", "2.123"); assert_template_format("$(round 2.123456 4)", "2.1235"); assert_template_format("$(round 0.5)", "1"); assert_template_format("$(round 2 -1)", "NaN"); assert_template_format("$(round 2 21)", "NaN"); assert_template_format("$(round 2 0)", "2"); assert_template_format("$(round 2 20)", "2.00000000000000000000"); assert_template_format("$(floor 0.7)", "0"); assert_template_format("$(ceil 0.2)", "1"); } Test(basicfuncs, test_fname_funcs) { assert_template_format("$(basename foo)", "foo"); assert_template_format("$(basename /foo/bar)", "bar"); assert_template_format("$(basename /foo/bar/baz)", "baz"); assert_template_format("$(dirname foo)", "."); assert_template_format("$(dirname /foo/bar)", "/foo"); assert_template_format("$(dirname /foo/bar/)", "/foo/bar"); assert_template_format("$(dirname /foo/bar/baz)", "/foo/bar"); } typedef struct { const gchar *macro; const gchar *result; } MacroAndResult; static void _test_macros_with_context(const gchar *id, const gchar *numbers[], const MacroAndResult test_cases[]) { GPtrArray *messages = create_log_messages_with_values(id, numbers); start_grabbing_messages(); for (const MacroAndResult *test_case = test_cases; test_case->macro; test_case++) assert_template_format_with_context_msgs( test_case->macro, test_case->result, (LogMessage **)messages->pdata, messages->len); stop_grabbing_messages(); free_log_message_array(messages); } Test(basicfuncs, test_numeric_aggregate_simple) { _test_macros_with_context( "NUMBER", (const gchar *[]) { "1", "-1", "3", NULL }, (const MacroAndResult[]) { { "$(sum ${NUMBER})", "3" }, { "$(min ${NUMBER})", "-1" }, { "$(max ${NUMBER})", "3" }, { "$(average ${NUMBER})", "1" }, { } }); } Test(basicfuncs, test_numeric_aggregate_invalid_values) { _test_macros_with_context( "NUMBER", (const gchar *[]) { "abc", "1", "c", "2", "", NULL }, (const MacroAndResult[]) { { "$(sum ${NUMBER})", "3" }, { "$(min ${NUMBER})", "1" }, { "$(max ${NUMBER})", "2" }, { "$(average ${NUMBER})", "1" }, { } }); } Test(basicfuncs, test_numeric_aggregate_full_invalid_values) { _test_macros_with_context( "NUMBER", (const gchar *[]) { "abc", "184467440737095516160", "c", "", NULL }, (const MacroAndResult[]) { { "$(sum ${NUMBER})", "" }, { "$(min ${NUMBER})", "" }, { "$(max ${NUMBER})", "" }, { "$(average ${NUMBER})", "" }, { } }); } Test(basicfuncs, test_misc_funcs) { unsetenv("OHHELLO"); setenv("TEST_ENV", "test-env", 1); assert_template_format("$(env OHHELLO)", ""); assert_template_format("$(env TEST_ENV)", "test-env"); } Test(basicfuncs, test_tf_template) { /* static binding */ assert_template_format("foo $(template dummy) bar", "foo dummy template expanded bzorp bar"); assert_template_failure("foo $(template unknown) bar", "Unknown template function or template \"unknown\""); /* dynamic binding */ assert_template_format("foo $(template ${template_name}) bar", "foo dummy template expanded bzorp bar"); assert_template_format("foo $(template '${unknown:-unknown}' fallback) bar", "foo fallback bar"); assert_template_format("foo $(template '${unknown:-unknown}' fallback more args $HOST) bar", "foo fallback more args bzorp bar"); assert_template_format("foo $(template '${unknown:-unknown}') bar", "foo bar"); } Test(basicfuncs, test_list_funcs) { assert_template_format("$(list-concat)", ""); assert_template_format("$(list-concat foo bar baz)", "foo,bar,baz"); assert_template_format("$(list-concat foo bar baz '')", "foo,bar,baz"); assert_template_format("$(list-concat foo $HOST $PROGRAM $PID bar)", "foo,bzorp,syslog-ng,23323,bar"); assert_template_format("$(list-concat foo $HOST,$PROGRAM,$PID bar)", "foo,bzorp,syslog-ng,23323,bar"); assert_template_format("$(list-concat foo '$HOST,$PROGRAM,$PID' bar)", "foo,bzorp,syslog-ng,23323,bar"); assert_template_format("$(list-concat foo '$HOST,$PROGRAM,$PID,' bar)", "foo,bzorp,syslog-ng,23323,bar"); assert_template_format("$(list-append)", ""); assert_template_format("$(list-append '' foo)", "foo"); assert_template_format("$(list-append '' foo bar)", "foo,bar"); assert_template_format("$(list-append '' foo bar baz)", "foo,bar,baz"); assert_template_format("$(list-append foo,bar,baz 'x')", "foo,bar,baz,x"); assert_template_format("$(list-append foo,bar,baz '')", "foo,bar,baz,\"\""); assert_template_format("$(list-append foo,bar,baz 'xxx,')", "foo,bar,baz,\"xxx,\""); assert_template_format("$(list-append foo,bar,baz 'a\tb')", "foo,bar,baz,\"a\\tb\""); assert_template_format("$(list-head)", ""); assert_template_format("$(list-head '')", ""); assert_template_format("$(list-head foo)", "foo"); assert_template_format("$(list-head foo,)", "foo"); assert_template_format("$(list-head foo,bar)", "foo"); assert_template_format("$(list-head foo,bar,baz)", "foo"); assert_template_format("$(list-head ,bar,baz)", "bar"); assert_template_format("$(list-head foo bar)", "foo"); assert_template_format("$(list-head foo bar baz)", "foo"); assert_template_format("$(list-head '' bar baz)", "bar"); assert_template_format("$(list-head '\"\\tfoo,\",bar,baz')", "\tfoo,"); assert_template_format("$(list-nth 0 '\"foo,\",\"bar\",\"baz\"')", "foo,"); assert_template_format("$(list-nth 1 '\"foo,\",\"bar\",\"baz\"')", "bar"); assert_template_format("$(list-nth 2 '\"foo,\",\"bar\",\"baz\"')", "baz"); assert_template_format("$(list-nth 3 '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-nth 4 '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-nth -1 '\"foo,\",\"bar\",\"baz\"')", "baz"); assert_template_format("$(list-nth -2 '\"foo,\",\"bar\",\"baz\"')", "bar"); assert_template_format("$(list-nth -3 '\"foo,\",\"bar\",\"baz\"')", "foo,"); assert_template_format("$(list-nth -4 '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-tail)", ""); assert_template_format("$(list-tail foo)", ""); assert_template_format("$(list-tail foo,bar)", "bar"); assert_template_format("$(list-tail foo,)", ""); assert_template_format("$(list-tail ,bar)", ""); assert_template_format("$(list-tail foo,bar,baz)", "bar,baz"); assert_template_format("$(list-tail foo bar baz)", "bar,baz"); assert_template_format("$(list-tail foo,bar baz bad)", "bar,baz,bad"); assert_template_format("$(list-tail foo,bar,xxx, baz bad)", "bar,xxx,baz,bad"); assert_template_format("$(list-slice 0:0 foo,bar,xxx,baz,bad)", ""); assert_template_format("$(list-slice 0:1 foo,bar,xxx,baz,bad)", "foo"); assert_template_format("$(list-slice 0:2 foo,bar,xxx,baz,bad)", "foo,bar"); assert_template_format("$(list-slice 0:3 foo,bar,xxx,baz,bad)", "foo,bar,xxx"); assert_template_format("$(list-slice 1:1 foo,bar,xxx,baz,bad)", ""); assert_template_format("$(list-slice 1:2 foo,bar,xxx,baz,bad)", "bar"); assert_template_format("$(list-slice : foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(list-slice 0: foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(list-slice 3: foo,bar,xxx,baz,bad)", "baz,bad"); assert_template_format("$(list-slice :1 foo,bar,xxx,baz,bad)", "foo"); assert_template_format("$(list-slice :2 foo,bar,xxx,baz,bad)", "foo,bar"); assert_template_format("$(list-slice :3 foo,bar,xxx,baz,bad)", "foo,bar,xxx"); assert_template_format("$(list-slice -1: foo,bar,xxx,baz,bad)", "bad"); assert_template_format("$(list-slice -2: foo,bar,xxx,baz,bad)", "baz,bad"); assert_template_format("$(list-slice -3: foo,bar,xxx,baz,bad)", "xxx,baz,bad"); assert_template_format("$(list-slice -5: foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(list-slice -6: foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(list-slice -100: foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(list-slice :-1 foo,bar,xxx,baz,bad)", "foo,bar,xxx,baz"); assert_template_format("$(list-slice :-2 foo,bar,xxx,baz,bad)", "foo,bar,xxx"); assert_template_format("$(list-slice :-3 foo,bar,xxx,baz,bad)", "foo,bar"); assert_template_format("$(list-slice :-4 foo,bar,xxx,baz,bad)", "foo"); assert_template_format("$(list-slice :-5 foo,bar,xxx,baz,bad)", ""); assert_template_format("$(list-slice :-6 foo,bar,xxx,baz,bad)", ""); assert_template_format("$(list-count foo,bar,xxx, baz bad)", "5"); assert_template_format("$(explode ' ' foo bar xxx baz bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(explode ' ' 'foo bar xxx baz bad')", "foo,bar,xxx,baz,bad"); assert_template_format("$(explode ';' foo;bar;xxx;baz;bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(explode ';' foo;bar xxx;baz;bad)", "foo,bar,xxx,baz,bad"); assert_template_format("$(implode ' ' foo,bar,xxx,baz,bad)", "foo bar xxx baz bad"); assert_template_format("$(implode ' ' $(list-slice :3 foo,bar,xxx,baz,bad))", "foo bar xxx"); assert_template_format("$(list-search almafa '')", ""); assert_template_format("$(list-search 'foo,' '\"foo,\",\"bar\",\"baz\",\"bar\"')", "0"); assert_template_format("$(list-search --start-index 0 --mode literal bar '\"foo,\",\"bar\",\"baz\",\"bar\"')", "1"); assert_template_format("$(list-search --start-index 2 bar '\"foo,\",\"bar\",\"baz\",\"bar\"')", "3"); assert_template_format("$(list-search --mode literal --start-index 1 baz '\"foo,\",\"bar\",\"baz\",\"bar\"')", "2"); assert_template_format("$(list-search --start-index 5 baz '\"foo,\",\"bar\",\"baz\",\"bar\"' '\"foo,\",\"bar\",\"baz\",\"bar\"')", "6"); assert_template_format("$(list-search almafa --mode literal '\"foo,\",\"bar\",\"baz\",\"bar\"')", ""); assert_template_format("$(list-search --mode prefix --start-index 0 almafa '')", ""); assert_template_format("$(list-search --start-index 0 --mode prefix fo '\"foo,\",\"bar\",\"baz\"')", "0"); assert_template_format("$(list-search --mode prefix ba '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --mode prefix --start-index 1 ba '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --start-index 2 --mode prefix ba '\"foo,\",\"bar\",\"baz\"')", "2"); assert_template_format("$(list-search --mode prefix --start-index 0 almafa '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-search --mode substring almafa '')", ""); assert_template_format("$(list-search --start-index 0 --mode substring oo '\"foo,\",\"bar\",\"baz\"')", "0"); assert_template_format("$(list-search --mode substring --start-index 2 a '\"foo,\",\"bar\",\"baz\"')", "2"); assert_template_format("$(list-search --mode substring ar '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --start-index 1 --mode substring ar '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --mode substring almafa '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-search --mode glob al*fa '')", ""); assert_template_format("$(list-search --start-index 0 --mode glob f*, '\"foo,\",\"bar\",\"baz\"')", "0"); assert_template_format("$(list-search --mode glob --start-index 1 *az '\"foo,\",\"bar\",\"baz\"')", "2"); assert_template_format("$(list-search --mode glob ar '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-search --mode glob ba* '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --mode glob al*fa '\"foo,\",\"bar\",\"baz\"')", ""); assert_template_format("$(list-search --mode pcre al.*fa '')", ""); assert_template_format("$(list-search --mode pcre --start-index 0 f.*, '\"foo,\",\"bar\",\"baz\"')", "0"); assert_template_format("$(list-search --start-index 1 --mode pcre .az '\"foo,\",\"bar\",\"baz\"')", "2"); assert_template_format("$(list-search --mode pcre ^bar$ '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --mode pcre ba. '\"foo,\",\"bar\",\"baz\"')", "1"); assert_template_format("$(list-search --mode pcre a...fa '\"foo,\",\"bar\",\"baz\"')", ""); } Test(basicfuncs, test_context_funcs) { assert_template_format_with_context("$(context-length)", "2"); assert_template_format_with_context("$(context-lookup 'facility(local3)' $PID)", "23323,23323"); assert_template_format_with_context("$(context-lookup 'facility(local3)' ${comma_value})", "\"value,with,a,comma\",\"value,with,a,comma\""); assert_template_format_with_context("$(context-values ${PID})", "23323,23323"); assert_template_format_with_context("$(context-values ${comma_value})", "\"value,with,a,comma\",\"value,with,a,comma\""); } Test(basicfuncs, test_vp_funcs) { assert_template_format_with_context("$(values .unix.*)", "command,1000,1000"); assert_template_format_with_context("$(values .foo.*)", ""); assert_template_format_with_context("$(values PID PROGRAM)", "23323,syslog-ng"); assert_template_format_with_context("$(values PROGRAM PID)", "23323,syslog-ng"); assert_template_format_with_context("$(values)", ""); assert_template_format_with_context("$(names .unix.*)", ".unix.cmd,.unix.gid,.unix.uid"); assert_template_format_with_context("$(names .foo.*)", ""); assert_template_format_with_context("$(names PID PROGRAM)", "PID,PROGRAM"); assert_template_format_with_context("$(names PROGRAM PID)", "PID,PROGRAM"); assert_template_format_with_context("$(names)", ""); } Test(basicfuncs, test_tfurlencode) { assert_template_format("$(url-encode '')", ""); assert_template_format("$(url-encode test)", "test"); assert_template_format("$(url-encode <>)", "%3C%3E"); assert_template_format("$(url-encode &)", "%26"); } Test(basicfuncs, test_tfurldecode) { assert_template_format("$(url-decode '')", ""); assert_template_format("$(url-decode test)", "test"); assert_template_format("$(url-decode %3C%3E)", "<>"); assert_template_format("$(url-decode %26)", "&"); assert_template_format("$(url-decode %26 %26)", "&&"); assert_template_format("$(url-decode %)", ""); assert_template_format("$(url-decode %00a)", ""); } Test(basicfuncs, test_iterate) { LogMessage *msg = log_msg_new_empty(); GString *result = g_string_new(""); LogTemplate *template = log_template_new(configuration, NULL); cr_assert(log_template_compile(template, "Some prefix $(iterate \"$(+ 1 $_)\" 0)", NULL)); LogTemplateEvalOptions options = {NULL, LTZ_LOCAL, 999, "", LM_VT_STRING}; log_template_format(template, msg, &options, result); cr_assert_str_eq(result->str, "Some prefix 0"); g_string_assign(result, ""); log_template_format(template, msg, &options, result); cr_assert_str_eq(result->str, "Some prefix 1"); g_string_assign(result, ""); log_template_format(template, msg, &options, result); cr_assert_str_eq(result->str, "Some prefix 2"); g_string_free(result, TRUE); log_template_unref(template); log_msg_unref(msg); } struct test_params { gchar *template; char *expected; }; ParameterizedTestParameters(basicfuncs, test_map) { static struct test_params params[] = { { "Some prefix $(map \"$(+ 1 $_)\" 0,1,2)", "Some prefix 1,2,3" }, { "Some prefix $(map \"$(+ 1 $_)\" $(+ 1 1))", "Some prefix 3" }, { "Some prefix $(map \"$(+ 1 $_)\" 0,1,2)", "Some prefix 1,2,3" }, { "Some prefix $(map \"$(+ 1 $_)\" '')", "Some prefix " }, { "Some prefix $(map $(+ 1 $_) $(map $(+ 1 $_) 0,1,2))", "Some prefix 2,3,4" }, // embedded map { "Some prefix $(map \"$(if ('$_' eq '1') 'same' 'different')\" 0,1,2)", "Some prefix different,same,different" }, { "Some prefix $(map \"$(if ('$_' le '1') 'smaller' 'larger')\" 0,1,2)", "Some prefix smaller,smaller,larger" }, { "Some prefix $(map \"$(if ('$_' ge '1') 'larger' 'smaller')\" 0,1,2)", "Some prefix smaller,larger,larger"}, { "$(map \"$(if ('$(echo $_)' eq '1') 'same' 'different')\" 0,1,2)", "different,same,different"}, }; return cr_make_param_array(struct test_params, params, sizeof(params)/sizeof(params[0])); } ParameterizedTest(struct test_params *param, basicfuncs, test_map) { assert_template_format(param->template, param->expected); } ParameterizedTestParameters(basicfuncs, test_filter) { static struct test_params params[] = { { "Some prefix $(filter ('1' == '1') 0,1,2)", "Some prefix 0,1,2" }, { "$(filter ('$_' le '1') 0,1,2)", "0,1" }, { "$(filter ('$(% $_ 2)' eq '0') 0,1,2,3)", "0,2" }, { "Something $(filter ('$_' eq '0') '')", "Something " }, { "$(filter ('1' eq '0') '')", "" }, { "$(filter message('árvíztűrőtükörfúrógép') 'doesnotchange')", "doesnotchange" }, { "$(filter (message('árvíz') and ('${APP.VALUE}' eq 'value')) 'doesnotchange')", "doesnotchange" }, { "$(filter (message('donotmatch') or ('${APP.VALUE}' eq 'value')) 'doesnotchange')", "doesnotchange" }, { "$(filter ('$YEAR' ge '1900') 'doesnotchange')", "doesnotchange" }, { "$(filter ('$YEAR' le '1900') 'doesnotchange')", "" }, }; return cr_make_param_array(struct test_params, params, sizeof(params)/sizeof(params[0])); } ParameterizedTest(struct test_params *param, basicfuncs, test_filter) { assert_template_format(param->template, param->expected); } Test(basicfuncs, test_performance) { perftest_template("$(list-search --start-index 1 --mode pcre .az '\"foo,\",\"bar\",\"baz\"')"); } syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tf-filter.c000066400000000000000000000047631450431004300232150ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ static gboolean tf_filter_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { if (argc != 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Wrong number of arguments. Example: $(filter expr list).\n"); return FALSE; } return tf_cond_prepare(self, s, parent, argc, argv, error); } static void tf_filter_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { ListScanner scanner; gsize initial_len = result->len; TFCondState *state = (TFCondState *)s; GString *lst = args->argv[0]; *type = LM_VT_STRING; list_scanner_init(&scanner); list_scanner_input_string(&scanner, lst->str, lst->len); LogTemplateEvalOptions copy_options = *args->options; while (list_scanner_scan_next(&scanner)) { const gchar *current = list_scanner_get_current_value(&scanner); copy_options.context_id = current; gboolean filter_result = filter_expr_eval_with_context(state->filter, args->messages, args->num_messages, ©_options); if (filter_result) { _append_comma_between_list_elements_if_needed(result, initial_len); g_string_append(result, current); } } list_scanner_deinit(&scanner); } TEMPLATE_FUNCTION(TFCondState, tf_filter, tf_filter_prepare, tf_simple_func_eval, tf_filter_call, tf_cond_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tf-iterate.c000066400000000000000000000065151450431004300233620ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ typedef struct _IterateState { TFSimpleFuncState super; GMutex mutex; GString *current; LogMessageValueType current_type; LogTemplate *template; } IterateState; static gboolean tf_iterate_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { IterateState *state = (IterateState *)s; GOptionContext *ctx = g_option_context_new("iterate"); if (!g_option_context_parse(ctx, &argc, &argv, error)) { g_option_context_free(ctx); return FALSE; } if (argc != 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Wrong number of arguments. Example: $(iterate template initial-value).\n"); g_option_context_free(ctx); return FALSE; } state->template = log_template_new(configuration, "iterate"); if (!log_template_compile(state->template, argv[1], error)) { log_template_unref(state->template); state->template = NULL; g_option_context_free(ctx); return FALSE; } state->current = g_string_new(argv[2]); g_option_context_free(ctx); g_mutex_init(&state->mutex); return TRUE; } static void update_current(LogTemplateFunction *self, IterateState *state, LogMessage *msg) { gchar *current_value = g_strdup(state->current->str); g_string_assign(state->current, ""); LogTemplateEvalOptions options = {NULL, LTZ_LOCAL, 0, current_value, LM_VT_STRING}; log_template_format_value_and_type(state->template, msg, &options, state->current, &state->current_type); g_free(current_value); } static void tf_iterate_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { IterateState *state = (IterateState *)s; g_mutex_lock(&state->mutex); g_string_append(result, state->current->str); *type = state->current_type; update_current(self, state, args->messages[0]); g_mutex_unlock(&state->mutex); } static void tf_iterate_free_state(gpointer s) { IterateState *state = (IterateState *)s; log_template_unref(state->template); state->template = NULL; g_string_free(state->current, TRUE); state->current = NULL; tf_simple_func_free_state(&state->super); g_mutex_clear(&state->mutex); } TEMPLATE_FUNCTION(IterateState, tf_iterate, tf_iterate_prepare, NULL, tf_iterate_call, tf_iterate_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tf-map.c000066400000000000000000000062101450431004300224720ustar00rootroot00000000000000/* * Copyright (c) 2020 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ typedef struct _MapState { TFSimpleFuncState super; LogTemplate *template; } MapState; static gboolean tf_map_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { MapState *state = (MapState *)s; if (argc != 3) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "Wrong number of arguments. Example: $(map template list).\n"); return FALSE; } state->template = log_template_new(configuration, "map"); if (!log_template_compile(state->template, argv[1], error)) { log_template_unref(state->template); state->template = NULL; return FALSE; } memmove(&argv[1], &argv[2], sizeof(argv[0]) * (argc - 2)); if (!tf_simple_func_prepare(self, s, parent, argc - 1, argv, error)) return FALSE; return TRUE; } static void tf_map_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { ListScanner scanner; gsize initial_len = result->len; MapState *state = (MapState *)s; GString *lst = args->argv[0]; LogMessage *msg = args->messages[0]; *type = LM_VT_LIST; list_scanner_init(&scanner); list_scanner_input_string(&scanner, lst->str, lst->len); ScratchBuffersMarker mark; scratch_buffers_mark(&mark); while (list_scanner_scan_next(&scanner)) { const gchar *current_value = list_scanner_get_current_value(&scanner); _append_comma_between_list_elements_if_needed(result, initial_len); GString *buffer = scratch_buffers_alloc(); LogTemplateEvalOptions options = *args->options; options.context_id = current_value; log_template_format(state->template, msg, &options, buffer); str_repr_encode_append(result, buffer->str, -1, ","); } list_scanner_deinit(&scanner); scratch_buffers_reclaim_marked(mark); } static void tf_map_free_state(gpointer s) { MapState *state = (MapState *)s; log_template_unref(state->template); state->template = NULL; tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(MapState, tf_map, tf_map_prepare, tf_simple_func_eval, tf_map_call, tf_map_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/tf-template.c000066400000000000000000000144551450431004300235420ustar00rootroot00000000000000/* * Copyright (c) 2002-2014 Balabit * Copyright (c) 1998-2014 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg.h" /* * $(template ...) * * This template function looks up in the configuration * and uses that format its result. The template name can either be a * static or a dynamic reference. * * * static: means that we perform lookup at configuration read time * * * dynamic: the template name is actually a template (e.g. * ${foobar}), its result are taken as the name of the template and * that is looked up at runtime. * * Dynamic references are slower, but more flexible. syslog-ng uses the * following algorithm to determine which one to use: * * * static: if the name of the template can be resolved at compile * time, the binding becomes static. * * * dynamic: if static lookup fails and the template name contains at * least one '$' character to indicate that it is actually a template. * * In case of dynamic we allow 2nd and further arguments which will be * used as content if the lookup fails. * * Examples: * $(template foobar) -> static binding * $(template ${foobar}) -> dynamic binding * $(template ${foobar} '$DATE $HOST $MSGHDR$MSG\n') -> dynamic binding with fallback * */ typedef struct _TFTemplateState { TFSimpleFuncState super; GlobalConfig *cfg; LogTemplate *invoked_template; } TFTemplateState; static LogTemplate * tf_template_lookup_invoked_template(TFTemplateState *state, GlobalConfig *cfg, const gchar *function_name, GError **error) { return cfg_tree_lookup_template(&cfg->tree, function_name); } static const gchar * tf_template_extract_invoked_template_name_from_args(gint argc, gchar *argv[]) { if (argc >= 2 && strcmp(argv[0], "template") == 0) return argv[1]; return NULL; } static gboolean tf_template_statically_bound(TFTemplateState *state) { return state->invoked_template != NULL; } static gboolean tf_template_dynamically_bound(TFTemplateState *state) { return !tf_template_statically_bound(state); } static gboolean tf_template_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFTemplateState *state = (TFTemplateState *) s; const gchar *invoked_template_name; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); invoked_template_name = tf_template_extract_invoked_template_name_from_args(argc, argv); if (!invoked_template_name) { g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(template) requires one argument, that specifies the template name to be invoked"); return FALSE; } state->invoked_template = tf_template_lookup_invoked_template(state, parent->cfg, invoked_template_name, error); if (tf_template_statically_bound(state)) return TRUE; /* compile time lookup failed, let's check if it's a dynamically bound invocation */ if (strchr(invoked_template_name, '$') == NULL) { /* our argument is not a template, no chance of being better at * runtime, raise as an error */ g_set_error(error, LOG_TEMPLATE_ERROR, LOG_TEMPLATE_ERROR_COMPILE, "$(template) Unknown template function or template \"%s\"", invoked_template_name); return FALSE; } state->cfg = parent->cfg; return tf_simple_func_prepare(self, s, parent, argc, argv, error); } static void tf_template_eval(LogTemplateFunction *self, gpointer s, LogTemplateInvokeArgs *args) { TFTemplateState *state = (TFTemplateState *) s; if (tf_template_dynamically_bound(state)) tf_simple_func_eval(self, s, args); } static LogTemplate * tf_template_get_template_to_be_invoked(TFTemplateState *state, const LogTemplateInvokeArgs *args) { LogTemplate *invoked_template; if (tf_template_dynamically_bound(state)) { const gchar *template_name = args->argv[0]->str; invoked_template = cfg_tree_lookup_template(&state->cfg->tree, template_name); msg_trace("$(template) dynamic template lookup result", evt_tag_str("template", template_name), evt_tag_int("found", invoked_template != NULL)); } else { invoked_template = log_template_ref(state->invoked_template); } return invoked_template; } static void tf_template_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFTemplateState *state = (TFTemplateState *) s; LogTemplate *invoked_template = NULL; invoked_template = tf_template_get_template_to_be_invoked(state, args); if (!invoked_template) { *type = LM_VT_STRING; _append_args_with_separator(state->super.argc - 1, (GString **) &args->argv[1], result, ' '); return; } log_template_append_format_value_and_type_with_context(invoked_template, args->messages, args->num_messages, args->options, result, type); log_template_unref(invoked_template); } static void tf_template_free_state(gpointer s) { TFTemplateState *state = (TFTemplateState *) s; log_template_unref(state->invoked_template); tf_simple_func_free_state(s); } TEMPLATE_FUNCTION(TFTemplateState, tf_template, tf_template_prepare, tf_template_eval, tf_template_call, tf_template_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/urlencode.c000066400000000000000000000035431450431004300232740ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ static void tf_urlencode(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { *type = LM_VT_STRING; if (argc < 1) return; for (gint i = 0; i < argc; i++) { gchar *escaped = g_uri_escape_string(argv[i]->str, NULL, FALSE); g_string_append(result, escaped); g_free(escaped); } } TEMPLATE_FUNCTION_SIMPLE(tf_urlencode); static void tf_urldecode(LogMessage *msg, gint argc, GString *argv[], GString *result, LogMessageValueType *type) { *type = LM_VT_STRING; if (argc < 1) return; for (gint i = 0; i < argc; i++) { gchar *escaped = g_uri_unescape_string(argv[i]->str, NULL); if (escaped) { g_string_append(result, escaped); g_free(escaped); } else { msg_error("Could not urldecode", evt_tag_str("str", argv[i]->str)); } } } TEMPLATE_FUNCTION_SIMPLE(tf_urldecode); syslog-ng-syslog-ng-4.4.0/modules/basicfuncs/vp-funcs.c000066400000000000000000000066551450431004300230640ustar00rootroot00000000000000/* * Copyright (c) 2022 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "value-pairs/cmdline.h" typedef enum { TFVP_NAMES, TFVP_VALUES, } TFValuePairsResultType; typedef struct _TFValuePairsState { TFSimpleFuncState super; ValuePairs *vp; TFValuePairsResultType result_type; } TFValuePairsState; typedef struct _TFValuePairsIterState { GString *result; gsize initial_len; TFValuePairsResultType result_type; } TFValuePairsIterState; static gboolean tf_value_pairs_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFValuePairsState *state = (TFValuePairsState *)s; if (strcmp(argv[0], "values") == 0) state->result_type = TFVP_VALUES; else if(strcmp(argv[0], "names") == 0) state->result_type = TFVP_NAMES; else g_assert_not_reached(); state->vp = value_pairs_new_from_cmdline (parent->cfg, &argc, &argv, NULL, NULL, error); return state->vp != NULL; } static gboolean tf_value_pairs_foreach(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { TFValuePairsIterState *iter_state = (TFValuePairsIterState *) user_data; _append_comma_between_list_elements_if_needed(iter_state->result, iter_state->initial_len); switch (iter_state->result_type) { case TFVP_VALUES: str_repr_encode_append(iter_state->result, value, value_len, ","); break; case TFVP_NAMES: str_repr_encode_append(iter_state->result, name, -1, ","); break; default: g_assert_not_reached(); } return FALSE; } static void tf_value_pairs_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFValuePairsState *state = (TFValuePairsState *)s; TFValuePairsIterState iter_state = { .result = result, .initial_len = result->len, .result_type = state->result_type, }; *type = LM_VT_LIST; value_pairs_foreach(state->vp, tf_value_pairs_foreach, args->messages[args->num_messages-1], args->options, &iter_state); } static void tf_value_pairs_free_state(gpointer s) { TFValuePairsState *state = (TFValuePairsState *)s; value_pairs_unref(state->vp); tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(TFValuePairsState, tf_value_pairs, tf_value_pairs_prepare, NULL, tf_value_pairs_call, tf_value_pairs_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/cef/000077500000000000000000000000001450431004300175605ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/cef/CMakeLists.txt000066400000000000000000000002541450431004300223210ustar00rootroot00000000000000set(CEF_SOURCES format-cef-extension.c format-cef-extension.h cef-plugin.c ) add_module( TARGET cef SOURCES ${CEF_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/cef/Makefile.am000066400000000000000000000011721450431004300216150ustar00rootroot00000000000000module_LTLIBRARIES += modules/cef/libcef.la EXTRA_DIST += modules/cef/CMakeLists.txt modules_cef_libcef_la_SOURCES = \ modules/cef/format-cef-extension.c \ modules/cef/format-cef-extension.h \ modules/cef/cef-plugin.c modules_cef_libcef_la_CFLAGS = \ $(AM_CFLAGS) \ -I$(top_srcdir)/modules/cef \ -I$(top_builddir)/modules/cef modules_cef_libcef_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_cef_libcef_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_cef_libcef_la_DEPENDENCIES= \ $(MODULE_DEPS_LIBS) modules/cef modules/cef/ mod-cef: modules/cef/libcef.la .PHONY: modules/cef/ mod-cef include modules/cef/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/cef/cef-plugin.c000066400000000000000000000027651450431004300217670ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "format-cef-extension.h" #include "plugin.h" #include "plugin-types.h" static Plugin cef_plugins[] = { TEMPLATE_FUNCTION_PLUGIN(tf_cef, "format-cef-extension"), }; gboolean cef_module_init(PluginContext *context, CfgArgs *args) { plugin_register(context, cef_plugins, G_N_ELEMENTS(cef_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "cef", .version = SYSLOG_NG_VERSION, .description = "The CEF module provides CEF formatting support for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = cef_plugins, .plugins_len = G_N_ELEMENTS(cef_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/cef/format-cef-extension.c000066400000000000000000000124001450431004300237560ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include "filter/filter-expr.h" #include "filter/filter-expr-parser.h" #include "cfg.h" #include "value-pairs/value-pairs.h" #include "value-pairs/cmdline.h" #include "syslog-ng.h" #include "str-utils.h" #include "format-cef-extension.h" typedef struct _TFCefState { TFSimpleFuncState super; ValuePairs *vp; } TFCefState; static gboolean tf_cef_prepare(LogTemplateFunction *self, gpointer s, LogTemplate *parent, gint argc, gchar *argv[], GError **error) { TFCefState *state = (TFCefState *)s; state->vp = value_pairs_new_from_cmdline(parent->cfg, &argc, &argv, NULL, NULL, error); if (!state->vp) return FALSE; return TRUE; } typedef struct { gboolean need_separator; GString *buffer; const LogTemplateOptions *template_options; } CefWalkerState; static gboolean tf_cef_is_valid_key(const gchar *str) { size_t end = strspn(str, "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); return str[end] == '\0'; } static inline void tf_cef_append_escaped(GString *escaped_string, const gchar *str, gsize str_len) { const gchar *char_ptr; gunichar uchar; while (str_len) { uchar = g_utf8_get_char_validated(str, str_len); switch (uchar) { case (gunichar) -1: case (gunichar) -2: g_string_append_printf(escaped_string, "\\x%02x", *(guint8 *) str++); str_len--; continue; break; case '=': g_string_append(escaped_string, "\\="); break; case '\n': g_string_append(escaped_string, "\\n"); break; case '\r': g_string_append(escaped_string, "\\r"); break; case '\\': g_string_append(escaped_string, "\\\\"); break; default: if (uchar < 32) g_string_append_printf(escaped_string, "\\u%04x", uchar); else g_string_append_unichar_optimized(escaped_string, uchar); break; } char_ptr = g_utf8_next_char(str); str_len -= char_ptr - str; str = char_ptr; } } static gboolean tf_cef_append_value(const gchar *name, const gchar *value, gsize value_len, CefWalkerState *state) { if (state->need_separator) g_string_append_c(state->buffer, ' '); g_string_append(state->buffer, name); g_string_append_c(state->buffer, '='); tf_cef_append_escaped(state->buffer, value, value_len); return TRUE; } static gint tf_cef_walk_cmp(const gchar *s1, const gchar *s2) { return strcmp(s1, s2); } static gboolean tf_cef_walker(const gchar *name, LogMessageValueType type, const gchar *value, gsize value_len, gpointer user_data) { CefWalkerState *state = (CefWalkerState *)user_data; gint on_error = state->template_options->on_error; if (!tf_cef_is_valid_key(name)) { if (!(on_error & ON_ERROR_SILENT)) { msg_error("Invalid CEF key", evt_tag_str("key", name)); } return !!(on_error & ON_ERROR_DROP_MESSAGE); } tf_cef_append_value(name, value, value_len, state); state->need_separator = TRUE; return FALSE; } static gboolean tf_cef_append(GString *result, ValuePairs *vp, LogMessage *msg, LogTemplateEvalOptions *options) { CefWalkerState state; state.need_separator = FALSE; state.buffer = result; state.template_options = options->opts; return value_pairs_foreach_sorted(vp, tf_cef_walker, (GCompareFunc) tf_cef_walk_cmp, msg, options, &state); } static void tf_cef_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result, LogMessageValueType *type) { TFCefState *state = (TFCefState *)s; gint i; gboolean r = TRUE; gsize orig_size = result->len; *type = LM_VT_STRING; for (i = 0; i < args->num_messages; i++) r &= tf_cef_append(result, state->vp, args->messages[i], args->options); if (!r && (args->options->opts->on_error & ON_ERROR_DROP_MESSAGE)) g_string_set_size(result, orig_size); } static void tf_cef_free_state(gpointer s) { TFCefState *state = (TFCefState *)s; if (state->vp) value_pairs_unref(state->vp); tf_simple_func_free_state(&state->super); } TEMPLATE_FUNCTION(TFCefState, tf_cef, tf_cef_prepare, NULL, tf_cef_call, tf_cef_free_state, NULL); syslog-ng-syslog-ng-4.4.0/modules/cef/format-cef-extension.h000066400000000000000000000020761450431004300237730ustar00rootroot00000000000000/* * Copyright (c) 2015 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #ifndef FORMAT_CEF_EXTENSION_H_INCLUDED #define FORMAT_CEF_EXTENSION_H_INCLUDED #include "template/simple-function.h" #include "plugin.h" TEMPLATE_FUNCTION_DECLARE(tf_cef); #endif syslog-ng-syslog-ng-4.4.0/modules/cef/tests/000077500000000000000000000000001450431004300207225ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/cef/tests/CMakeLists.txt000066400000000000000000000001161450431004300234600ustar00rootroot00000000000000add_unit_test(LIBTEST CRITERION TARGET test-format-cef-extension DEPENDS cef) syslog-ng-syslog-ng-4.4.0/modules/cef/tests/Makefile.am000066400000000000000000000010371450431004300227570ustar00rootroot00000000000000modules_cef_tests_TESTS = \ modules/cef/tests/test-format-cef-extension check_PROGRAMS += ${modules_cef_tests_TESTS} EXTRA_DIST += modules/cef/tests/CMakeLists.txt modules_cef_tests_test_format_cef_extension_CFLAGS = $(TEST_CFLAGS) modules_cef_tests_test_format_cef_extension_LDADD = $(TEST_LDADD) modules_cef_tests_test_format_cef_extension_LDFLAGS = \ $(PREOPEN_SYSLOGFORMAT) \ -dlpreopen $(top_builddir)/modules/cef/libcef.la modules_cef_tests_test_format_cef_extension_DEPENDENCIES = \ $(top_builddir)/modules/cef/libcef.la syslog-ng-syslog-ng-4.4.0/modules/cef/tests/test-format-cef-extension.c000066400000000000000000000157351450431004300261130ustar00rootroot00000000000000/* * Copyright (c) 2015-2018 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. */ #include #include "libtest/cr_template.h" #include "apphook.h" #include "plugin.h" #include "cfg.h" #include "logmsg/logmsg.h" #include #define _EXPECT_CEF_RESULT(...) _expect_cef_result_va(__VA_ARGS__, NULL) #define _EXPECT_DROP_MESSAGE(...) _expect_cef_result_va("", __VA_ARGS__, NULL) #define _EXPECT_SKIP_BAD_PROPERTY(...) _expect_skip_bad_property_va(__VA_ARGS__, NULL) #define _EXPECT_CEF_RESULT_FORMAT(X, ...) _expect_cef_result_format_va(X, __VA_ARGS__, NULL); static void _expect_cef_result_properties_list(const gchar *expected, va_list ap) { LogMessage *msg = message_from_list(ap); assert_template_format_msg("$(format-cef-extension --subkeys .cef.)", expected, msg); log_msg_unref(msg); } static void _expect_cef_result_va(const gchar *expected, ...) { va_list ap; configuration->template_options.on_error = ON_ERROR_DROP_MESSAGE | ON_ERROR_SILENT; va_start(ap, expected); _expect_cef_result_properties_list(expected, ap); va_end(ap); } static void _expect_skip_bad_property_va(const gchar *expected, ...) { va_list ap; configuration->template_options.on_error = ON_ERROR_DROP_PROPERTY | ON_ERROR_SILENT; va_start(ap, expected); _expect_cef_result_properties_list(expected, ap); va_end(ap); } static void _expect_cef_result_format_va(const gchar *format, const gchar *expected, ...) { va_list ap; va_start(ap, expected); LogMessage *msg = message_from_list(ap); va_end(ap); configuration->template_options.on_error = ON_ERROR_DROP_MESSAGE | ON_ERROR_SILENT; assert_template_format_msg(format, expected, msg); log_msg_unref(msg); } void setup(void) { app_startup(); setenv("TZ", "UTC", TRUE); tzset(); init_template_tests(); cfg_load_module(configuration, "cef"); } void teardown(void) { deinit_template_tests(); app_shutdown(); } TestSuite(format_cef, .init = setup, .fini = teardown); Test(format_cef, test_null_in_value) { LogMessage *msg = create_empty_message(); configuration->template_options.on_error = ON_ERROR_DROP_MESSAGE | ON_ERROR_SILENT; log_msg_set_value_by_name(msg, ".cef.k", "a\0b", 3); assert_template_format_msg("$(format-cef-extension --subkeys .cef.)", "k=a\\x00b", msg); log_msg_unref(msg); } Test(format_cef, test_filter) { _EXPECT_CEF_RESULT("k=v", ".cef.k", "v", "x", "w"); } Test(format_cef, test_multiple_properties_with_space) { _EXPECT_CEF_RESULT("act=c:/program files dst=10.0.0.1", ".cef.act", "c:/program files", ".cef.dst", "10.0.0.1"); } Test(format_cef, test_multiple_properties) { _EXPECT_CEF_RESULT("k=v x=y", ".cef.k", "v", ".cef.x", "y"); } Test(format_cef, test_drop_property) { _EXPECT_SKIP_BAD_PROPERTY("kkk=v", ".cef.a|b", "c", ".cef.kkk", "v", ".cef.x=y", "w"); } Test(format_cef, test_drop_message) { _EXPECT_DROP_MESSAGE(".cef.a|b", "c", ".cef.kkk", "v", ".cef.x=y", "w"); } Test(format_cef, test_empty) { _EXPECT_CEF_RESULT(""); } Test(format_cef, test_inline) { _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys .cef. .cef.k=v)", "k=v"); } Test(format_cef, test_space) { _EXPECT_CEF_RESULT("act=blocked a ping", ".cef.act", "blocked a ping"); } Test(format_cef, test_charset) { _EXPECT_DROP_MESSAGE(".cef.árvíztűrőtükörfúrógép", "v"); _EXPECT_CEF_RESULT("k=árvíztűrőtükörfúrógép", ".cef.k", "árvíztűrőtükörfúrógép"); _EXPECT_CEF_RESULT("k=\\xff", ".cef.k", "\xff"); _EXPECT_CEF_RESULT("k=\\xc3", ".cef.k", "\xc3"); _EXPECT_DROP_MESSAGE(".cef.k\xff", "v"); _EXPECT_DROP_MESSAGE(".cef.k\xc3", "v"); } Test(format_cef, test_escaping) { _EXPECT_CEF_RESULT("act=\\\\", ".cef.act", "\\"); _EXPECT_CEF_RESULT("act=\\\\\\\\", ".cef.act", "\\\\"); _EXPECT_CEF_RESULT("act=\\=", ".cef.act", "="); _EXPECT_CEF_RESULT("act=|", ".cef.act", "|"); _EXPECT_CEF_RESULT("act=\\u0009", ".cef.act", "\t"); _EXPECT_CEF_RESULT("act=\\n", ".cef.act", "\n"); _EXPECT_CEF_RESULT("act=\\r", ".cef.act", "\r"); _EXPECT_CEF_RESULT("act=v\\n", ".cef.act", "v\n"); _EXPECT_CEF_RESULT("act=v\\r", ".cef.act", "v\r"); _EXPECT_CEF_RESULT("act=u\\nv", ".cef.act", "u\nv"); _EXPECT_CEF_RESULT("act=\\r\\n", ".cef.act", "\r\n"); _EXPECT_CEF_RESULT("act=\\n\\r", ".cef.act", "\n\r"); _EXPECT_CEF_RESULT("act=this is a long value \\= something", ".cef.act", "this is a long value = something"); _EXPECT_DROP_MESSAGE(".cef.k=w", "v"); _EXPECT_DROP_MESSAGE(".cef.k|w", "v"); _EXPECT_DROP_MESSAGE(".cef.k\\w", "v"); _EXPECT_DROP_MESSAGE(".cef.k\nw", "v"); _EXPECT_DROP_MESSAGE(".cef.k w", "v"); } Test(format_cef, test_prefix) { configuration->template_options.on_error = ON_ERROR_DROP_MESSAGE | ON_ERROR_SILENT; _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys ..)", "k=v", "..k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys ,)", "k=v", ",k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys .cef.)", "", "k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys ' ')", "k=v", " k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension --subkeys \" \")", "k=v", " k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension x=y)", "x=y", "k", "v"); _EXPECT_CEF_RESULT_FORMAT("$(format-cef-extension)", "", "k", "v"); assert_template_failure("$(format-cef-extension --subkeys)", "Missing argument for --subkeys"); assert_template_failure("$(format-cef-extension --subkeys '')", "Error parsing value-pairs: --subkeys requires a non-empty argument"); assert_template_failure("$(format-cef-extension --subkeys \"\")", "Error parsing value-pairs: --subkeys requires a non-empty argument"); } Test(format_cef, test_macro_parity) { _EXPECT_CEF_RESULT("", "k"); _EXPECT_CEF_RESULT_FORMAT("", ""); _EXPECT_CEF_RESULT_FORMAT("", "", "k"); _EXPECT_DROP_MESSAGE(""); _EXPECT_DROP_MESSAGE("", "k"); _EXPECT_SKIP_BAD_PROPERTY(""); _EXPECT_SKIP_BAD_PROPERTY("", "k"); } syslog-ng-syslog-ng-4.4.0/modules/confgen/000077500000000000000000000000001450431004300204425ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/confgen/CMakeLists.txt000066400000000000000000000002251450431004300232010ustar00rootroot00000000000000set (CONFGEN_SOURCES confgen.h confgen-plugin.c ) add_module( TARGET confgen SOURCES ${CONFGEN_SOURCES} ) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/confgen/Makefile.am000066400000000000000000000011531450431004300224760ustar00rootroot00000000000000module_LTLIBRARIES += modules/confgen/libconfgen.la modules_confgen_libconfgen_la_SOURCES = \ modules/confgen/confgen.h \ modules/confgen/confgen-plugin.c modules_confgen_libconfgen_la_CPPFLAGS = \ $(AM_CPPFLAGS) modules_confgen_libconfgen_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_confgen_libconfgen_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_confgen_libconfgen_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) EXTRA_DIST += modules/confgen/CMakeLists.txt modules/confgen modules/confgen/ mod-confgen: modules/confgen/libconfgen.la .PHONY: modules/confgen/ mod-confgen include modules/confgen/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/confgen/confgen-plugin.c000066400000000000000000000130011450431004300235140ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "confgen.h" #include "cfg.h" #include "cfg-block-generator.h" #include "messages.h" #include "plugin.h" #include #include #include static void confgen_set_args_as_env(gpointer k, gpointer v, gpointer user_data) { if (!v) { msg_debug("confgen: Skipping empty argument", evt_tag_str("name", (gchar *) k)); return; } gchar buf[1024]; g_snprintf(buf, sizeof(buf), "confgen_%s", (gchar *)k); msg_debug("confgen: Passing argument to confgen script", evt_tag_str("name", (gchar *) k), evt_tag_str("value", (gchar *) v), evt_tag_str("env_name", buf)); setenv(buf, (gchar *)v, 1); } static void confgen_unset_args_from_env(gpointer k, gpointer v, gpointer user_data) { gchar buf[1024]; g_snprintf(buf, sizeof(buf), "confgen_%s", (gchar *)k); unsetenv(buf); } typedef struct _ConfgenExec { CfgBlockGenerator super; gchar *exec; } ConfgenExec; static void _read_program_output(FILE *out, GString *result) { gchar buf[1024]; gsize res; while ((res = fread(buf, 1, sizeof(buf), out)) > 0) { g_string_append_len(result, buf, res); } } gboolean confgen_exec_generate(CfgBlockGenerator *s, GlobalConfig *cfg, gpointer args, GString *result, const gchar *reference) { ConfgenExec *self = (ConfgenExec *) s; FILE *out; gchar buf[256]; gint res; CfgArgs *cfgargs = (CfgArgs *)args; g_snprintf(buf, sizeof(buf), "%s confgen %s", cfg_lexer_lookup_context_name_by_type(self->super.context), self->super.name); cfg_args_foreach(cfgargs, confgen_set_args_as_env, NULL); out = popen(self->exec, "r"); cfg_args_foreach(cfgargs, confgen_unset_args_from_env, NULL); if (!out) { msg_error("confgen: Error executing generator program", evt_tag_str("reference", reference), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(self->super.context)), evt_tag_str("block", self->super.name), evt_tag_str("exec", self->exec), evt_tag_error("error")); return FALSE; } _read_program_output(out, result); res = pclose(out); if (res != 0) { msg_error("confgen: Generator program returned with non-zero exit code", evt_tag_str("reference", reference), evt_tag_str("context", cfg_lexer_lookup_context_name_by_type(self->super.context)), evt_tag_str("block", self->super.name), evt_tag_str("exec", self->exec), evt_tag_int("rc", res)); return FALSE; } msg_debug("confgen: output from the executed program to be included is", evt_tag_mem("block", result->str, result->len)); return TRUE; } static void confgen_exec_free(CfgBlockGenerator *s) { ConfgenExec *self = (ConfgenExec *) s; g_free(self->exec); cfg_block_generator_free_instance(s); } static CfgBlockGenerator * confgen_exec_new(gint context, const gchar *name, const gchar *exec) { ConfgenExec *self = g_new0(ConfgenExec, 1); cfg_block_generator_init_instance(&self->super, context, name); self->super.generate = confgen_exec_generate; self->super.free_fn = confgen_exec_free; self->exec = g_strdup(exec); return &self->super; } gboolean confgen_module_init(PluginContext *plugin_context, CfgArgs *args) { const gchar *name, *context, *exec; gint context_value; if (!args) { msg_error("confgen: no arguments"); return FALSE; } name = cfg_args_get(args, "name"); if (!name) { msg_error("confgen: name argument expected"); return FALSE; } context = cfg_args_get(args, "context"); if (!context) { msg_error("confgen: context argument expected"); return FALSE; } context_value = cfg_lexer_lookup_context_type_by_name(context); if (context_value == 0) { msg_error("confgen: context value is unknown", evt_tag_str("context", context)); return FALSE; } exec = cfg_args_get(args, "exec"); if (!exec) { msg_error("confgen: exec argument expected"); return FALSE; } cfg_lexer_register_generator_plugin(plugin_context, confgen_exec_new(context_value, name, exec)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "confgen", .version = SYSLOG_NG_VERSION, .description = "The confgen module provides support for dynamically generated configuration file snippets for syslog-ng, used for the SCL system() driver for example", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = NULL, .plugins_len = 0, }; syslog-ng-syslog-ng-4.4.0/modules/confgen/confgen.h000066400000000000000000000020221450431004300222260ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CONFGEN_H_INCLUDED #define CONFGEN_H_INCLUDED #include "syslog-ng.h" #endif syslog-ng-syslog-ng-4.4.0/modules/confgen/tests/000077500000000000000000000000001450431004300216045ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/confgen/tests/CMakeLists.txt000066400000000000000000000001051450431004300243400ustar00rootroot00000000000000add_unit_test(CRITERION LIBTEST TARGET test_confgen DEPENDS confgen) syslog-ng-syslog-ng-4.4.0/modules/confgen/tests/Makefile.am000066400000000000000000000006251450431004300236430ustar00rootroot00000000000000modules_confgen_tests_TESTS = \ modules/confgen/tests/test_confgen check_PROGRAMS += ${modules_confgen_tests_TESTS} modules_confgen_tests_test_confgen_CFLAGS = \ $(TEST_CFLAGS) modules_confgen_tests_test_confgen_LDADD = \ $(TEST_LDADD) -dlpreopen $(top_builddir)/modules/confgen/libconfgen.la EXTRA_DIST += modules/confgen/tests/confgentest.sh \ modules/confgen/tests/CMakeLists.txt syslog-ng-syslog-ng-4.4.0/modules/confgen/tests/confgentest.sh000077500000000000000000000020741450431004300244650ustar00rootroot00000000000000#!/bin/sh ############################################################################# # Copyright (c) 2018 Balabit # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # As an additional exemption you are allowed to compile & link against the # OpenSSL libraries as published by the OpenSSL project. See the file # COPYING for details. # ############################################################################# echo from-confgen1 echo from-confgen2 syslog-ng-syslog-ng-4.4.0/modules/confgen/tests/test_confgen.c000066400000000000000000000101671450431004300244330ustar00rootroot00000000000000/* * Copyright (c) 2018 Balabit * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include #include "libtest/grab-logging.h" #include "libtest/mock-cfg-parser.h" #include "apphook.h" #include "cfg-grammar.h" #define TESTDATA_DIR TOP_SRCDIR "/modules/confgen/tests" CfgParserMock *parser = NULL; static void _input(const gchar *input) { cfg_parser_mock_input(parser, input); } static void _next_token(void) { cfg_parser_mock_next_token(parser); } static CFG_STYPE * _current_token(void) { return parser->yylval; } #define assert_token_type(expected) \ cr_assert_eq(_current_token()->type, expected, "Unexpected token type %d != %d", _current_token()->type, expected); #define assert_parser_string(expected) \ _next_token(); \ assert_token_type(LL_STRING); \ cr_assert_str_eq(_current_token()->cptr, expected, "Unexpected string value parsed >>>%s<<< != >>>%s<<<", _current_token()->cptr, expected); #define assert_parser_character_token(expected) \ _next_token(); \ assert_token_type((gint) expected); #define assert_parser_identifier(expected) \ _next_token(); \ assert_token_type(LL_IDENTIFIER); \ cr_assert_str_eq(_current_token()->cptr, expected, "Unexpected identifier parsed >>>%s<<< != >>>%s<<<", _current_token()->cptr, expected); Test(confgen, confgen_script_output_is_included_into_the_config) { parser->lexer->ignore_pragma = FALSE; cfg_lexer_push_context(parser->lexer, main_parser.context, main_parser.keywords, main_parser.name); _input( "@module confgen context(root) name(confgentest) exec('"TESTDATA_DIR "/confgentest.sh')\n" "from-config1\n" "confgentest()\n" "from-config2\n"); assert_parser_identifier("from-config1"); assert_parser_identifier("from-confgen1"); assert_parser_identifier("from-confgen2"); assert_parser_identifier("from-config2"); cfg_lexer_pop_context(parser->lexer); } Test(confgen, confgen_unknown_context_is_reported_as_an_error) { parser->lexer->ignore_pragma = FALSE; start_grabbing_messages(); cfg_lexer_push_context(parser->lexer, main_parser.context, main_parser.keywords, main_parser.name); _input( "@module confgen context(unknown-context) name(confgentest) exec('"TESTDATA_DIR "/confgentest.sh')\n" "from-config1\n" "confgentest()\n" "from-config2\n"); _next_token(); assert_parser_identifier("from-config1"); assert_grabbed_log_contains("context value is unknown"); /* confgen is not registered */ assert_parser_identifier("confgentest"); assert_parser_character_token('('); assert_parser_character_token(')'); assert_parser_identifier("from-config2"); cfg_lexer_pop_context(parser->lexer); stop_grabbing_messages(); } static void setup(void) { app_startup(); configuration = cfg_new_snippet(); parser = cfg_parser_mock_new(); } static void teardown(void) { cfg_parser_mock_free(parser); cfg_free(configuration); configuration = NULL; app_shutdown(); } TestSuite(confgen, .init = setup, .fini = teardown); syslog-ng-syslog-ng-4.4.0/modules/correlation/000077500000000000000000000000001450431004300213445ustar00rootroot00000000000000syslog-ng-syslog-ng-4.4.0/modules/correlation/CMakeLists.txt000066400000000000000000000036371450431004300241150ustar00rootroot00000000000000set(PATTERNDB_SOURCES radix.c radix.h patterndb.c patterndb.h pdb-load.c pdb-load.h pdb-rule.c pdb-rule.h pdb-file.c pdb-file.h pdb-error.c pdb-error.h pdb-action.c pdb-action.h pdb-program.c pdb-program.h pdb-example.c pdb-example.h pdb-ruleset.c pdb-ruleset.h pdb-context.c pdb-context.h pdb-ratelimit.c pdb-ratelimit.h pdb-lookup-params.h pdb-lookup-params.c correlation.c correlation.h correlation-key.c correlation-key.h correlation-context.c correlation-context.h synthetic-message.c synthetic-message.h synthetic-context.c synthetic-context.h timerwheel.c timerwheel.h patternize.c patternize.h id-counter.h id-counter.c ) set(PATTERNDB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_library(patterndb ${PATTERNDB_SOURCES}) # The radix tree uses unsigned char internally but passes these values to # string.h functions, which trigger a lot of harmless warnings. Of course # these could be fixed by adding a lot of casts to the code, but I # considered these to be less readable, than simply adding -Wno-pointer-sign # warning option. # set_target_properties(patterndb PROPERTIES COMPILE_FLAGS "-fPIC -Wno-pointer-sign") target_include_directories(patterndb INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(patterndb PUBLIC syslog-ng) set(CORRELATION_SOURCES stateful-parser.c stateful-parser.h dbparser.c dbparser.h correlation-parser.c correlation-parser.h correlation-plugin.c groupingby.c groupingby.h grouping-parser.c grouping-parser.h group-lines.c group-lines.h ) add_module( TARGET correlation GRAMMAR correlation-grammar INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${PATTERNDB_INCLUDE_DIR} DEPENDS patterndb SOURCES ${CORRELATION_SOURCES} ) add_subdirectory(pdbtool) add_test_subdirectory(tests) syslog-ng-syslog-ng-4.4.0/modules/correlation/Makefile.am000066400000000000000000000072051450431004300234040ustar00rootroot00000000000000noinst_LTLIBRARIES += modules/correlation/libsyslog-ng-patterndb.la modules_correlation_libsyslog_ng_patterndb_la_SOURCES = \ modules/correlation/radix.c \ modules/correlation/radix.h \ modules/correlation/patterndb.c \ modules/correlation/patterndb.h \ modules/correlation/pdb-error.c \ modules/correlation/pdb-error.h \ modules/correlation/pdb-file.c \ modules/correlation/pdb-file.h \ modules/correlation/pdb-load.c \ modules/correlation/pdb-load.h \ modules/correlation/pdb-rule.c \ modules/correlation/pdb-rule.h \ modules/correlation/pdb-action.c \ modules/correlation/pdb-action.h \ modules/correlation/pdb-program.c \ modules/correlation/pdb-program.h \ modules/correlation/pdb-example.c \ modules/correlation/pdb-example.h \ modules/correlation/pdb-ruleset.c \ modules/correlation/pdb-ruleset.h \ modules/correlation/pdb-context.c \ modules/correlation/pdb-context.h \ modules/correlation/pdb-ratelimit.c \ modules/correlation/pdb-ratelimit.h \ modules/correlation/pdb-lookup-params.h \ modules/correlation/pdb-lookup-params.c \ modules/correlation/correlation.c \ modules/correlation/correlation.h \ modules/correlation/correlation-key.c \ modules/correlation/correlation-key.h \ modules/correlation/correlation-context.c \ modules/correlation/correlation-context.h \ modules/correlation/synthetic-message.c \ modules/correlation/synthetic-message.h \ modules/correlation/synthetic-context.c \ modules/correlation/synthetic-context.h \ modules/correlation/timerwheel.c \ modules/correlation/timerwheel.h \ modules/correlation/patternize.c \ modules/correlation/patternize.h \ modules/correlation/id-counter.h \ modules/correlation/id-counter.c modules_correlation_libsyslog_ng_patterndb_la_CFLAGS = \ $(AM_CFLAGS) -fPIC modules_correlation_libsyslog_ng_patterndb_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_correlation_libsyslog_ng_patterndb_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) module_LTLIBRARIES += modules/correlation/libcorrelation.la modules_correlation_libcorrelation_la_SOURCES = \ modules/correlation/stateful-parser.c \ modules/correlation/stateful-parser.h \ modules/correlation/dbparser.c \ modules/correlation/dbparser.h \ modules/correlation/correlation-grammar.y \ modules/correlation/correlation-parser.c \ modules/correlation/correlation-parser.h \ modules/correlation/correlation-plugin.c \ modules/correlation/grouping-parser.c \ modules/correlation/grouping-parser.h \ modules/correlation/groupingby.c \ modules/correlation/groupingby.h \ modules/correlation/group-lines.c \ modules/correlation/group-lines.h \ $(modules_correlation_libsyslog_ng_patterndb_la_SOURCES) modules_correlation_libcorrelation_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/modules/correlation \ -I$(top_builddir)/modules/correlation modules_correlation_libcorrelation_la_LIBADD = \ $(MODULE_DEPS_LIBS) modules_correlation_libcorrelation_la_LDFLAGS = \ $(MODULE_LDFLAGS) modules_correlation_libcorrelation_la_DEPENDENCIES = \ $(MODULE_DEPS_LIBS) BUILT_SOURCES += \ modules/correlation/correlation-grammar.y \ modules/correlation/correlation-grammar.c \ modules/correlation/correlation-grammar.h EXTRA_DIST += \ modules/correlation/correlation-grammar.ym \ modules/correlation/CMakeLists.txt modules/correlation modules/correlation/ mod-correlation: modules/correlation/libcorrelation.la \ modules/correlation/pdbtool/pdbtool .PHONY: modules/correlation/ mod-correlation include modules/correlation/pdbtool/Makefile.am include modules/correlation/tests/Makefile.am syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-context.c000066400000000000000000000102711450431004300255140ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "correlation-context.h" #include "logmsg/logmsg.h" #include "scratch-buffers.h" #include static gint _compare_messages_with_trivial_template(gconstpointer a, gconstpointer b, gpointer user_data) { LogMessage *am = *(LogMessage **) a; LogMessage *bm = *(LogMessage **) b; gssize av_len, bv_len; LogTemplate *sort_key = (LogTemplate *) user_data; const gchar *am_key = log_template_get_trivial_value(sort_key, am, &av_len); const gchar *bm_key = log_template_get_trivial_value(sort_key, bm, &bv_len); if (am_key == NULL && bm_key == NULL) return 0; if (am_key == NULL) return -1; if (bm_key == NULL) return 1; gssize cmp_len = MIN(av_len, bv_len); return strncmp(am_key, bm_key, cmp_len); } static gint _compare_messages_with_nontrivial_template(gconstpointer a, gconstpointer b, gpointer user_data) { LogMessage *am = *(LogMessage **) a; LogMessage *bm = *(LogMessage **) b; LogTemplate *sort_key = (LogTemplate *) user_data; ScratchBuffersMarker mark; GString *am_key = scratch_buffers_alloc_and_mark(&mark); GString *bm_key = scratch_buffers_alloc(); log_template_format(sort_key, am, &DEFAULT_TEMPLATE_EVAL_OPTIONS, am_key); log_template_format(sort_key, bm, &DEFAULT_TEMPLATE_EVAL_OPTIONS, bm_key); gint result = strcmp(am_key->str, bm_key->str); scratch_buffers_reclaim_marked(mark); return result; } void correlation_context_sort(CorrelationContext *self, LogTemplate *sort_key) { if (log_template_is_trivial(sort_key)) g_ptr_array_sort_with_data(self->messages, _compare_messages_with_trivial_template, sort_key); else g_ptr_array_sort_with_data(self->messages, _compare_messages_with_nontrivial_template, sort_key); } void correlation_context_init(CorrelationContext *self, const CorrelationKey *key) { self->clear = correlation_context_clear_method; self->messages = g_ptr_array_new(); memcpy(&self->key, key, sizeof(self->key)); if (self->key.pid) self->key.pid = g_strdup(self->key.pid); if (self->key.program) self->key.program = g_strdup(self->key.program); if (self->key.host) self->key.host = g_strdup(self->key.host); self->ref_cnt = 1; self->free_fn = correlation_context_free_method; } void correlation_context_clear_method(CorrelationContext *self) { for (gint i = 0; i < self->messages->len; i++) { log_msg_unref((LogMessage *) g_ptr_array_index(self->messages, i)); } g_ptr_array_set_size(self->messages, 0); } void correlation_context_free_method(CorrelationContext *self) { correlation_context_clear(self); g_ptr_array_free(self->messages, TRUE); if (self->key.host) g_free((gchar *) self->key.host); if (self->key.program) g_free((gchar *) self->key.program); if (self->key.pid) g_free((gchar *) self->key.pid); g_free(self->key.session_id); } CorrelationContext * correlation_context_new(CorrelationKey *key) { CorrelationContext *self = g_new0(CorrelationContext, 1); correlation_context_init(self, key); return self; } CorrelationContext * correlation_context_ref(CorrelationContext *self) { self->ref_cnt++; return self; } void correlation_context_unref(CorrelationContext *self) { if (--self->ref_cnt == 0) { if (self->free_fn) self->free_fn(self); g_free(self); } } syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-context.h000066400000000000000000000046301450431004300255230ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_CORRELATION_CONTEXT_H_INCLUDED #define CORRELATION_CORRELATION_CONTEXT_H_INCLUDED #include "syslog-ng.h" #include "correlation-key.h" #include "timerwheel.h" #include "logmsg/logmsg.h" #include "template/templates.h" /* This class encapsulates a correlation context, keyed by CorrelationKey, type == PSK_RULE. */ typedef struct _CorrelationContext CorrelationContext; struct _CorrelationContext { /* key in the hashtable. */ CorrelationKey key; /* timeout timer */ TWEntry *timer; /* messages belonging to this context */ GPtrArray *messages; gint ref_cnt; void (*clear)(CorrelationContext *s); void (*free_fn)(CorrelationContext *s); }; static inline LogMessage * correlation_context_get_last_message(CorrelationContext *self) { g_assert(self->messages->len > 0); return (LogMessage *) g_ptr_array_index(self->messages, self->messages->len - 1); } static inline void correlation_context_clear(CorrelationContext *self) { self->clear(self); } void correlation_context_init(CorrelationContext *self, const CorrelationKey *key); void correlation_context_clear_method(CorrelationContext *self); void correlation_context_free_method(CorrelationContext *self); void correlation_context_sort(CorrelationContext *self, LogTemplate *sort_key); CorrelationContext *correlation_context_new(CorrelationKey *key); CorrelationContext *correlation_context_ref(CorrelationContext *self); void correlation_context_unref(CorrelationContext *self); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-grammar.ym000066400000000000000000000160001450431004300256550ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code top { #include "correlation-parser.h" } %code { #include "dbparser.h" #include "cfg-grammar-internal.h" #include "groupingby.h" #include "group-lines.h" #include "cfg-parser.h" #include "syslog-names.h" #include "messages.h" #include "filter/filter-expr.h" #include SyntheticMessage *last_message; } %define api.prefix {correlation_} /* this parameter is needed in order to instruct bison to use a complete * argument list for yylex/yyerror */ %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {LogParser **instance} %parse-param {gpointer arg} /* INCLUDE_DECLS */ %token KW_DB_PARSER %token KW_GROUPING_BY %token KW_INJECT_MODE %token KW_INHERIT_MODE %token KW_TIMEOUT %token KW_TRIGGER %token KW_WHERE %token KW_HAVING %token KW_AGGREGATE %token KW_DROP_UNMATCHED %token KW_FILE %token KW_PROGRAM_TEMPLATE %token KW_MESSAGE_TEMPLATE %token KW_SORT_KEY %token KW_PREFIX %token KW_GROUP_LINES %token KW_LINE_SEPARATOR %type stateful_parser_inject_mode %type synthetic_message %type inherit_mode %type context_scope %% start : LL_CONTEXT_PARSER parser_expr_db { YYACCEPT; } ; parser_expr_db : KW_DB_PARSER '(' { last_parser = *instance = (LogParser *) log_db_parser_new(configuration); } parser_db_opts ')' | KW_GROUPING_BY '(' { last_parser = *instance = grouping_by_new(configuration); } grouping_by_opts ')' | KW_GROUP_LINES '(' { last_parser = *instance = group_lines_new(configuration); last_multi_line_options = group_lines_get_multi_line_options(last_parser); } group_lines_opts ')' ; parser_db_opts : parser_db_opt parser_db_opts | ; /* NOTE: we don't support parser_opt as we don't want the user to specify a template */ parser_db_opt : KW_FILE '(' path_no_check ')' { log_db_parser_set_db_file(((LogDBParser *) last_parser), $3); free($3); } | KW_DROP_UNMATCHED '(' yesno ')' { log_db_parser_set_drop_unmatched(((LogDBParser *) last_parser), $3); }; | KW_PROGRAM_TEMPLATE '(' template_content ')' { log_db_parser_set_program_template_ref(last_parser, $3); } | KW_MESSAGE_TEMPLATE '(' template_content ')' { log_parser_set_template(last_parser, $3); } | KW_PREFIX '(' string ')' { log_db_parser_set_prefix(((LogDBParser *) last_parser), $3); free($3); }; | stateful_parser_opt ; stateful_parser_opt : KW_INJECT_MODE '(' stateful_parser_inject_mode ')' { stateful_parser_set_inject_mode(((StatefulParser *) last_parser), $3); } | KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_parser->super, $3); free($3); } | parser_opt ; stateful_parser_inject_mode : string { $$ = stateful_parser_lookup_inject_mode($1); CHECK_ERROR($$ != -1, @1, "Unknown inject-mode %s", $1); free($1); } | KW_INTERNAL { $$ = stateful_parser_lookup_inject_mode("internal"); } ; grouping_parser_opt : KW_KEY '(' template_content ')' { grouping_parser_set_key_template(last_parser, $3); log_template_unref($3); } | KW_SORT_KEY '(' template_content ')' { grouping_parser_set_sort_key_template(last_parser, $3); log_template_unref($3); } | KW_SCOPE '(' context_scope ')' { grouping_parser_set_scope(last_parser, $3); } | KW_TIMEOUT '(' nonnegative_integer ')' { CHECK_ERROR($3 >= 1, @1, "timeout() needs to be greater than zero"); grouping_parser_set_timeout(last_parser, $3); } ; grouping_by_opts : grouping_by_opt grouping_by_opts | ; grouping_by_opt : KW_WHERE '(' { FilterExprNode *filter_expr; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1); grouping_by_set_where_condition(last_parser, filter_expr); } ')' | KW_HAVING '(' { FilterExprNode *filter_expr; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1); grouping_by_set_having_condition(last_parser, filter_expr); } ')' | KW_AGGREGATE '(' synthetic_message ')' { grouping_by_set_synthetic_message(last_parser, $3); } | KW_TRIGGER '(' { FilterExprNode *filter_expr; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1); grouping_by_set_trigger_condition(last_parser, filter_expr); } ')' | KW_PREFIX '(' string ')' { grouping_by_set_prefix(last_parser, $3); free($3); }; | stateful_parser_opt | grouping_parser_opt ; group_lines_opts : group_lines_opt group_lines_opts | ; group_lines_opt : multi_line_option | parser_opt | grouping_parser_opt | KW_LINE_SEPARATOR '(' string ')' { group_lines_set_separator(last_parser, $3); free($3); } ; synthetic_message : { last_message = synthetic_message_new(); } synthetic_message_opts { $$ = last_message; } ; synthetic_message_opts : synthetic_message_opt synthetic_message_opts | ; synthetic_message_opt : KW_INHERIT_MODE '(' inherit_mode ')' { synthetic_message_set_inherit_mode(last_message, $3); } | KW_VALUE '(' string template_content ')' { synthetic_message_add_value_template(last_message, $3, $4); free($3); log_template_unref($4); } | KW_TAGS '(' string ')' { synthetic_message_add_tag(last_message, $3); free($3); } ; inherit_mode : string { $$ = synthetic_message_lookup_inherit_mode($1); free($1); CHECK_ERROR($$ >= 0, @1, "unknown inherit-mode()"); } ; context_scope : string { $$ = correlation_key_lookup_scope($1); free($1); CHECK_ERROR($$ >= 0, @1, "unknown context-scope()"); } ; /* INCLUDE_RULES */ %% syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-key.c000066400000000000000000000066051450431004300246260ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "correlation-key.h" #include "logmsg/logmsg.h" #include /********************************************************* * CorrelationKey, is the key in the state hash table *********************************************************/ guint correlation_key_hash(gconstpointer k) { CorrelationKey *key = (CorrelationKey *) k; guint hash; hash = (key->scope << 30); switch (key->scope) { case RCS_PROCESS: hash += g_str_hash(key->pid); case RCS_PROGRAM: hash += g_str_hash(key->program); case RCS_HOST: hash += g_str_hash(key->host); case RCS_GLOBAL: break; default: g_assert_not_reached(); break; } return hash + g_str_hash(key->session_id); } gboolean correlation_key_equal(gconstpointer k1, gconstpointer k2) { CorrelationKey *key1 = (CorrelationKey *) k1; CorrelationKey *key2 = (CorrelationKey *) k2; if (key1->scope != key2->scope) return FALSE; switch (key1->scope) { case RCS_PROCESS: if (strcmp(key1->pid, key2->pid) != 0) return FALSE; case RCS_PROGRAM: if (strcmp(key1->program, key2->program) != 0) return FALSE; case RCS_HOST: if (strcmp(key1->host, key2->host) != 0) return FALSE; case RCS_GLOBAL: break; default: g_assert_not_reached(); break; } if (strcmp(key1->session_id, key2->session_id) != 0) return FALSE; return TRUE; } /* fills a CorrelationKey structure with borrowed values */ void correlation_key_init(CorrelationKey *self, CorrelationScope scope, LogMessage *msg, gchar *session_id) { memset(self, 0, sizeof(*self)); self->scope = scope; self->session_id = session_id; /* NVTable ensures that builtin name-value pairs are always NUL terminated */ switch (scope) { case RCS_PROCESS: self->pid = log_msg_get_value(msg, LM_V_PID, NULL); case RCS_PROGRAM: self->program = log_msg_get_value(msg, LM_V_PROGRAM, NULL); case RCS_HOST: self->host = log_msg_get_value(msg, LM_V_HOST, NULL); case RCS_GLOBAL: break; default: g_assert_not_reached(); break; } } gint correlation_key_lookup_scope(const gchar *scope) { if (strcasecmp(scope, "global") == 0) return RCS_GLOBAL; else if (strcasecmp(scope, "host") == 0) return RCS_HOST; else if (strcasecmp(scope, "program") == 0) return RCS_PROGRAM; else if (strcasecmp(scope, "process") == 0) return RCS_PROCESS; return -1; } syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-key.h000066400000000000000000000044721450431004300246330ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_CORRELATION_KEY_H_INCLUDED #define CORRELATION_CORRELATION_KEY_H_INCLUDED #include "syslog-ng.h" /* rule context scope */ typedef enum { /* correlation happens globally, e.g. log messages even on different hosts are considered */ RCS_GLOBAL, /* correlation happens inside the same host only, e.g. messages from other hosts are not considered */ RCS_HOST, /* correlation happens for the same program only, e.g. messages from other programs are not considered */ RCS_PROGRAM, /* correlation happens for the same process only, e.g. messages from a different program/pid are not considered */ RCS_PROCESS, } CorrelationScope; gint correlation_key_lookup_scope(const gchar *scope); /* Our state hash contains a mixed set of values, they are either * correlation contexts or the state entry required by rate limiting. */ typedef struct _CorrelationKey { const gchar *host; const gchar *program; const gchar *pid; gchar *session_id; /* we use guint8 to limit the size of this structure, we can have 10s of * thousands of this structure present in memory */ guint8 /* CorrelationScope */ scope; } CorrelationKey; guint correlation_key_hash(gconstpointer k); gboolean correlation_key_equal(gconstpointer k1, gconstpointer k2); void correlation_key_init(CorrelationKey *self, CorrelationScope scope, LogMessage *msg, gchar *session_id); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-parser.c000066400000000000000000000046421450431004300253310ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "dbparser.h" #include "cfg-parser.h" #include "correlation-grammar.h" extern int correlation_debug; int correlation_parse(CfgLexer *lexer, LogParser **instance, gpointer arg); static CfgLexerKeyword correlation_keywords[] = { { "db_parser", KW_DB_PARSER }, { "grouping_by", KW_GROUPING_BY }, { "file", KW_FILE }, /* correlate options */ { "inject_mode", KW_INJECT_MODE }, { "drop_unmatched", KW_DROP_UNMATCHED }, { "key", KW_KEY }, { "sort_key", KW_SORT_KEY }, { "scope", KW_SCOPE }, { "timeout", KW_TIMEOUT }, { "aggregate", KW_AGGREGATE }, { "inherit_mode", KW_INHERIT_MODE }, { "where", KW_WHERE }, { "having", KW_HAVING }, { "trigger", KW_TRIGGER }, { "value", KW_VALUE }, { "prefix", KW_PREFIX }, { "program_template", KW_PROGRAM_TEMPLATE }, { "message_template", KW_MESSAGE_TEMPLATE }, /* group lines */ { "group_lines", KW_GROUP_LINES }, { "line_separator", KW_LINE_SEPARATOR }, { NULL } }; CfgParser correlation_parser = { #if SYSLOG_NG_ENABLE_DEBUG .debug_flag = &correlation_debug, #endif .name = "correlation", .keywords = correlation_keywords, .parse = (gint (*)(CfgLexer *, gpointer *, gpointer)) correlation_parse, .cleanup = (void (*)(gpointer)) log_pipe_unref, }; CFG_PARSER_IMPLEMENT_LEXER_BINDING(correlation_, CORRELATION_, LogParser **) syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-parser.h000066400000000000000000000022731450431004300253340ustar00rootroot00000000000000/* * Copyright (c) 2002-2010 Balabit * Copyright (c) 1998-2010 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PARSER_H_INCLUDED #define CORRELATION_PARSER_H_INCLUDED #include "cfg-parser.h" #include "parser/parser-expr.h" extern CfgParser correlation_parser; CFG_PARSER_DECLARE_LEXER_BINDING(correlation_, CORRELATION_, LogParser **) #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation-plugin.c000066400000000000000000000040251450431004300253260ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "cfg-parser.h" #include "dbparser.h" #include "groupingby.h" #include "plugin.h" #include "plugin-types.h" extern CfgParser correlation_parser; static Plugin correlation_plugins[] = { { .type = LL_CONTEXT_PARSER, .name = "db-parser", .parser = &correlation_parser, }, { .type = LL_CONTEXT_PARSER, .name = "grouping-by", .parser = &correlation_parser, }, { .type = LL_CONTEXT_PARSER, .name = "group-lines", .parser = &correlation_parser, }, }; gboolean correlation_module_init(PluginContext *context, CfgArgs *args) { pattern_db_global_init(); grouping_parser_global_init(); plugin_register(context, correlation_plugins, G_N_ELEMENTS(correlation_plugins)); return TRUE; } const ModuleInfo module_info = { .canonical_name = "correlation", .version = SYSLOG_NG_VERSION, .description = "The correlation module implements db-parser(), grouping-by() and other correlation based functionality for syslog-ng.", .core_revision = SYSLOG_NG_SOURCE_REVISION, .plugins = correlation_plugins, .plugins_len = G_N_ELEMENTS(correlation_plugins), }; syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation.c000066400000000000000000000133321450431004300240330ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "correlation.h" #include "correlation-key.h" #include "correlation-context.h" #include "timeutils/cache.h" #include "timeutils/misc.h" void correlation_state_tx_begin(CorrelationState *self) { g_mutex_lock(&self->lock); } void correlation_state_tx_end(CorrelationState *self) { g_mutex_unlock(&self->lock); } CorrelationContext * correlation_state_tx_lookup_context(CorrelationState *self, const CorrelationKey *key) { return g_hash_table_lookup(self->state, key); } void correlation_state_tx_store_context(CorrelationState *self, CorrelationContext *context, gint timeout) { g_assert(context->timer == NULL); g_hash_table_insert(self->state, &context->key, context); context->timer = timer_wheel_add_timer(self->timer_wheel, timeout, self->expire_callback, correlation_context_ref(context), (GDestroyNotify) correlation_context_unref); } void correlation_state_tx_remove_context(CorrelationState *self, CorrelationContext *context) { /* NOTE: in expire callbacks our timer is already deleted and thus it is * set to NULL in which case we don't need to remove it again. */ if (context->timer) timer_wheel_del_timer(self->timer_wheel, context->timer); g_hash_table_remove(self->state, &context->key); } void correlation_state_tx_update_context(CorrelationState *self, CorrelationContext *context, gint timeout) { g_assert(context->timer != NULL); timer_wheel_mod_timer(self->timer_wheel, context->timer, timeout); } void correlation_state_expire_all(CorrelationState *self, gpointer caller_context) { g_mutex_lock(&self->lock); timer_wheel_expire_all(self->timer_wheel, caller_context); g_mutex_unlock(&self->lock); } void correlation_state_advance_time(CorrelationState *self, gint timeout, gpointer caller_context) { guint64 new_time; g_mutex_lock(&self->lock); new_time = timer_wheel_get_time(self->timer_wheel) + timeout; timer_wheel_set_time(self->timer_wheel, new_time, caller_context); g_mutex_unlock(&self->lock); } void correlation_state_set_time(CorrelationState *self, guint64 sec, gpointer caller_context) { GTimeVal now; /* clamp the current time between the timestamp of the current message * (low limit) and the current system time (high limit). This ensures * that incorrect clocks do not skew the current time know by the * correlation engine too much. */ cached_g_current_time(&now); self->last_tick = now; if (sec < now.tv_sec) now.tv_sec = sec; g_mutex_lock(&self->lock); timer_wheel_set_time(self->timer_wheel, now.tv_sec, caller_context); g_mutex_unlock(&self->lock); } guint64 correlation_state_get_time(CorrelationState *self) { return timer_wheel_get_time(self->timer_wheel); } gboolean correlation_state_timer_tick(CorrelationState *self, gpointer caller_context) { GTimeVal now; glong diff; gboolean updated = FALSE; g_mutex_lock(&self->lock); cached_g_current_time(&now); diff = g_time_val_diff(&now, &self->last_tick); if (diff > 1e6) { glong diff_sec = (glong)(diff / 1e6); timer_wheel_set_time(self->timer_wheel, timer_wheel_get_time(self->timer_wheel) + diff_sec, caller_context); /* update last_tick, take the fraction of the seconds not calculated into this update into account */ self->last_tick = now; g_time_val_add(&self->last_tick, - (glong)(diff - diff_sec * 1e6)); updated = TRUE; } else if (diff < 0) { /* time moving backwards, this can only happen if the computer's time * is changed. We don't update patterndb's idea of the time now, wait * another tick instead to update that instead. */ self->last_tick = now; } g_mutex_unlock(&self->lock); return updated; } CorrelationState * correlation_state_new(TWCallbackFunc expire_callback) { CorrelationState *self = g_new0(CorrelationState, 1); g_mutex_init(&self->lock); self->state = g_hash_table_new_full(correlation_key_hash, correlation_key_equal, NULL, (GDestroyNotify) correlation_context_unref); self->timer_wheel = timer_wheel_new(); cached_g_current_time(&self->last_tick); g_atomic_counter_set(&self->ref_cnt, 1); self->expire_callback = expire_callback; return self; } void _free(CorrelationState *self) { if (self->state) g_hash_table_destroy(self->state); timer_wheel_free(self->timer_wheel); g_mutex_clear(&self->lock); g_free(self); } CorrelationState * correlation_state_ref(CorrelationState *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0); if (self) { g_atomic_counter_inc(&self->ref_cnt); } return self; } void correlation_state_unref(CorrelationState *self) { g_assert(!self || g_atomic_counter_get(&self->ref_cnt)); if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt))) _free(self); } syslog-ng-syslog-ng-4.4.0/modules/correlation/correlation.h000066400000000000000000000051631450431004300240430ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_CORRELATION_H_INCLUDED #define CORRELATION_CORRELATION_H_INCLUDED #include "syslog-ng.h" #include "correlation-key.h" #include "correlation-context.h" #include "timerwheel.h" #include "timeutils/unixtime.h" typedef struct _CorrelationState { GAtomicCounter ref_cnt; GMutex lock; GHashTable *state; TimerWheel *timer_wheel; TWCallbackFunc expire_callback; GTimeVal last_tick; } CorrelationState; void correlation_state_tx_begin(CorrelationState *self); void correlation_state_tx_end(CorrelationState *self); CorrelationContext *correlation_state_tx_lookup_context(CorrelationState *self, const CorrelationKey *key); void correlation_state_tx_store_context(CorrelationState *self, CorrelationContext *context, gint timeout); void correlation_state_tx_remove_context(CorrelationState *self, CorrelationContext *context); void correlation_state_tx_update_context(CorrelationState *self, CorrelationContext *context, gint timeout); void correlation_state_set_time(CorrelationState *self, guint64 sec, gpointer caller_context); guint64 correlation_state_get_time(CorrelationState *self); gboolean correlation_state_timer_tick(CorrelationState *self, gpointer caller_context); void correlation_state_expire_all(CorrelationState *self, gpointer caller_context); void correlation_state_advance_time(CorrelationState *self, gint timeout, gpointer caller_context); void correlation_state_init_instance(CorrelationState *self); void correlation_state_deinit_instance(CorrelationState *self); CorrelationState *correlation_state_new(TWCallbackFunc expire); CorrelationState *correlation_state_ref(CorrelationState *self); void correlation_state_unref(CorrelationState *self); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/dbparser.c000066400000000000000000000225041450431004300233150ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "dbparser.h" #include "patterndb.h" #include "radix.h" #include "apphook.h" #include "reloc.h" #include "stateful-parser.h" #include #include #include struct _LogDBParser { StatefulParser super; GMutex lock; struct iv_timer tick; PatternDB *db; gchar *db_file; gchar *prefix; time_t db_file_last_check; ino_t db_file_inode; time_t db_file_mtime; gboolean db_file_reloading; gboolean drop_unmatched; LogTemplate *program_template; }; static void log_db_parser_emit(LogMessage *msg, gpointer user_data) { LogDBParser *self = (LogDBParser *) user_data; stateful_parser_emit_synthetic(&self->super, msg); msg_debug("db-parser: emitting synthetic message", evt_tag_str("msg", log_msg_get_value(msg, LM_V_MESSAGE, NULL)), log_pipe_location_tag(&self->super.super.super)); } static void log_db_parser_reload_database(LogDBParser *self) { struct stat st; GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super); if (stat(self->db_file, &st) < 0) { msg_error("Error stating pattern database file, no automatic reload will be performed", evt_tag_str("file", self->db_file), evt_tag_str("error", g_strerror(errno)), log_pipe_location_tag(&self->super.super.super)); return; } if ((self->db_file_inode == st.st_ino && self->db_file_mtime == st.st_mtime)) { return; } self->db_file_inode = st.st_ino; self->db_file_mtime = st.st_mtime; if (!pattern_db_reload_ruleset(self->db, cfg, self->db_file)) { msg_error("Error reloading pattern database, no automatic reload will be performed", evt_tag_str("file", self->db_file), log_pipe_location_tag(&self->super.super.super)); } else { /* free the old database if the new was loaded successfully */ msg_notice("Log pattern database reloaded", evt_tag_str("file", self->db_file), evt_tag_str("version", pattern_db_get_ruleset_version(self->db)), evt_tag_str("pub_date", pattern_db_get_ruleset_pub_date(self->db)), log_pipe_location_tag(&self->super.super.super)); } } static void log_db_parser_timer_tick(gpointer s) { LogDBParser *self = (LogDBParser *) s; pattern_db_timer_tick(self->db); iv_validate_now(); self->tick.expires = iv_now; self->tick.expires.tv_sec++; iv_timer_register(&self->tick); } static gchar * log_db_parser_format_persist_name(LogDBParser *self) { static gchar persist_name[512]; g_snprintf(persist_name, sizeof(persist_name), "db-parser(%s)", self->db_file); return persist_name; } static gboolean log_db_parser_init(LogPipe *s) { LogDBParser *self = (LogDBParser *) s; GlobalConfig *cfg = log_pipe_get_config(s); self->db = cfg_persist_config_fetch(cfg, log_db_parser_format_persist_name(self)); if (!self->db) self->db = pattern_db_new(self->prefix); log_db_parser_reload_database(self); if (self->db) { pattern_db_set_emit_func(self->db, log_db_parser_emit, self); pattern_db_set_program_template(self->db, self->program_template); } iv_validate_now(); IV_TIMER_INIT(&self->tick); self->tick.cookie = self; self->tick.handler = log_db_parser_timer_tick; self->tick.expires = iv_now; self->tick.expires.tv_sec++; self->tick.expires.tv_nsec = 0; iv_timer_register(&self->tick); if (!self->db) return FALSE; return stateful_parser_init_method(s); } static gboolean log_db_parser_deinit(LogPipe *s) { LogDBParser *self = (LogDBParser *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (iv_timer_registered(&self->tick)) { iv_timer_unregister(&self->tick); } cfg_persist_config_add(cfg, log_db_parser_format_persist_name(self), self->db, (GDestroyNotify) pattern_db_free); self->db = NULL; return stateful_parser_deinit_method(s); } static gboolean log_db_parser_process(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const char *input, gsize input_len) { LogDBParser *self = (LogDBParser *) s; gboolean matched = FALSE; if (G_UNLIKELY(!self->db_file_reloading && (self->db_file_last_check == 0 || self->db_file_last_check < (*pmsg)->timestamps[LM_TS_RECVD].ut_sec - 5))) { /* first check if we need to reload without doing a lock, then grab * the lock, recheck the condition to rule out parallel database * reloads. This avoids a lock in the fast path. */ g_mutex_lock(&self->lock); if (!self->db_file_reloading && (self->db_file_last_check == 0 || self->db_file_last_check < (*pmsg)->timestamps[LM_TS_RECVD].ut_sec - 5)) { self->db_file_last_check = (*pmsg)->timestamps[LM_TS_RECVD].ut_sec; self->db_file_reloading = TRUE; g_mutex_unlock(&self->lock); /* only one thread may come here, the others may continue to use self->db, until we update it here. */ log_db_parser_reload_database(self); g_mutex_lock(&self->lock); self->db_file_reloading = FALSE; } g_mutex_unlock(&self->lock); } if (self->db) { log_msg_make_writable(pmsg, path_options); msg_trace("db-parser message processing started", evt_tag_str("input", input), evt_tag_msg_reference(*pmsg)); if (G_UNLIKELY(self->super.super.template_obj)) matched = pattern_db_process_with_custom_message(self->db, *pmsg, input, input_len); else matched = pattern_db_process(self->db, *pmsg); } if (self->drop_unmatched && !matched) { msg_debug("db-parser failed", evt_tag_str("error", "db-parser() failed to parse its input and drop-unmatched flag was specified"), evt_tag_str("input", input)); } if (!self->drop_unmatched) matched = TRUE; if (self->super.inject_mode == LDBP_IM_AGGREGATE_ONLY) matched = FALSE; return matched; } void log_db_parser_set_db_file(LogDBParser *self, const gchar *db_file) { g_free(self->db_file); self->db_file = g_strdup(db_file); } void log_db_parser_set_prefix(LogDBParser *self, const gchar *prefix) { g_free(self->prefix); self->prefix = g_strdup(prefix); } void log_db_parser_set_drop_unmatched(LogDBParser *self, gboolean setting) { self->drop_unmatched = setting; } /* * NOTE: we could be smarter than this by sharing the radix tree in this case. */ static LogPipe * log_db_parser_clone(LogPipe *s) { LogDBParser *cloned; LogDBParser *self = (LogDBParser *) s; cloned = (LogDBParser *) log_db_parser_new(s->cfg); stateful_parser_clone_settings(&self->super, &cloned->super); log_db_parser_set_db_file(cloned, self->db_file); log_db_parser_set_prefix(cloned, self->prefix); log_db_parser_set_drop_unmatched(cloned, self->drop_unmatched); log_db_parser_set_program_template_ref(&cloned->super.super, log_template_ref(self->program_template)); return &cloned->super.super.super; } void log_db_parser_set_program_template_ref(LogParser *s, LogTemplate *program_template) { LogDBParser *self = (LogDBParser *) s; log_template_unref(self->program_template); self->program_template = program_template; } static void log_db_parser_free(LogPipe *s) { LogDBParser *self = (LogDBParser *) s; log_template_unref(self->program_template); g_mutex_clear(&self->lock); if (self->db) pattern_db_free(self->db); g_free(self->db_file); g_free(self->prefix); stateful_parser_free_method(s); } LogParser * log_db_parser_new(GlobalConfig *cfg) { LogDBParser *self = g_new0(LogDBParser, 1); stateful_parser_init_instance(&self->super, cfg); self->super.super.super.free_fn = log_db_parser_free; self->super.super.super.init = log_db_parser_init; self->super.super.super.deinit = log_db_parser_deinit; self->super.super.super.clone = log_db_parser_clone; self->super.super.process = log_db_parser_process; self->db_file = g_strdup(get_installation_path_for(PATH_PATTERNDB_FILE)); g_mutex_init(&self->lock); if (cfg_is_config_version_older(cfg, VERSION_VALUE_3_3)) { msg_warning_once("WARNING: The default behaviour for injecting messages in db-parser() has changed in " VERSION_3_3 " from internal to pass-through, use an explicit inject-mode(internal) option for old behaviour"); self->super.inject_mode = LDBP_IM_INTERNAL; } return &self->super.super; } syslog-ng-syslog-ng-4.4.0/modules/correlation/dbparser.h000066400000000000000000000030711450431004300233200ustar00rootroot00000000000000/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef DBPARSER_H_INCLUDED #define DBPARSER_H_INCLUDED #include "stateful-parser.h" #include "patterndb.h" #define PATH_PATTERNDB_FILE SYSLOG_NG_PATH_LOCALSTATEDIR "/patterndb.xml" typedef struct _LogDBParser LogDBParser; void log_db_parser_set_drop_unmatched(LogDBParser *self, gboolean setting); void log_db_parser_set_program_template_ref(LogParser *s, LogTemplate *program_template); void log_db_parser_set_db_file(LogDBParser *self, const gchar *db_file); void log_db_parser_set_prefix(LogDBParser *self, const gchar *prefix); LogParser *log_db_parser_new(GlobalConfig *cfg); void log_pattern_database_init(void); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/group-lines.c000066400000000000000000000230621450431004300237570ustar00rootroot00000000000000/* * Copyright (c) 2023 One Identity LLC. * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "group-lines.h" #include "correlation.h" #include "correlation-context.h" #include "scratch-buffers.h" #include "str-utils.h" #include "messages.h" #include "grouping-parser.h" #include "id-counter.h" #include typedef struct _GroupLinesContext { CorrelationContext super; MultiLineLogic *multi_line; GString *line_buffer; } GroupLinesContext; static void group_lines_context_update(GroupLinesContext *self, LogMessage *msg) { if (self->super.messages->len > 0) { LogMessage *old_msg = g_ptr_array_index(self->super.messages, 0); log_msg_unref(old_msg); g_ptr_array_index(self->super.messages, 0) = log_msg_ref(msg); } else g_ptr_array_add(self->super.messages, log_msg_ref(msg)); } static void group_lines_context_clear(CorrelationContext *s) { GroupLinesContext *self = (GroupLinesContext *) s; g_string_truncate(self->line_buffer, 0); correlation_context_clear_method(s); } static void group_lines_context_free(CorrelationContext *s) { GroupLinesContext *self = (GroupLinesContext *) s; multi_line_logic_free(self->multi_line); g_string_free(self->line_buffer, TRUE); correlation_context_free_method(&self->super); } GroupLinesContext * group_lines_context_new(const CorrelationKey *key, MultiLineLogic *multi_line) { GroupLinesContext *self = g_new0(GroupLinesContext, 1); correlation_context_init(&self->super, key); self->super.free_fn = group_lines_context_free; self->super.clear = group_lines_context_clear; self->line_buffer = g_string_sized_new(1024); self->multi_line = multi_line; return self; } typedef struct _GroupLines { GroupingParser super; guint clone_id; IdCounter *id_counter; gchar *separator; gsize separator_len; MultiLineOptions multi_line_options; } GroupLines; /* public functions */ MultiLineOptions * group_lines_get_multi_line_options(LogParser *s) { GroupLines *self = (GroupLines *) s; return &self->multi_line_options; } void group_lines_set_separator(LogParser *s, const gchar *separator) { GroupLines *self = (GroupLines *) s; g_free(self->separator); self->separator = g_strdup(separator); self->separator_len = strlen(self->separator); } static CorrelationContext * _construct_context(GroupingParser *s, CorrelationKey *key) { GroupLines *self = (GroupLines *) s; return &group_lines_context_new(key, multi_line_factory_construct(&self->multi_line_options))->super; } static void _update_context_add_message(GroupLines *self, GroupLinesContext *context, LogMessage *msg, const gchar *line, gsize line_len) { group_lines_context_update(context, msg); msg_debug("group-lines: accumulating new segment into the line", evt_tag_str("key", context->super.key.session_id), evt_tag_mem("segment", line, line_len), evt_tag_str("line", context->line_buffer->str)); if (context->line_buffer->len) g_string_append_len(context->line_buffer, self->separator, self->separator_len); g_string_append_len(context->line_buffer, line, line_len); } static const gchar * _get_payload(GroupLines *self, LogMessage *msg, gssize *len) { LogTemplate *template = self->super.super.super.template_obj; if (!template) return log_msg_get_value(msg, LM_V_MESSAGE, len); if (log_template_is_trivial(template)) return log_template_get_trivial_value(template, msg, len); GString *buf = scratch_buffers_alloc(); log_template_format(template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, buf); *len = buf->len; return buf->str; } static GroupingParserUpdateContextResult _update_context(GroupingParser *s, CorrelationContext *c, LogMessage *msg) { GroupLines *self = (GroupLines *) s; GroupLinesContext *context = (GroupLinesContext *) c; gssize line_len; const gchar *line = _get_payload(self, msg, &line_len); gint verdict = multi_line_logic_accumulate_line(context->multi_line, (const guchar *) context->line_buffer->str, context->line_buffer->len, (const guchar *) line, line_len); if (verdict & MLL_EXTRACTED) { if (verdict & MLL_CONSUME_SEGMENT) { gint drop_length = (verdict & MLL_CONSUME_PARTIAL_AMOUNT_MASK) >> MLL_CONSUME_PARTIAL_AMOUNT_SHIFT; _update_context_add_message(self, context, msg, line, line_len - drop_length); msg_debug("group-lines: accumulated line extracted", evt_tag_str("key", context->super.key.session_id), evt_tag_str("line", context->line_buffer->str)); return GP_CONTEXT_COMPLETE; } else if (verdict & MLL_REWIND_SEGMENT) { msg_debug("group-lines: accumulated line extracted", evt_tag_str("key", context->super.key.session_id), evt_tag_str("line", context->line_buffer->str)); return GP_STARTS_NEW_CONTEXT; } else g_assert_not_reached(); } else if (verdict & MLL_WAITING) { if (verdict & MLL_CONSUME_SEGMENT) { _update_context_add_message(self, context, msg, line, line_len); return GP_CONTEXT_UPDATED; } else g_assert_not_reached(); return FALSE; } else g_assert_not_reached(); } static LogMessage * _generate_synthetic_msg(GroupLines *self, GroupLinesContext *context) { LogPathOptions path_options = LOG_PATH_OPTIONS_INIT; path_options.ack_needed = FALSE; LogMessage *msg = log_msg_ref(correlation_context_get_last_message(&context->super)); log_msg_make_writable(&msg, &path_options); return msg; } static LogMessage * _aggregate_context(GroupingParser *s, CorrelationContext *c) { GroupLines *self = (GroupLines *) s; GroupLinesContext *context = (GroupLinesContext *) c; LogMessage *msg = _generate_synthetic_msg(self, context); log_msg_set_value(msg, LM_V_MESSAGE, context->line_buffer->str, context->line_buffer->len); return msg; } static const gchar * _format_persist_name(const LogPipe *s) { static gchar persist_name[512]; GroupLines *self = (GroupLines *)s; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "group-lines.%s(clone=%d)", s->persist_name, self->clone_id); else g_snprintf(persist_name, sizeof(persist_name), "group-lines(%s,scope=%d,clone=%d)", self->super.key_template->template_str, self->super.scope, self->clone_id); return persist_name; } static gboolean _init(LogPipe *s) { GroupLines *self = (GroupLines *) s; self->id_counter = NULL; if (self->super.timeout < 1) { msg_error("timeout() needs to be specified explicitly and must be greater than 0 in the group-lines() parser", log_pipe_location_tag(s)); return FALSE; } if (!self->super.key_template) { msg_error("The key() option is mandatory for the group-lines() parser", log_pipe_location_tag(s)); return FALSE; } if (!multi_line_options_validate(&self->multi_line_options)) return FALSE; return grouping_parser_init_method(s); } static LogPipe * _clone(LogPipe *s) { GroupLines *self = (GroupLines *) s; GroupLines *cloned; cloned = (GroupLines *) group_lines_new(s->cfg); grouping_parser_clone_settings(&self->super, &cloned->super); group_lines_set_separator(&cloned->super.super.super, self->separator); multi_line_options_copy(&cloned->multi_line_options, &self->multi_line_options); id_counter_unref(cloned->id_counter); cloned->id_counter = id_counter_ref(self->id_counter); cloned->clone_id = id_counter_get_next_id(cloned->id_counter); return &cloned->super.super.super.super; } static void _free(LogPipe *s) { GroupLines *self = (GroupLines *) s; id_counter_unref(self->id_counter); multi_line_options_destroy(&self->multi_line_options); g_free(self->separator); grouping_parser_free_method(s); } LogParser * group_lines_new(GlobalConfig *cfg) { GroupLines *self = g_new0(GroupLines, 1); self->id_counter = id_counter_new(); self->clone_id = id_counter_get_next_id(self->id_counter); grouping_parser_init_instance(&self->super, cfg); self->super.super.super.super.init = _init; self->super.super.super.super.free_fn = _free; self->super.super.super.super.clone = _clone; self->super.super.super.super.generate_persist_name = _format_persist_name; self->super.scope = RCS_GLOBAL; self->super.construct_context = _construct_context; self->super.update_context = _update_context; self->super.aggregate_context = _aggregate_context; self->super.super.inject_mode = LDBP_IM_AGGREGATE_ONLY; group_lines_set_separator(&self->super.super.super, "\n"); multi_line_options_defaults(&self->multi_line_options); return &self->super.super.super; } syslog-ng-syslog-ng-4.4.0/modules/correlation/group-lines.h000066400000000000000000000024641450431004300237670ustar00rootroot00000000000000/* * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_GROUP_LINES_PARSER_H_INCLUDED #define CORRELATION_GROUP_LINES_PARSER_H_INCLUDED #include "stateful-parser.h" #include "synthetic-message.h" #include "multi-line/multi-line-factory.h" MultiLineOptions *group_lines_get_multi_line_options(LogParser *s); void group_lines_set_separator(LogParser *s, const gchar *separator); LogParser *group_lines_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/grouping-parser.c000066400000000000000000000303001450431004300246300ustar00rootroot00000000000000/* * Copyright (c) 2015 BalaBit * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "grouping-parser.h" #include "scratch-buffers.h" #include "str-utils.h" void grouping_parser_set_key_template(LogParser *s, LogTemplate *key_template) { GroupingParser *self = (GroupingParser *) s; log_template_unref(self->key_template); self->key_template = log_template_ref(key_template); } void grouping_parser_set_sort_key_template(LogParser *s, LogTemplate *sort_key) { GroupingParser *self = (GroupingParser *) s; log_template_unref(self->sort_key_template); self->sort_key_template = log_template_ref(sort_key); } void grouping_parser_set_scope(LogParser *s, CorrelationScope scope) { GroupingParser *self = (GroupingParser *) s; self->scope = scope; } void grouping_parser_set_timeout(LogParser *s, gint timeout) { GroupingParser *self = (GroupingParser *) s; self->timeout = timeout; } void grouping_parser_clone_settings(GroupingParser *self, GroupingParser *cloned) { stateful_parser_clone_settings(&self->super, &cloned->super); grouping_parser_set_key_template(&cloned->super.super, self->key_template); grouping_parser_set_sort_key_template(&cloned->super.super, self->sort_key_template); grouping_parser_set_timeout(&cloned->super.super, self->timeout); grouping_parser_set_scope(&cloned->super.super, self->scope); } /* * This function can be called any time when pattern-db is not processing * messages, but we expect the correlation timer to move forward. It * doesn't need to be called absolutely regularly as it'll use the current * system time to determine how much time has passed since the last * invocation. See the timing comment at pattern_db_process() for more * information. */ static void _advance_time_by_timer_tick(GroupingParser *self) { StatefulParserEmittedMessages emitted_messages = STATEFUL_PARSER_EMITTED_MESSAGES_INIT; if (correlation_state_timer_tick(self->correlation, &emitted_messages)) { msg_debug("grouping-parser: advancing current time because of timer tick", evt_tag_long("utc", correlation_state_get_time(self->correlation)), log_pipe_location_tag(&self->super.super.super)); } stateful_parser_emitted_messages_flush(&emitted_messages, &self->super); } static void _timer_tick(gpointer s) { GroupingParser *self = (GroupingParser *) s; _advance_time_by_timer_tick(self); iv_validate_now(); self->tick.expires = iv_now; self->tick.expires.tv_sec++; iv_timer_register(&self->tick); } /* NOTE: lock is acquired within correlation_state_set_time() */ void _advance_time_based_on_message(GroupingParser *self, const UnixTime *ls, StatefulParserEmittedMessages *emitted_messages) { correlation_state_set_time(self->correlation, ls->ut_sec, emitted_messages); msg_debug("grouping-parser: advancing current time because of an incoming message", evt_tag_long("utc", correlation_state_get_time(self->correlation)), log_pipe_location_tag(&self->super.super.super)); } static void _load_correlation_state(GroupingParser *self, GlobalConfig *cfg) { CorrelationState *persisted_correlation = cfg_persist_config_fetch(cfg, log_pipe_get_persist_name(&self->super.super.super)); if (persisted_correlation) { correlation_state_unref(self->correlation); self->correlation = persisted_correlation; } timer_wheel_set_associated_data(self->correlation->timer_wheel, log_pipe_ref((LogPipe *)self), (GDestroyNotify)log_pipe_unref); } static void _store_data_in_persist(GroupingParser *self, GlobalConfig *cfg) { cfg_persist_config_add(cfg, log_pipe_get_persist_name(&self->super.super.super), correlation_state_ref(self->correlation), (GDestroyNotify) correlation_state_unref); } LogMessage * grouping_parser_aggregate_context(GroupingParser *self, CorrelationContext *context) { if (context->messages->len == 0) return NULL; if (self->sort_key_template) correlation_context_sort(context, self->sort_key_template); LogMessage *msg = self->aggregate_context(self, context); correlation_context_clear(context); /* correlation_context_free is automatically called when returning from this function by the timerwheel code as a destroy notify callback. */ return msg; } static void _expire_entry(TimerWheel *wheel, guint64 now, gpointer user_data, gpointer caller_context) { CorrelationContext *context = user_data; StatefulParserEmittedMessages *emitted_messages = caller_context; GroupingParser *self = (GroupingParser *) timer_wheel_get_associated_data(wheel); msg_debug("grouping-parser: Expiring correlation context", evt_tag_long("utc", correlation_state_get_time(self->correlation)), evt_tag_str("context-id", context->key.session_id), log_pipe_location_tag(&self->super.super.super)); context->timer = NULL; LogMessage *msg = grouping_parser_aggregate_context(self, context); correlation_state_tx_remove_context(self->correlation, context); if (msg) { stateful_parser_emitted_messages_add(emitted_messages, msg); log_msg_unref(msg); } } CorrelationContext * grouping_parser_lookup_or_create_context(GroupingParser *self, LogMessage *msg) { CorrelationContext *context; CorrelationKey key; GString *buffer = scratch_buffers_alloc(); log_template_format(self->key_template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, buffer); correlation_key_init(&key, self->scope, msg, buffer->str); context = correlation_state_tx_lookup_context(self->correlation, &key); if (!context) { msg_debug("grouping-parser: Correlation context lookup failure, starting a new context", evt_tag_str("key", key.session_id), evt_tag_int("timeout", self->timeout), evt_tag_int("expiration", correlation_state_get_time(self->correlation) + self->timeout), log_pipe_location_tag(&self->super.super.super)); context = grouping_parser_construct_context(self, &key); correlation_state_tx_store_context(self->correlation, context, self->timeout); g_string_steal(buffer); } else { msg_debug("grouping-parser: Correlation context lookup successful", evt_tag_str("key", key.session_id), evt_tag_int("timeout", self->timeout), evt_tag_int("expiration", correlation_state_get_time(self->correlation) + self->timeout), evt_tag_int("num_messages", context->messages->len), log_pipe_location_tag(&self->super.super.super)); } return context; } static void _aggregate_and_emit(GroupingParser *self, CorrelationContext *context, StatefulParserEmittedMessages *emitted_messages) { LogMessage *genmsg = grouping_parser_aggregate_context(self, context); correlation_state_tx_update_context(self->correlation, context, self->timeout); correlation_state_tx_end(self->correlation); if (genmsg) { stateful_parser_emitted_messages_add(emitted_messages, genmsg); log_msg_unref(genmsg); } } void grouping_parser_perform_grouping(GroupingParser *self, LogMessage *msg, StatefulParserEmittedMessages *emitted_messages) { correlation_state_tx_begin(self->correlation); CorrelationContext *context = grouping_parser_lookup_or_create_context(self, msg); GroupingParserUpdateContextResult r = grouping_parser_update_context(self, context, msg); if (r == GP_CONTEXT_UPDATED) { msg_debug("grouping-parser: Correlation context update successful", evt_tag_str("key", context->key.session_id), evt_tag_int("num_messages", context->messages->len), evt_tag_int("expiration", correlation_state_get_time(self->correlation) + self->timeout), log_pipe_location_tag(&self->super.super.super)); correlation_state_tx_update_context(self->correlation, context, self->timeout); correlation_state_tx_end(self->correlation); } else if (r == GP_CONTEXT_COMPLETE) { msg_debug("grouping-parser: Correlation finished, aggregating context", evt_tag_str("key", context->key.session_id), evt_tag_int("num_messages", context->messages->len), evt_tag_int("expiration", correlation_state_get_time(self->correlation) + self->timeout), log_pipe_location_tag(&self->super.super.super)); _aggregate_and_emit(self, context, emitted_messages); } else if (r == GP_STARTS_NEW_CONTEXT) { msg_debug("grouping-parser: Correlation finished, aggregating and starting a new context", evt_tag_str("key", context->key.session_id), evt_tag_int("num_messages", context->messages->len), evt_tag_int("expiration", correlation_state_get_time(self->correlation) + self->timeout), log_pipe_location_tag(&self->super.super.super)); _aggregate_and_emit(self, context, emitted_messages); grouping_parser_perform_grouping(self, msg, emitted_messages); } } gboolean grouping_parser_process_method(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const char *input, gsize input_len) { GroupingParser *self = (GroupingParser *) s; if (grouping_parser_filter_messages(self, pmsg, path_options)) { LogMessage *msg = *pmsg; StatefulParserEmittedMessages emitted_messages = STATEFUL_PARSER_EMITTED_MESSAGES_INIT; _advance_time_based_on_message(self, &msg->timestamps[LM_TS_STAMP], &emitted_messages); grouping_parser_perform_grouping(self, msg, &emitted_messages); stateful_parser_emitted_messages_flush(&emitted_messages, &self->super); } return (self->super.inject_mode != LDBP_IM_AGGREGATE_ONLY); } gboolean grouping_parser_init_method(LogPipe *s) { GroupingParser *self = (GroupingParser *) s; GlobalConfig *cfg = log_pipe_get_config(s); iv_validate_now(); IV_TIMER_INIT(&self->tick); self->tick.cookie = self; self->tick.handler = _timer_tick; self->tick.expires = iv_now; self->tick.expires.tv_sec++; self->tick.expires.tv_nsec = 0; iv_timer_register(&self->tick); _load_correlation_state(self, cfg); return stateful_parser_init_method(s); } gboolean grouping_parser_deinit_method(LogPipe *s) { GroupingParser *self = (GroupingParser *) s; GlobalConfig *cfg = log_pipe_get_config(s); if (iv_timer_registered(&self->tick)) { iv_timer_unregister(&self->tick); } _store_data_in_persist(self, cfg); return stateful_parser_deinit_method(s); } void grouping_parser_free_method(LogPipe *s) { GroupingParser *self = (GroupingParser *) s; log_template_unref(self->key_template); log_template_unref(self->sort_key_template); correlation_state_unref(self->correlation); stateful_parser_free_method(s); } void grouping_parser_init_instance(GroupingParser *self, GlobalConfig *cfg) { stateful_parser_init_instance(&self->super, cfg); self->super.super.super.free_fn = grouping_parser_free_method; self->super.super.super.init = grouping_parser_init_method; self->super.super.super.deinit = grouping_parser_deinit_method; self->super.super.process = grouping_parser_process_method; self->scope = RCS_GLOBAL; self->timeout = -1; self->correlation = correlation_state_new(_expire_entry); } void grouping_parser_global_init(void) { } syslog-ng-syslog-ng-4.4.0/modules/correlation/grouping-parser.h000066400000000000000000000073251450431004300246500ustar00rootroot00000000000000/* * Copyright (c) 2015 BalaBit * Copyright (c) 2023 Balazs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_GROUPING_PARSER_H_INCLUDED #define CORRELATION_GROUPING_PARSER_H_INCLUDED #include "stateful-parser.h" #include "correlation.h" #include typedef struct _GroupingParser GroupingParser; typedef enum { GP_CONTEXT_UPDATED, GP_CONTEXT_COMPLETE, GP_STARTS_NEW_CONTEXT, } GroupingParserUpdateContextResult; struct _GroupingParser { StatefulParser super; struct iv_timer tick; CorrelationState *correlation; LogTemplate *key_template; LogTemplate *sort_key_template; gint timeout; CorrelationScope scope; gboolean (*filter_messages)(GroupingParser *self, LogMessage **pmsg, const LogPathOptions *path_options); CorrelationContext *(*construct_context)(GroupingParser *self, CorrelationKey *key); GroupingParserUpdateContextResult (*update_context)(GroupingParser *self, CorrelationContext *context, LogMessage *msg); LogMessage *(*aggregate_context)(GroupingParser *self, CorrelationContext *context); }; static inline gboolean grouping_parser_filter_messages(GroupingParser *self, LogMessage **pmsg, const LogPathOptions *path_options) { if (self->filter_messages) return self->filter_messages(self, pmsg, path_options); return TRUE; } static inline CorrelationContext * grouping_parser_construct_context(GroupingParser *self, CorrelationKey *key) { if (self->construct_context) return self->construct_context(self, key); return correlation_context_new(key); } static inline gboolean grouping_parser_update_context(GroupingParser *self, CorrelationContext *context, LogMessage *msg) { return self->update_context(self, context, msg); } LogMessage *grouping_parser_aggregate_context(GroupingParser *self, CorrelationContext *context); void grouping_parser_set_key_template(LogParser *s, LogTemplate *key_template); void grouping_parser_set_sort_key_template(LogParser *s, LogTemplate *sort_key); void grouping_parser_set_scope(LogParser *s, CorrelationScope scope); void grouping_parser_set_timeout(LogParser *s, gint timeout); void grouping_parser_clone_settings(GroupingParser *self, GroupingParser *cloned); CorrelationContext *grouping_parser_lookup_or_create_context(GroupingParser *self, LogMessage *msg); void grouping_parser_perform_grouping(GroupingParser *s, LogMessage *msg, StatefulParserEmittedMessages *emitted_mesages); gboolean grouping_parser_process_method(LogParser *s, LogMessage **pmsg, const LogPathOptions *path_options, const char *input, gsize input_len); gboolean grouping_parser_init_method(LogPipe *s); gboolean grouping_parser_deinit_method(LogPipe *s); void grouping_parser_free_method(LogPipe *s); void grouping_parser_init_instance(GroupingParser *self, GlobalConfig *cfg); void grouping_parser_global_init(void); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/groupingby.c000066400000000000000000000167031450431004300237040ustar00rootroot00000000000000/* * Copyright (c) 2023 OneIdentity LLC. * Copyright (c) 2015 BalaBit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "groupingby.h" #include "id-counter.h" typedef struct _GroupingBy { GroupingParser super; SyntheticMessage *synthetic_message; FilterExprNode *trigger_condition_expr; FilterExprNode *where_condition_expr; FilterExprNode *having_condition_expr; gchar *prefix; guint clone_id; IdCounter *id_counter; } GroupingBy; /* public functions */ void grouping_by_set_trigger_condition(LogParser *s, FilterExprNode *filter_expr) { GroupingBy *self = (GroupingBy *) s; self->trigger_condition_expr = filter_expr; } void grouping_by_set_where_condition(LogParser *s, FilterExprNode *filter_expr) { GroupingBy *self = (GroupingBy *) s; self->where_condition_expr = filter_expr; } void grouping_by_set_having_condition(LogParser *s, FilterExprNode *filter_expr) { GroupingBy *self = (GroupingBy *) s; self->having_condition_expr = filter_expr; } void grouping_by_set_synthetic_message(LogParser *s, SyntheticMessage *message) { GroupingBy *self = (GroupingBy *) s; if (self->synthetic_message) synthetic_message_free(self->synthetic_message); self->synthetic_message = message; } void grouping_by_set_prefix(LogParser *s, const gchar *prefix) { GroupingBy *self = (GroupingBy *) s; g_free(self->prefix); self->prefix = g_strdup(prefix); } static gboolean _evaluate_filter(FilterExprNode *expr, CorrelationContext *context) { return filter_expr_eval_with_context(expr, (LogMessage **) context->messages->pdata, context->messages->len, &DEFAULT_TEMPLATE_EVAL_OPTIONS); } static gboolean _evaluate_having(GroupingBy *self, CorrelationContext *context) { if (!self->having_condition_expr) return TRUE; return _evaluate_filter(self->having_condition_expr, context); } static GroupingParserUpdateContextResult _update_context(GroupingParser *s, CorrelationContext *context, LogMessage *msg) { GroupingBy *self = (GroupingBy *) s; g_ptr_array_add(context->messages, log_msg_ref(msg)); if (self->trigger_condition_expr && _evaluate_filter(self->trigger_condition_expr, context)) return GP_CONTEXT_COMPLETE; return GP_CONTEXT_UPDATED; } static LogMessage * _aggregate_context(GroupingParser *s, CorrelationContext *context) { GroupingBy *self = (GroupingBy *) s; LogMessage *msg = NULL; if (!_evaluate_having(self, context)) { msg_debug("groupingby() dropping context, because having() is FALSE", evt_tag_str("key", context->key.session_id), log_pipe_location_tag(&self->super.super.super.super)); return NULL; } msg = synthetic_message_generate_with_context(self->synthetic_message, context); return msg; } static gboolean _evaluate_where(GroupingParser *s, LogMessage **pmsg, const LogPathOptions *path_options) { GroupingBy *self = (GroupingBy *) s; if (!self->where_condition_expr) return TRUE; return filter_expr_eval_root(self->where_condition_expr, pmsg, path_options); } static const gchar * _format_persist_name(const LogPipe *s) { static gchar persist_name[512]; GroupingBy *self = (GroupingBy *)s; if (s->persist_name) g_snprintf(persist_name, sizeof(persist_name), "grouping-by.%s(clone=%d)", s->persist_name, self->clone_id); else g_snprintf(persist_name, sizeof(persist_name), "grouping-by(%s,scope=%d,clone=%d)", self->super.key_template->template_str, self->super.scope, self->clone_id); return persist_name; } static gboolean _init(LogPipe *s) { GroupingBy *self = (GroupingBy *) s; GlobalConfig *cfg = log_pipe_get_config(s); self->id_counter = NULL; if (self->super.timeout < 1) { msg_error("timeout() needs to be specified explicitly and must be greater than 0 in the grouping-by() parser", log_pipe_location_tag(s)); return FALSE; } if (!self->super.key_template) { msg_error("The key() option is mandatory for the grouping-by() parser", log_pipe_location_tag(s)); return FALSE; } if (!self->synthetic_message) { msg_error("The aggregate() option for grouping-by() is mandatory", log_pipe_location_tag(s)); return FALSE; } synthetic_message_set_prefix(self->synthetic_message, self->prefix); if (self->trigger_condition_expr && !filter_expr_init(self->trigger_condition_expr, cfg)) return FALSE; if (self->where_condition_expr && !filter_expr_init(self->where_condition_expr, cfg)) return FALSE; if (self->having_condition_expr && !filter_expr_init(self->having_condition_expr, cfg)) return FALSE; return grouping_parser_init_method(s); } static LogPipe * _clone(LogPipe *s) { GroupingBy *self = (GroupingBy *) s; GroupingBy *cloned; cloned = (GroupingBy *) grouping_by_new(s->cfg); grouping_parser_clone_settings(&self->super, &cloned->super); grouping_by_set_synthetic_message(&cloned->super.super.super, self->synthetic_message); grouping_by_set_trigger_condition(&cloned->super.super.super, filter_expr_clone(self->trigger_condition_expr)); grouping_by_set_where_condition(&cloned->super.super.super, filter_expr_clone(self->where_condition_expr)); grouping_by_set_having_condition(&cloned->super.super.super, filter_expr_clone(self->having_condition_expr)); grouping_by_set_prefix(&cloned->super.super.super, self->prefix); id_counter_unref(cloned->id_counter); cloned->id_counter = id_counter_ref(self->id_counter); cloned->clone_id = id_counter_get_next_id(cloned->id_counter); return &cloned->super.super.super.super; } static void _free(LogPipe *s) { GroupingBy *self = (GroupingBy *) s; id_counter_unref(self->id_counter); g_free(self->prefix); if (self->synthetic_message) synthetic_message_free(self->synthetic_message); filter_expr_unref(self->trigger_condition_expr); filter_expr_unref(self->where_condition_expr); filter_expr_unref(self->having_condition_expr); grouping_parser_free_method(s); } LogParser * grouping_by_new(GlobalConfig *cfg) { GroupingBy *self = g_new0(GroupingBy, 1); self->id_counter = id_counter_new(); self->clone_id = id_counter_get_next_id(self->id_counter); grouping_parser_init_instance(&self->super, cfg); self->super.super.super.super.free_fn = _free; self->super.super.super.super.init = _init; self->super.super.super.super.clone = _clone; self->super.super.super.super.generate_persist_name = _format_persist_name; self->super.filter_messages = _evaluate_where; self->super.update_context = _update_context; self->super.aggregate_context = _aggregate_context; return &self->super.super.super; } syslog-ng-syslog-ng-4.4.0/modules/correlation/groupingby.h000066400000000000000000000034341450431004300237060ustar00rootroot00000000000000/* * Copyright (c) 2015 BalaBit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_GROUPING_BY_PARSER_H_INCLUDED #define CORRELATION_GROUPING_BY_PARSER_H_INCLUDED #include "grouping-parser.h" #include "synthetic-message.h" #include "filter/filter-expr.h" void grouping_by_set_key_template(LogParser *s, LogTemplate *context_id); void grouping_by_set_sort_key_template(LogParser *s, LogTemplate *sort_key); void grouping_by_set_timeout(LogParser *s, gint timeout); void grouping_by_set_scope(LogParser *s, CorrelationScope scope); void grouping_by_set_synthetic_message(LogParser *s, SyntheticMessage *message); void grouping_by_set_trigger_condition(LogParser *s, FilterExprNode *filter_expr); void grouping_by_set_where_condition(LogParser *s, FilterExprNode *filter_expr); void grouping_by_set_having_condition(LogParser *s, FilterExprNode *filter_expr); void grouping_by_set_prefix(LogParser *s, const gchar *prefix); LogParser *grouping_by_new(GlobalConfig *cfg); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/id-counter.c000066400000000000000000000027001450431004300235600ustar00rootroot00000000000000/* * Copyright (c) 2023 OneIdentity LLC. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "glib.h" typedef struct _IdCounter { guint id; guint ref_count; } IdCounter; IdCounter *id_counter_new(void) { IdCounter *self = g_new(IdCounter, 1); self->id = 0; self->ref_count = 1; return self; } guint id_counter_get_next_id(IdCounter *self) { return self->id++; } IdCounter *id_counter_ref(IdCounter *self) { if (self == NULL) return NULL; self->ref_count += 1; return self; } void id_counter_unref(IdCounter *self) { if (self == NULL) return; self->ref_count -= 1; if (self->ref_count == 0) g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/correlation/id-counter.h000066400000000000000000000022501450431004300235650ustar00rootroot00000000000000/* * Copyright (c) 2023 OneIdentity LLC. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef ID_COUNTER_H_INCLUDED #define ID_COUNTER_H_INCLUDED #include "glib.h" typedef void IdCounter; IdCounter *id_counter_new(void); guint id_counter_get_next_id(IdCounter *self); IdCounter *id_counter_ref(IdCounter *self); void id_counter_unref(IdCounter *self); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/patterndb.c000066400000000000000000000532461450431004300235050ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "patterndb.h" #include "pdb-action.h" #include "pdb-rule.h" #include "pdb-program.h" #include "pdb-ruleset.h" #include "pdb-load.h" #include "pdb-context.h" #include "pdb-ratelimit.h" #include "pdb-lookup-params.h" #include "correlation.h" #include "logmsg/logmsg.h" #include "template/templates.h" #include "str-utils.h" #include "filter/filter-expr-parser.h" #include "logpipe.h" #include "timeutils/cache.h" #include "timeutils/misc.h" #include #include #include #include static NVHandle context_id_handle = 0; #define EXPECTED_NUMBER_OF_MESSAGES_EMITTED 32 typedef struct _PDBProcessParams { PDBRule *rule; PDBAction *action; PDBContext *context; LogMessage *msg; gpointer emitted_messages[EXPECTED_NUMBER_OF_MESSAGES_EMITTED]; GPtrArray *emitted_messages_overflow; gint num_emitted_messages; } PDBProcessParams; struct _PatternDB { GMutex ruleset_lock; PDBRuleSet *ruleset; CorrelationState *correlation; LogTemplate *program_template; GHashTable *rate_limits; PatternDBEmitFunc emit; gpointer emit_data; gchar *prefix; }; /* This function is called to populate the emitted_messages array in * process_params. It only manipulates per-thread data structure so it does * not require locks but does not mind them being locked either. */ static void _emit_message(PatternDB *self, PDBProcessParams *process_params, LogMessage *msg) { if (!self->emit) return; if (process_params->num_emitted_messages < EXPECTED_NUMBER_OF_MESSAGES_EMITTED) { process_params->emitted_messages[process_params->num_emitted_messages++] = msg; } else { if (!process_params->emitted_messages_overflow) process_params->emitted_messages_overflow = g_ptr_array_new(); g_ptr_array_add(process_params->emitted_messages_overflow, msg); } log_msg_ref(msg); } static void _send_emitted_message_array(PatternDB *self, gpointer *values, gsize len) { /* if emit is NULL, we don't store any entries in the arrays, so no need * to check it here. */ for (gint i = 0; i < len; i++) { LogMessage *msg = values[i]; self->emit(msg, self->emit_data); log_msg_unref(msg); } } /* This function is called to flush the accumulated list of messages that * are generated during rule evaluation. We must not hold any locks within * PatternDB when doing this, as it will cause log_pipe_queue() calls to * subsequent elements in the message pipeline, which in turn may recurse * into PatternDB. This works as process_params itself is per-thread * (actually an auto variable on the stack), and this is called without * locks held at the end of a pattern_db_process() invocation. */ static void _flush_emitted_messages(PatternDB *self, PDBProcessParams *process_params) { /* send inline elements */ _send_emitted_message_array(self, process_params->emitted_messages, process_params->num_emitted_messages); process_params->num_emitted_messages = 0; if (process_params->emitted_messages_overflow) { /* send overflow area */ _send_emitted_message_array(self, process_params->emitted_messages_overflow->pdata, process_params->emitted_messages_overflow->len); g_ptr_array_free(process_params->emitted_messages_overflow, TRUE); process_params->emitted_messages_overflow = NULL; } } /* * Timing * ====== * * The time tries to follow the message stream, e.g. it is independent from * the current system time. Whenever a message comes in, its timestamp * moves the current time forward, which means it is quite easy to process * logs from the past, correlation timeouts will be measured in "message * time". There's one exception to this rule: when the patterndb is idle * (e.g. no messages are coming in), the current system time is used to * measure as real time passes, and that will also increase the time of the * correlation engine. This is based on the following assumptions: * * 1) dbparser can only be idle in case on-line logs are processed * (otherwise messages are read from the disk much faster) * * 2) if on-line processing is done, it is expected that messages have * roughly correct timestamps, e.g. if 1 second passes in current * system time, further incoming messages will have a timestamp close * to this. * * Thus whenever the patterndb is idle, a timer tick callback arrives, which * checks the real elapsed time between the last message (or last tick) and * increments the current known time with this value. * * This behaviour makes it possible to properly work in these use-cases: * * 1) process a log file stored on disk, containing messages in the past * 2) process an incoming message stream on-line, expiring correlation * states even if there are no incoming messages * */ /********************************************* * Rule evaluation *********************************************/ static gboolean _is_action_within_rate_limit(PatternDB *db, PDBProcessParams *process_params) { PDBRule *rule = process_params->rule; PDBAction *action = process_params->action; LogMessage *msg = process_params->msg; GString *buffer = g_string_sized_new(256); CorrelationKey key; PDBRateLimit *rl; guint64 now; if (action->rate == 0) return TRUE; g_string_printf(buffer, "%s:%d", rule->rule_id, action->id); correlation_key_init(&key, rule->context.scope, msg, buffer->str); rl = g_hash_table_lookup(db->rate_limits, &key); if (!rl) { rl = pdb_rate_limit_new(&key); g_hash_table_insert(db->rate_limits, &rl->key, rl); g_string_free(buffer, FALSE); } else { g_string_free(buffer, TRUE); } now = correlation_state_get_time(db->correlation); if (rl->last_check == 0) { rl->last_check = now; rl->buckets = action->rate; } else { /* quick and dirty fixed point arithmetic, 8 bit fraction part */ gint new_credits = (((glong) (now - rl->last_check)) << 8) / ((((glong) action->rate_quantum) << 8) / action->rate); if (new_credits) { /* ok, enough time has passed to increase the current credit. * Deposit the new credits in bucket but make sure we don't permit * more than the maximum rate. */ rl->buckets = MIN(rl->buckets + new_credits, action->rate); rl->last_check = now; } } if (rl->buckets) { rl->buckets--; return TRUE; } return FALSE; } static gboolean _is_action_triggered(PatternDB *db, PDBProcessParams *process_params, PDBActionTrigger trigger) { PDBAction *action = process_params->action; PDBContext *context = process_params->context; LogMessage *msg = process_params->msg; if (action->trigger != trigger) return FALSE; if (action->condition) { if (context && !filter_expr_eval_with_context(action->condition, (LogMessage **) context->super.messages->pdata, context->super.messages->len, &DEFAULT_TEMPLATE_EVAL_OPTIONS)) return FALSE; if (!context && !filter_expr_eval(action->condition, msg)) return FALSE; } if (!_is_action_within_rate_limit(db, process_params)) return FALSE; return TRUE; } static LogMessage * _generate_synthetic_message(PDBProcessParams *process_params) { PDBAction *action = process_params->action; PDBContext *context = process_params->context; LogMessage *msg = process_params->msg; if (context) return synthetic_message_generate_with_context(&action->content.message, &context->super); else return synthetic_message_generate_without_context(&action->content.message, msg); } static void _execute_action_message(PatternDB *db, PDBProcessParams *process_params) { LogMessage *genmsg; genmsg = _generate_synthetic_message(process_params); _emit_message(db, process_params, genmsg); log_msg_unref(genmsg); } static void pattern_db_expire_entry(TimerWheel *wheel, guint64 now, gpointer user_data, gpointer caller_context); static void _execute_action_create_context(PatternDB *db, PDBProcessParams *process_params) { CorrelationKey key; PDBAction *action = process_params->action; PDBRule *rule = process_params->rule; PDBContext *triggering_context = process_params->context; LogMessage *triggering_msg = process_params->msg; GString *buffer = g_string_sized_new(256); PDBContext *new_context; LogMessage *context_msg; SyntheticContext *syn_context; SyntheticMessage *syn_message; syn_context = &action->content.create_context.context; syn_message = &action->content.create_context.message; if (triggering_context) { context_msg = synthetic_message_generate_with_context(syn_message, &triggering_context->super); log_template_format_with_context(syn_context->id_template, (LogMessage **) triggering_context->super.messages->pdata, triggering_context->super.messages->len, &DEFAULT_TEMPLATE_EVAL_OPTIONS, buffer); } else { context_msg = synthetic_message_generate_without_context(syn_message, triggering_msg); log_template_format(syn_context->id_template, triggering_msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, buffer); } msg_debug("Explicit create-context action, starting a new context", evt_tag_str("rule", rule->rule_id), evt_tag_str("context", buffer->str), evt_tag_int("context_timeout", syn_context->timeout), evt_tag_int("context_expiration", correlation_state_get_time(db->correlation) + syn_context->timeout)); correlation_key_init(&key, syn_context->scope, context_msg, buffer->str); new_context = pdb_context_new(&key); correlation_state_tx_store_context(db->correlation, &new_context->super, rule->context.timeout); g_string_free(buffer, FALSE); g_ptr_array_add(new_context->super.messages, context_msg); new_context->rule = pdb_rule_ref(rule); } static void _execute_action(PatternDB *db, PDBProcessParams *process_params) { PDBAction *action = process_params->action; switch (action->content_type) { case RAC_NONE: break; case RAC_MESSAGE: _execute_action_message(db, process_params); break; case RAC_CREATE_CONTEXT: _execute_action_create_context(db, process_params); break; default: g_assert_not_reached(); break; } } static void _execute_action_if_triggered(PatternDB *db, PDBProcessParams *process_params, PDBActionTrigger trigger) { if (_is_action_triggered(db, process_params, trigger)) _execute_action(db, process_params); } static void _execute_rule_actions(PatternDB *db, PDBProcessParams *process_params, PDBActionTrigger trigger) { gint i; PDBRule *rule = process_params->rule; if (!rule->actions) return; for (i = 0; i < rule->actions->len; i++) { process_params->action = (PDBAction *) g_ptr_array_index(rule->actions, i); _execute_action_if_triggered(db, process_params, trigger); } } /********************************************************* * PatternDB *********************************************************/ /* NOTE: this function requires PatternDB reader/writer lock to be * write-locked. * * Currently, it is, as timer_wheel_set_time() is only called with that * precondition, and timer-wheel callbacks are only called from within * timer_wheel_set_time(). */ static void pattern_db_expire_entry(TimerWheel *wheel, guint64 now, gpointer user_data, gpointer caller_context) { PDBContext *context = user_data; PatternDB *pdb = (PatternDB *) timer_wheel_get_associated_data(wheel); LogMessage *msg = correlation_context_get_last_message(&context->super); PDBProcessParams *process_params = caller_context; msg_debug("Expiring patterndb correlation context", evt_tag_str("last_rule", context->rule->rule_id), evt_tag_long("utc", correlation_state_get_time(pdb->correlation))); process_params->context = context; process_params->rule = context->rule; process_params->msg = msg; _execute_rule_actions(pdb, process_params, RAT_TIMEOUT); context->super.timer = NULL; correlation_state_tx_remove_context(pdb->correlation, &context->super); /* pdb_context_free is automatically called when returning from this function by the timerwheel code as a destroy notify callback. */ } /* * This function can be called any time when pattern-db is not processing * messages, but we expect the correlation timer to move forward. It * doesn't need to be called absolutely regularly as it'll use the current * system time to determine how much time has passed since the last * invocation. See the timing comment at pattern_db_process() for more * information. */ void pattern_db_timer_tick(PatternDB *self) { PDBProcessParams process_params = {0}; if (correlation_state_timer_tick(self->correlation, &process_params)) { msg_debug("Advancing patterndb current time because of timer tick", evt_tag_long("utc", correlation_state_get_time(self->correlation))); } _flush_emitted_messages(self, &process_params); } /* NOTE: lock should be acquired for writing before calling this function. */ static void _advance_time_based_on_message(PatternDB *self, PDBProcessParams *process_params, const UnixTime *ls) { correlation_state_set_time(self->correlation, ls->ut_sec, process_params); msg_debug("Advancing patterndb current time because of an incoming message", evt_tag_long("utc", correlation_state_get_time(self->correlation))); } void pattern_db_advance_time(PatternDB *self, gint timeout) { PDBProcessParams process_params= {0}; correlation_state_advance_time(self->correlation, timeout, &process_params); _flush_emitted_messages(self, &process_params); } gboolean pattern_db_reload_ruleset(PatternDB *self, GlobalConfig *cfg, const gchar *pdb_file) { PDBRuleSet *new_ruleset; new_ruleset = pdb_rule_set_new(self->prefix); if (!pdb_rule_set_load(new_ruleset, cfg, pdb_file, NULL)) { pdb_rule_set_free(new_ruleset); return FALSE; } else { g_mutex_lock(&self->ruleset_lock); if (self->ruleset) pdb_rule_set_free(self->ruleset); self->ruleset = new_ruleset; g_mutex_unlock(&self->ruleset_lock); return TRUE; } } void pattern_db_set_emit_func(PatternDB *self, PatternDBEmitFunc emit, gpointer emit_data) { self->emit = emit; self->emit_data = emit_data; } void pattern_db_set_program_template(PatternDB *self, LogTemplate *program_template) { log_template_unref(self->program_template); self->program_template = log_template_ref(program_template); } const gchar * pattern_db_get_ruleset_pub_date(PatternDB *self) { return self->ruleset->pub_date; } const gchar * pattern_db_get_ruleset_version(PatternDB *self) { return self->ruleset->version; } PDBRuleSet * pattern_db_get_ruleset(PatternDB *self) { return self->ruleset; } static gboolean _pattern_db_is_empty(PatternDB *self) { return (G_UNLIKELY(!self->ruleset) || self->ruleset->is_empty); } static void _pattern_db_process_matching_rule(PatternDB *self, PDBProcessParams *process_params) { PDBContext *context = NULL; PDBRule *rule = process_params->rule; LogMessage *msg = process_params->msg; GString *buffer = g_string_sized_new(32); correlation_state_tx_begin(self->correlation); if (rule->context.id_template) { CorrelationKey key; log_template_format(rule->context.id_template, msg, &DEFAULT_TEMPLATE_EVAL_OPTIONS, buffer); log_msg_set_value(msg, context_id_handle, buffer->str, -1); correlation_key_init(&key, rule->context.scope, msg, buffer->str); context = (PDBContext *) correlation_state_tx_lookup_context(self->correlation, &key); if (!context) { msg_debug("Correlation context lookup failure, starting a new context", evt_tag_str("rule", rule->rule_id), evt_tag_str("context", buffer->str), evt_tag_int("context_timeout", rule->context.timeout), evt_tag_int("context_expiration", correlation_state_get_time(self->correlation) + rule->context.timeout)); context = pdb_context_new(&key); correlation_state_tx_store_context(self->correlation, &context->super, rule->context.timeout); g_string_steal(buffer); } else { msg_debug("Correlation context lookup successful", evt_tag_str("rule", rule->rule_id), evt_tag_str("context", buffer->str), evt_tag_int("context_timeout", rule->context.timeout), evt_tag_int("context_expiration", correlation_state_get_time(self->correlation) + rule->context.timeout), evt_tag_int("num_messages", context->super.messages->len)); } g_ptr_array_add(context->super.messages, log_msg_ref(msg)); correlation_state_tx_update_context(self->correlation, &context->super, rule->context.timeout); if (context->rule != rule) { if (context->rule) pdb_rule_unref(context->rule); context->rule = pdb_rule_ref(rule); } } else { context = NULL; } process_params->context = context; synthetic_message_apply(&rule->msg, context ? &context->super : NULL, msg); _execute_rule_actions(self, process_params, RAT_MATCH); pdb_rule_unref(rule); correlation_state_tx_end(self->correlation); if (context) log_msg_write_protect(msg); g_string_free(buffer, TRUE); } static void _pattern_db_advance_time_and_flush_expired(PatternDB *self, LogMessage *msg) { PDBProcessParams process_params = {0}; _advance_time_based_on_message(self, &process_params, &msg->timestamps[LM_TS_STAMP]); _flush_emitted_messages(self, &process_params); } static gboolean _pattern_db_process(PatternDB *self, PDBLookupParams *lookup, GArray *dbg_list) { LogMessage *msg = lookup->msg; PDBProcessParams process_params_p = {0}; PDBProcessParams *process_params = &process_params_p; g_mutex_lock(&self->ruleset_lock); if (_pattern_db_is_empty(self)) { g_mutex_unlock(&self->ruleset_lock); return FALSE; } process_params->rule = pdb_ruleset_lookup(self->ruleset, lookup, dbg_list); process_params->msg = msg; g_mutex_unlock(&self->ruleset_lock); _pattern_db_advance_time_and_flush_expired(self, msg); if (process_params->rule) _pattern_db_process_matching_rule(self, process_params); _flush_emitted_messages(self, process_params); return process_params->rule != NULL; } gboolean pattern_db_process(PatternDB *self, LogMessage *msg) { PDBLookupParams lookup; pdb_lookup_params_init(&lookup, msg, self->program_template); return _pattern_db_process(self, &lookup, NULL); } gboolean pattern_db_process_with_custom_message(PatternDB *self, LogMessage *msg, const gchar *message, gssize message_len) { PDBLookupParams lookup; pdb_lookup_params_init(&lookup, msg, self->program_template); pdb_lookup_params_override_message(&lookup, message, message_len); return _pattern_db_process(self, &lookup, NULL); } void pattern_db_debug_ruleset(PatternDB *self, LogMessage *msg, GArray *dbg_list) { PDBLookupParams lookup; pdb_lookup_params_init(&lookup, msg, NULL); _pattern_db_process(self, &lookup, dbg_list); } void pattern_db_expire_state(PatternDB *self) { PDBProcessParams process_params = {0}; correlation_state_expire_all(self->correlation, &process_params); _flush_emitted_messages(self, &process_params); } static void _init_state(PatternDB *self) { self->rate_limits = g_hash_table_new_full(correlation_key_hash, correlation_key_equal, NULL, (GDestroyNotify) pdb_rate_limit_free); self->correlation = correlation_state_new(pattern_db_expire_entry); timer_wheel_set_associated_data(self->correlation->timer_wheel, self, NULL); } static void _destroy_state(PatternDB *self) { g_hash_table_destroy(self->rate_limits); correlation_state_unref(self->correlation); self->correlation = NULL; } /* NOTE: this function is for testing only and is not expecting parallel * threads taking actions within the same PatternDB instance. */ void pattern_db_forget_state(PatternDB *self) { _destroy_state(self); _init_state(self); } PatternDB * pattern_db_new(const gchar *prefix) { PatternDB *self = g_new0(PatternDB, 1); self->prefix = g_strdup(prefix); self->ruleset = pdb_rule_set_new(self->prefix); g_mutex_init(&self->ruleset_lock); _init_state(self); return self; } void pattern_db_free(PatternDB *self) { g_free(self->prefix); log_template_unref(self->program_template); if (self->ruleset) pdb_rule_set_free(self->ruleset); _destroy_state(self); g_mutex_clear(&self->ruleset_lock); g_free(self); } void pattern_db_global_init(void) { context_id_handle = log_msg_get_value_handle(".classifier.context_id"); pdb_rule_set_global_init(); } syslog-ng-syslog-ng-4.4.0/modules/correlation/patterndb.h000066400000000000000000000044331450431004300235040ustar00rootroot00000000000000/* * Copyright (c) 2002-2013 Balabit * Copyright (c) 1998-2013 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PATTERNDB_H_INCLUDED #define CORRELATION_PATTERNDB_H_INCLUDED #include "syslog-ng.h" #include "pdb-ruleset.h" #include "timerwheel.h" typedef struct _PatternDB PatternDB; typedef void (*PatternDBEmitFunc)(LogMessage *msg, gpointer user_data); void pattern_db_set_emit_func(PatternDB *self, PatternDBEmitFunc emit_func, gpointer emit_data); void pattern_db_set_program_template(PatternDB *self, LogTemplate *program_template); PDBRuleSet *pattern_db_get_ruleset(PatternDB *self); const gchar *pattern_db_get_ruleset_version(PatternDB *self); const gchar *pattern_db_get_ruleset_pub_date(PatternDB *self); gboolean pattern_db_reload_ruleset(PatternDB *self, GlobalConfig *cfg, const gchar *pdb_file); void pattern_db_advance_time(PatternDB *self, gint timeout); void pattern_db_timer_tick(PatternDB *self); gboolean pattern_db_process(PatternDB *self, LogMessage *msg); gboolean pattern_db_process_with_custom_message(PatternDB *self, LogMessage *msg, const gchar *message, gssize message_len); void pattern_db_debug_ruleset(PatternDB *self, LogMessage *msg, GArray *dbg_list); void pattern_db_expire_state(PatternDB *self); void pattern_db_forget_state(PatternDB *self); PatternDB *pattern_db_new(const gchar *prefix); void pattern_db_free(PatternDB *self); void pattern_db_global_init(void); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/patternize.c000066400000000000000000000451041450431004300237010ustar00rootroot00000000000000/* * Copyright (c) 2010-2012 Balabit * Copyright (c) 2009-2011 Péter Gyöngyösi * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "patternize.h" #include "logmsg/logmsg.h" #include "messages.h" #include "uuid.h" #include "msg-format.h" #include #include /* * NOTE: most of the algorithms come from SLCT and LogHound, written by Risto Vaarandi */ /* * Constants */ #define PTZ_MAXLINELEN 10240 #define PTZ_MAXWORDS 512 /* maximum number of words in one line */ #define PTZ_LOGTABLE_ALLOC_BASE 3000 #define PTZ_WORDLIST_CACHE 3 /* FIXME: make this a commandline parameter? */ static LogTagId cluster_tag_id; #if 0 static void _ptz_debug_print_word(gpointer key, gpointer value, gpointer dummy) { fprintf(stderr, "%d: %s\n", *((guint *) value), (gchar *) key); } static void _ptz_debug_print_cluster(gpointer key, gpointer value, gpointer dummy) { fprintf(stderr, "%s: %s\n", (gchar *) key, ((Cluster *) value)->words[0]); } #endif guint ptz_str2hash(gchar *string, guint modulo, guint seed) { int i; /* fast string hashing algorithm by M.V.Ramakrishna and Justin Zobel */ for (i = 0; string[i] != 0; ++i) { seed = seed ^ ((seed << 5) + (seed >> 2) + string[i]); } return seed % modulo; } gchar * ptz_find_delimiters(gchar *str, const gchar *delimdef) { gchar *remainder; GString *delimiters = g_string_sized_new(32); remainder = str; while (remainder[0] != 0) { remainder += strcspn(remainder, delimdef); if (remainder[0] != 0) { g_string_append_c(delimiters, remainder[0]); remainder++; } } return g_string_free(delimiters, FALSE); } gboolean ptz_find_frequent_words_remove_key_predicate(gpointer key, gpointer value, gpointer support) { return (*((guint *) value) < GPOINTER_TO_UINT(support)); } GHashTable * ptz_find_frequent_words(GPtrArray *logs, guint support, const gchar *delimiters, gboolean two_pass) { int i, j, pass; guint *curr_count; LogMessage *msg; gchar *msgstr; gssize msglen; gchar **words; GHashTable *wordlist; int *wordlist_cache = NULL; guint cachesize = 0, cacheseed = 0, cacheindex = 0; gchar *hash_key; wordlist = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); for (pass = (two_pass ? 1 : 2); pass <= 2; ++pass) { if (pass == 1) { msg_progress("Finding frequent words", evt_tag_str("phase", "caching")); srand(time(NULL)); cachesize = (guint) ((logs->len * PTZ_WORDLIST_CACHE)); cacheseed = rand(); wordlist_cache = g_new0(int, cachesize); } else { msg_progress("Finding frequent words", evt_tag_str("phase", "searching")); } for (i = 0; i < logs->len; ++i) { msg = (LogMessage *) g_ptr_array_index(logs, i); msgstr = (gchar *) log_msg_get_value(msg, LM_V_MESSAGE, &msglen); words = g_strsplit_set(msgstr, delimiters, PTZ_MAXWORDS); for (j = 0; words[j]; ++j) { /* NOTE: to calculate the key for the hash, we prefix a word with * its position in the row and a space -- as we always split at * spaces, this should not create confusion */ hash_key = g_strdup_printf("%d %s", j, words[j]); if (two_pass) cacheindex = ptz_str2hash(hash_key, cachesize, cacheseed); if (pass == 1) { wordlist_cache[cacheindex]++; } else if (pass == 2) { if (!two_pass || wordlist_cache[cacheindex] >= support) { curr_count = (guint *) g_hash_table_lookup(wordlist, hash_key); if (!curr_count) { guint *currcount_ref = g_new(guint, 1); (*currcount_ref) = 1; g_hash_table_insert(wordlist, g_strdup(hash_key), currcount_ref); } else { (*curr_count)++; } } } g_free(hash_key); } g_strfreev(words); } /* g_hash_table_foreach(wordlist, _ptz_debug_print_word, NULL); */ g_hash_table_foreach_remove(wordlist, ptz_find_frequent_words_remove_key_predicate, GUINT_TO_POINTER(support)); } if (wordlist_cache) g_free(wordlist_cache); return wordlist; } gboolean ptz_find_clusters_remove_cluster_predicate(gpointer key, gpointer value, gpointer data) { Cluster *val = (Cluster *) value; gboolean ret; LogMessage *msg; guint support; int i; support = GPOINTER_TO_UINT(data); ret = (val->loglines->len < support); if (ret) { /* remove cluster reference from the relevant logs */ for (i = 0; i < val->loglines->len; ++i) { msg = (LogMessage *) g_ptr_array_index(val->loglines, i); log_msg_clear_tag_by_id(msg, cluster_tag_id); } } return ret; } static void cluster_free(Cluster *cluster) { gint i; if (cluster->samples) { for (i = 0; i < cluster->samples->len; i++) g_free(g_ptr_array_index(cluster->samples, i)); g_ptr_array_free(cluster->samples, TRUE); } g_ptr_array_free(cluster->loglines, TRUE); g_strfreev(cluster->words); g_free(cluster); } GHashTable * ptz_find_clusters_slct(GPtrArray *logs, guint support, const gchar *delimiters, guint num_of_samples) { GHashTable *wordlist; GHashTable *clusters; int i, j; LogMessage *msg; gchar *msgstr; gssize msglen; gchar **words; gchar *hash_key; gboolean is_candidate; Cluster *cluster; GString *cluster_key; gchar *msgdelimiters; /* get the frequent word list */ wordlist = ptz_find_frequent_words(logs, support, delimiters, TRUE); /* g_hash_table_foreach(wordlist, _ptz_debug_print_word, NULL); */ /* find the cluster candidates */ clusters = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) cluster_free); cluster_key = g_string_sized_new(0); for (i = 0; i < logs->len; ++i) { msg = (LogMessage *) g_ptr_array_index(logs, i); msgstr = (gchar *) log_msg_get_value(msg, LM_V_MESSAGE, &msglen); g_string_truncate(cluster_key, 0); words = g_strsplit_set(msgstr, delimiters, PTZ_MAXWORDS); msgdelimiters = ptz_find_delimiters(msgstr, delimiters); is_candidate = FALSE; for (j = 0; words[j]; ++j) { hash_key = g_strdup_printf("%d %s", j, words[j]); if (g_hash_table_lookup(wordlist, hash_key)) { is_candidate = TRUE; g_string_append(cluster_key, hash_key); g_string_append_c(cluster_key, PTZ_SEPARATOR_CHAR); } else { g_string_append_printf(cluster_key, "%d %c%c", j, PTZ_PARSER_MARKER_CHAR, PTZ_SEPARATOR_CHAR); } g_free(hash_key); } /* append the delimiters of the message to the cluster key to assure unicity * otherwise the same words with different delimiters would still show as the * same cluster */ g_string_append_printf(cluster_key, "%s%c", msgdelimiters, PTZ_SEPARATOR_CHAR); g_free(msgdelimiters); if (is_candidate) { cluster = (Cluster *) g_hash_table_lookup(clusters, cluster_key->str); if (!cluster) { cluster = g_new0(Cluster, 1); if (num_of_samples > 0) { cluster->samples = g_ptr_array_sized_new(5); g_ptr_array_add(cluster->samples, g_strdup(msgstr)); } cluster->loglines = g_ptr_array_sized_new(64); g_ptr_array_add(cluster->loglines, (gpointer) msg); cluster->words = g_strdupv(words); g_hash_table_insert(clusters, g_strdup(cluster_key->str), (gpointer) cluster); } else { g_ptr_array_add(cluster->loglines, (gpointer) msg); if (cluster->samples && cluster->samples->len < num_of_samples) { g_ptr_array_add(cluster->samples, g_strdup(msgstr)); } } log_msg_set_tag_by_id(msg, cluster_tag_id); } g_strfreev(words); } g_hash_table_foreach_remove(clusters, ptz_find_clusters_remove_cluster_predicate, GUINT_TO_POINTER(support)); /* g_hash_table_foreach(clusters, _ptz_debug_print_cluster, NULL); */ g_hash_table_unref(wordlist); g_string_free(cluster_key, TRUE); return clusters; } /* callback function for g_hash_table_foreach_steal to migrate elements from one hash to the other */ static gboolean ptz_merge_clusterlists(gpointer _key, gpointer _value, gpointer _target) { gchar *key = _key; Cluster *cluster = _value; GHashTable *target = _target; g_hash_table_insert(target, key, cluster); return TRUE; } GHashTable * ptz_find_clusters_step(Patternizer *self, GPtrArray *logs, guint support, guint num_of_samples) { msg_progress("Searching clusters", evt_tag_int("input_lines", logs->len)); if (self->algo == PTZ_ALGO_SLCT) return ptz_find_clusters_slct(logs, support, self->delimiters, num_of_samples); else { msg_error("Unknown clustering algorithm", evt_tag_int("algo_id", self->algo)); return NULL; } } GHashTable * ptz_find_clusters(Patternizer *self) { /* FIXME: maybe we should dup everything... this way * we give out a clusters hash that contains references * to our internal logs array... */ GHashTable *curr_clusters; GHashTable *ret_clusters; GPtrArray *prev_logs, *curr_logs; guint curr_support; LogMessage *msg; int i; prev_logs = NULL; if (self->iterate == PTZ_ITERATE_NONE) return ptz_find_clusters_step(self, self->logs, self->support, self->num_of_samples); if (self->iterate == PTZ_ITERATE_OUTLIERS) { ret_clusters = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) cluster_free); curr_logs = self->logs; curr_support = self->support; while (TRUE) { curr_clusters = ptz_find_clusters_step(self, curr_logs, curr_support, self->num_of_samples); if (g_hash_table_size(curr_clusters) == 0) { g_hash_table_destroy(curr_clusters); break; } g_hash_table_foreach_steal(curr_clusters, ptz_merge_clusterlists, ret_clusters); g_hash_table_destroy(curr_clusters); prev_logs = curr_logs; curr_logs = g_ptr_array_sized_new(g_hash_table_size(curr_clusters)); for (i = 0; i < prev_logs->len; ++i) { msg = (LogMessage *) g_ptr_array_index(prev_logs, i); if (!log_msg_is_tag_by_id(msg, cluster_tag_id)) { /* it's an outlier, include it in the next iteration */ g_ptr_array_add(curr_logs, msg); } } curr_support = (guint) (curr_logs->len * (self->support_treshold / 100.0)); if (prev_logs != self->logs) { g_ptr_array_free(prev_logs, TRUE); prev_logs = NULL; } } if (prev_logs && prev_logs != self->logs) g_ptr_array_free(prev_logs, TRUE); if (curr_logs != self->logs) g_ptr_array_free(curr_logs, TRUE); return ret_clusters; } msg_error("Invalid iteration type", evt_tag_int("iteration_type", self->iterate)); return NULL; } void ptz_print_patterndb_rule(gpointer key, gpointer value, gpointer user_data) { char uuid_string[37]; gchar **words; gchar *skey; gchar *splitstr; gchar *escapedstr; gchar **escapedparts; gchar *samplestr, *samplestr_escaped; gboolean named_parsers = *((gboolean *) user_data); guint parser_counts[PTZ_NUM_OF_PARSERS]; int i; Cluster *cluster; GString *pattern = g_string_new(""); guint wordcount; gchar *delimiters; cluster = (Cluster *) value; if (named_parsers) { for (i = 0; i < PTZ_NUM_OF_PARSERS; ++i) parser_counts[i] = 0; } uuid_gen_random(uuid_string, sizeof(uuid_string)); printf(" \n", uuid_string); printf(" \n", cluster->loglines->len); printf(" \n"); printf(" "); /* we have to help strsplit a bit here so that we * won't get junk as the last word */ skey = g_strdup((gchar *) key); if (skey[strlen(skey) -1] == PTZ_SEPARATOR_CHAR) skey[strlen(skey) -1] = 0; splitstr = g_strdup_printf("%c", PTZ_SEPARATOR_CHAR); words = g_strsplit(skey, splitstr, 0); g_free(splitstr); /* pop the delimiters from the cluster key */ wordcount = g_strv_length(words); delimiters = words[wordcount-1]; words[wordcount-1] = 0; for (i = 0; words[i]; ++i) { g_string_truncate(pattern, 0); gchar **word_parts; word_parts = g_strsplit(words[i], " ", 2); if (word_parts[1][0] == PTZ_PARSER_MARKER_CHAR) { /* NOTE: nasty workaround: do not display last ESTRING as syslog-ng won't handle that well... */ /* FIXME: enter a simple @STRING@ here instead... */ if (words[i + 1]) { g_string_append(pattern, "@ESTRING:"); if (named_parsers) { /* TODO: do not hardcode ESTRING here... */ g_string_append_printf(pattern, ".dict.string%d", parser_counts[PTZ_PARSER_ESTRING]++); } g_string_append_printf(pattern, ":%c@", delimiters[i]); escapedstr = g_markup_escape_text(pattern->str, -1); printf("%s", escapedstr); g_free(escapedstr); } } else { g_string_append(pattern, word_parts[1]); if (words[i + 1]) g_string_append_printf(pattern, "%c", delimiters[i]); escapedstr = g_markup_escape_text(pattern->str, -1); if (g_strrstr(escapedstr, "@")) { escapedparts = g_strsplit(escapedstr, "@", -1); g_free(escapedstr); escapedstr = g_strjoinv("@@", escapedparts); g_strfreev(escapedparts); } printf("%s", escapedstr); g_free(escapedstr); } g_strfreev(word_parts); } g_free(skey); g_free(delimiters); g_strfreev(words); g_string_free(pattern, TRUE); printf("\n"); printf(" \n"); if (cluster->samples->len > 0) { printf(" \n"); for (i = 0; i < cluster->samples->len; ++i) { samplestr = (gchar *) g_ptr_array_index(cluster->samples, i); samplestr_escaped = g_markup_escape_text(samplestr, strlen(samplestr)); printf(" \n"); printf(" %s\n", samplestr_escaped); printf(" \n"); g_free(samplestr_escaped); } printf(" \n"); printf(" \n"); } } void ptz_print_patterndb(GHashTable *clusters, const gchar *delimiters, gboolean named_parsers) { char date[12], uuid_string[37]; time_t currtime; /* print the header */ time(&currtime); strftime(date, 12, "%Y-%m-%d", localtime(&currtime)); printf("\n", date); uuid_gen_random(uuid_string, sizeof(uuid_string)); printf(" \n", uuid_string); printf(" \n"); g_hash_table_foreach(clusters, ptz_print_patterndb_rule, (gpointer *) &named_parsers); printf(" \n"); printf(" \n"); printf("\n"); } gboolean ptz_load_file(Patternizer *self, gchar *input_file, gboolean no_parse, GError **error) { FILE *file; int len; MsgFormatOptions parse_options; gchar line[PTZ_MAXLINELEN]; LogMessage *msg; if (!input_file) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "No input file specified"); return FALSE; } if (strcmp(input_file, "-") != 0) { if (!(file = fopen(input_file, "r"))) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_IO, "Error opening input file %s", input_file); return FALSE; } } else { file = stdin; } memset(&parse_options, 0, sizeof(parse_options)); msg_format_options_defaults(&parse_options); if (no_parse) parse_options.flags |= LP_NOPARSE; else parse_options.flags |= LP_SYSLOG_PROTOCOL; msg_format_options_init(&parse_options, configuration); while (fgets(line, PTZ_MAXLINELEN, file)) { len = strlen(line); if (line[len-1] == '\n') line[len-1] = 0; msg = msg_format_parse(&parse_options, (const guchar *) line, len); g_ptr_array_add(self->logs, msg); } self->support = (guint)(self->logs->len * (self->support_treshold / 100.0)); msg_format_options_destroy(&parse_options); return TRUE; } Patternizer * ptz_new(gdouble support_treshold, guint algo, guint iterate, guint num_of_samples, const gchar *delimiters) { Patternizer *self = g_new0(Patternizer, 1); self->algo = algo; self->iterate = iterate; self->support_treshold = support_treshold; self->num_of_samples = num_of_samples; self->delimiters = delimiters; self->logs = g_ptr_array_sized_new(PTZ_LOGTABLE_ALLOC_BASE); cluster_tag_id = log_tags_get_by_name(".in_patternize_cluster"); return self; } void ptz_free(Patternizer *self) { int i; for (i = 0; i < self->logs->len; ++i) log_msg_unref((LogMessage *) (LogMessage *) g_ptr_array_index(self->logs, i)); g_ptr_array_free(self->logs, TRUE); g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/correlation/patternize.h000066400000000000000000000046751450431004300237160ustar00rootroot00000000000000/* * Copyright (c) 2010-2012 Balabit * Copyright (c) 2009-2011 Péter Gyöngyösi * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PATTERNIZE_H_INCLUDED #define CORRELATION_PATTERNIZE_H_INCLUDED #define PTZ_ALGO_SLCT 1 #define PTZ_ALGO_LOGHOUND 2 #define PTZ_ITERATE_NONE 0 #define PTZ_ITERATE_OUTLIERS 1 #define PTZ_ITERATE_HIEARARCH 2 #define PTZ_SEPARATOR_CHAR 0x1E #define PTZ_PARSER_MARKER_CHAR 0x1A #define PTZ_NUM_OF_PARSERS 1 #define PTZ_PARSER_ESTRING 0 #include "syslog-ng.h" typedef struct _Patternizer { guint algo; guint iterate; guint support; guint num_of_samples; gdouble support_treshold; const gchar *delimiters; // NOTE: for now, we store all logs read in the memory. // This brings in some obvious constraints and should be solved // in a more optimized way later. GPtrArray *logs; } Patternizer; typedef struct _Cluster { GPtrArray *loglines; char **words; GPtrArray *samples; } Cluster; /* only declared for the test program */ GHashTable *ptz_find_frequent_words(GPtrArray *logs, guint support, const gchar *delimiters, gboolean two_pass); GHashTable *ptz_find_clusters_slct(GPtrArray *logs, guint support, const gchar *delimiters, guint num_of_samples); GHashTable *ptz_find_clusters(Patternizer *self); void ptz_print_patterndb(GHashTable *clusters, const gchar *delimiters, gboolean named_parsers); gboolean ptz_load_file(Patternizer *self, gchar *input_file, gboolean no_parse, GError **error); Patternizer *ptz_new(gdouble support_treshold, guint algo, guint iterate, guint num_of_samples, const gchar *delimiters); void ptz_free(Patternizer *self); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-action.c000066400000000000000000000061731450431004300235370ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-action.h" #include "pdb-error.h" #include "filter/filter-expr-parser.h" #include void pdb_action_set_condition(PDBAction *self, GlobalConfig *cfg, const gchar *filter_string, GError **error) { CfgLexer *lexer; lexer = cfg_lexer_new_buffer(cfg, filter_string, strlen(filter_string)); if (!cfg_run_parser_with_main_context(cfg, lexer, &filter_expr_parser, (gpointer *) &self->condition, NULL, "conditional expression")) { g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "Error compiling conditional expression"); self->condition = NULL; return; } if (!filter_expr_init(self->condition, cfg)) { g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "Error initializing conditional expression"); self->condition = NULL; return; } } void pdb_action_set_rate(PDBAction *self, const gchar *rate_) { gchar *slash; gchar *rate; rate = g_strdup(rate_); slash = strchr(rate, '/'); if (!slash) { self->rate = atoi(rate); self->rate_quantum = 1; } else { *slash = 0; self->rate = atoi(rate); self->rate_quantum = atoi(slash + 1); *slash = '/'; } if (self->rate_quantum == 0) self->rate_quantum = 1; g_free(rate); } void pdb_action_set_trigger(PDBAction *self, const gchar *trigger, GError **error) { if (strcmp(trigger, "match") == 0) self->trigger = RAT_MATCH; else if (strcmp(trigger, "timeout") == 0) self->trigger = RAT_TIMEOUT; else g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "Unknown trigger type: %s", trigger); } PDBAction * pdb_action_new(gint id) { PDBAction *self; self = g_new0(PDBAction, 1); self->trigger = RAT_MATCH; self->content_type = RAC_NONE; self->id = id; return self; } void pdb_action_free(PDBAction *self) { if (self->condition) filter_expr_unref(self->condition); switch (self->content_type) { case RAC_MESSAGE: synthetic_message_deinit(&self->content.message); break; case RAC_CREATE_CONTEXT: synthetic_context_deinit(&self->content.create_context.context); break; default: g_assert_not_reached(); } g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-action.h000066400000000000000000000041131450431004300235340ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_ACTION_H_INCLUDED #define CORRELATION_PDB_ACTION_H_INCLUDED #include "syslog-ng.h" #include "synthetic-message.h" #include "synthetic-context.h" #include "filter/filter-expr.h" /* rule action triggers */ typedef enum { RAT_MATCH = 1, RAT_TIMEOUT } PDBActionTrigger; /* action content*/ typedef enum { RAC_NONE, RAC_MESSAGE, RAC_CREATE_CONTEXT, } PDBActionContentType; /* a rule may contain one or more actions to be performed */ typedef struct _PDBAction { FilterExprNode *condition; PDBActionTrigger trigger; PDBActionContentType content_type; guint32 rate_quantum; guint16 rate; guint8 id; union { SyntheticMessage message; struct { SyntheticMessage message; SyntheticContext context; } create_context; } content; } PDBAction; void pdb_action_set_condition(PDBAction *self, GlobalConfig *cfg, const gchar *filter_string, GError **error); void pdb_action_set_rate(PDBAction *self, const gchar *rate_); void pdb_action_set_trigger(PDBAction *self, const gchar *trigger, GError **error); PDBAction *pdb_action_new(gint id); void pdb_action_free(PDBAction *self); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-context.c000066400000000000000000000025311450431004300237400ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-context.h" static void pdb_context_free(CorrelationContext *s) { PDBContext *self = (PDBContext *) s; if (self->rule) pdb_rule_unref(self->rule); correlation_context_free_method(s); } PDBContext * pdb_context_new(CorrelationKey *key) { PDBContext *self = g_new0(PDBContext, 1); correlation_context_init(&self->super, key); self->super.free_fn = pdb_context_free; return self; } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-context.h000066400000000000000000000031601450431004300237440ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_CONTEXT_H_INCLUDED #define CORRELATION_PDB_CONTEXT_H_INCLUDED #include "pdb-rule.h" /************************************************************************** * PDBContext, represents a correlation state in the state hash table, is * marked with PSK_CONTEXT in the hash table key **************************************************************************/ /* This class encapsulates a correlation context, keyed by CorrelationKey, type == PSK_RULE. */ typedef struct _PDBContext { CorrelationContext super; /* back reference to the last rule touching this context */ PDBRule *rule; } PDBContext; PDBContext *pdb_context_new(CorrelationKey *key); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-error.c000066400000000000000000000020501450431004300234010ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-error.h" GQuark pdb_error_quark(void) { return g_quark_from_static_string("syslog-ng-error-quark"); } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-error.h000066400000000000000000000022271450431004300234140ustar00rootroot00000000000000/* * Copyright (c) 2016 Balabit * Copyright (c) 2016 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_ERROR_H_INCLUDED #define CORRELATION_PDB_ERROR_H_INCLUDED #include "syslog-ng.h" #define PDB_ERROR pdb_error_quark() GQuark pdb_error_quark(void); typedef enum { PDB_ERROR_FAILED, } PDBError; #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-example.c000066400000000000000000000026431450431004300237130ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-example.h" void pdb_example_free(PDBExample *self) { gint i; if (self->rule) pdb_rule_unref(self->rule); if (self->message) g_free(self->message); if (self->program) g_free(self->program); if (self->values) { for (i = 0; i < self->values->len; i++) { gchar **nv = g_ptr_array_index(self->values, i); g_strfreev(nv); } g_ptr_array_free(self->values, TRUE); } g_free(self); } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-example.h000066400000000000000000000027241450431004300237200ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_EXAMPLE_H_INCLUDED #define CORRELATION_PDB_EXAMPLE_H_INCLUDED #include "syslog-ng.h" #include "pdb-rule.h" /* this class encapsulates an example message in the pattern database * used for testing rules and patterns. It contains the message with the * program field and the expected rule_id with the expected name/value * pairs. */ typedef struct _PDBExample { PDBRule *rule; gchar *message; gchar *program; GPtrArray *values; } PDBExample; void pdb_example_free(PDBExample *s); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-file.c000066400000000000000000000147611450431004300232030ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 1998-2016 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-file.h" #include "pdb-error.h" #include "reloc.h" #include "pathutils.h" #include #include #include #include #include gint pdb_file_detect_version(const gchar *pdbfile, GError **error) { FILE *pdb; gchar line[1024]; gint result = 0; pdb = fopen(pdbfile, "r"); if (!pdb) { g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "Error opening file %s (%s)", pdbfile, g_strerror(errno)); return 0; } while (fgets(line, sizeof(line), pdb)) { gchar *patterndb_tag; patterndb_tag = strstr(line, " version attribute not found or is not on its own line"); } return result; } static const gchar * _get_xsddir_in_build(void) { static gchar path[256]; g_snprintf(path, sizeof(path), "%s/doc/xsd", SYSLOG_NG_PATH_TOPSRC_DIR); return path; } static const gchar * _get_xsddir_in_production(void) { return get_installation_path_for(SYSLOG_NG_PATH_XSDDIR); } typedef const gchar *(*PdbGetXsdDirFunc) (void); static gchar * _get_xsd_file(gint version, PdbGetXsdDirFunc get_xsd_dir) { return g_strdup_printf("%s/patterndb-%d.xsd", get_xsd_dir(), version); } static gboolean _pdb_file_validate(const gchar *filename, GError **error, PdbGetXsdDirFunc get_xsd_dir) { gchar *xmllint_cmdline; gint version; gint exit_status; gchar *stderr_content = NULL; gchar *xsd_file; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); version = pdb_file_detect_version(filename, error); if (!version) return FALSE; xsd_file = _get_xsd_file(version, get_xsd_dir); if (!is_file_regular(xsd_file)) { g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "XSD file is not available at %s", xsd_file); g_free(xsd_file); return FALSE; } xmllint_cmdline = g_strdup_printf("xmllint --noout --nonet --schema '%s' '%s'", xsd_file, filename); g_free(xsd_file); if (!g_spawn_command_line_sync(xmllint_cmdline, NULL, &stderr_content, &exit_status, error)) { g_free(xmllint_cmdline); g_free(stderr_content); return FALSE; } if (exit_status != 0) { g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "Non-zero exit code from xmllint while validating PDB file, " "schema version %d, rc=%d, error: %s, command line %s", version, WEXITSTATUS(exit_status), stderr_content, xmllint_cmdline); g_free(stderr_content); g_free(xmllint_cmdline); return FALSE; } g_free(xmllint_cmdline); g_free(stderr_content); return TRUE; } gboolean pdb_file_validate(const gchar *filename, GError **error) { return _pdb_file_validate(filename, error, _get_xsddir_in_production); } gboolean pdb_file_validate_in_tests(const gchar *filename, GError **error) { return _pdb_file_validate(filename, error, _get_xsddir_in_build); } GPtrArray * pdb_get_filenames(const gchar *dir_path, gboolean recursive, gchar *pattern, GError **error) { GDir *dir; if ((dir = g_dir_open(dir_path, 0, error)) == NULL) return NULL; GPtrArray *filenames = g_ptr_array_new_with_free_func(g_free); const gchar *path; while ((path = g_dir_read_name(dir)) != NULL) { gchar *full_path = g_build_filename(dir_path, path, NULL); if (recursive && is_file_directory(full_path)) { GPtrArray *recursive_filenames = pdb_get_filenames(full_path, recursive, pattern, error); if (recursive_filenames == NULL) { g_ptr_array_free(recursive_filenames, TRUE); g_ptr_array_free(filenames, TRUE); g_free(full_path); g_dir_close(dir); return NULL; } for (guint i = 0; i < recursive_filenames->len; ++i) g_ptr_array_add(filenames, g_ptr_array_index(recursive_filenames, i)); g_free(g_ptr_array_free(recursive_filenames, FALSE)); g_free(full_path); } else if (is_file_regular(full_path) && (!pattern || g_pattern_match_simple(pattern, full_path))) { g_ptr_array_add(filenames, full_path); } else { g_free(full_path); } } g_dir_close(dir); return filenames; } static guint pdbtool_get_path_depth(const gchar *path) { gint depth = 0; while (*path) { if (*path++ == '/') ++depth; } return depth; } static int pdbtool_path_compare(gconstpointer a, gconstpointer b) { const gchar *path_a = *(const gchar **)a; const gchar *path_b = *(const gchar **)b; guint a_depth = pdbtool_get_path_depth(path_a); guint b_depth = pdbtool_get_path_depth(path_b); if (a_depth > b_depth) return 1; else if (a_depth < b_depth) return -1; else return strcmp(path_a, path_b); } void pdb_sort_filenames(GPtrArray *filenames) { g_ptr_array_sort(filenames, pdbtool_path_compare); } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-file.h000066400000000000000000000026321450431004300232020ustar00rootroot00000000000000/* * Copyright (c) 2002-2016 Balabit * Copyright (c) 1998-2016 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_FILE_H_INCLUDED #define CORRELATION_PDB_FILE_H_INCLUDED 1 #include "syslog-ng.h" gint pdb_file_detect_version(const gchar *pdbfile, GError **error); gboolean pdb_file_validate(const gchar *filename, GError **error); gboolean pdb_file_validate_in_tests(const gchar *filename, GError **error); GPtrArray *pdb_get_filenames(const gchar *dir_path, gboolean recursive, gchar *pattern, GError **error); void pdb_sort_filenames(GPtrArray *filenames); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-load.c000066400000000000000000001126611450431004300232010ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "patterndb.h" #include "pdb-rule.h" #include "pdb-program.h" #include "pdb-action.h" #include "pdb-example.h" #include "pdb-ruleset.h" #include "pdb-error.h" #include #include #include #include enum PDBLoaderState { PDBL_INITIAL = 0, PDBL_PATTERNDB, PDBL_RULESET, PDBL_RULESET_URL, PDBL_RULESET_DESCRIPTION, PDBL_RULESET_PATTERN, PDBL_RULES, PDBL_RULE, PDBL_RULE_URL, PDBL_RULE_DESCRIPTION, PDBL_RULE_PATTERN, PDBL_RULE_EXAMPLES, PDBL_RULE_EXAMPLE, PDBL_RULE_EXAMPLE_TEST_MESSAGE, PDBL_RULE_EXAMPLE_TEST_VALUES, PDBL_RULE_EXAMPLE_TEST_VALUE, PDBL_RULE_ACTIONS, PDBL_RULE_ACTION, PDBL_RULE_ACTION_CREATE_CONTEXT, /* generic states, reused by multiple paths in the XML */ PDBL_VALUE, PDBL_TAG, PDBL_MESSAGE, }; #define PDB_STATE_STACK_MAX_DEPTH 12 typedef struct _PDBStateStack { gint stack[PDB_STATE_STACK_MAX_DEPTH]; gint top; } PDBStateStack; /* arguments passed to the markup parser functions */ typedef struct _PDBLoader { const gchar *filename; GMarkupParseContext *context; PDBRuleSet *ruleset; PDBProgram *root_program; PDBProgram *current_program; PDBRule *current_rule; PDBAction *current_action; PDBExample *current_example; SyntheticMessage *current_message; enum PDBLoaderState current_state; PDBStateStack state_stack; gboolean first_program; gboolean load_examples; GList *examples; gchar *value_name; gchar *value_type; gchar *test_value_name; gchar *test_value_type; GlobalConfig *cfg; gint action_id; GHashTable *ruleset_patterns; GArray *program_patterns; } PDBLoader; typedef struct _PDBProgramPattern { gchar *pattern; gchar *pdb_location; PDBRule *rule; } PDBProgramPattern; static void pdb_program_pattern_clear(PDBProgramPattern *self) { pdb_rule_unref(self->rule); g_free(self->pattern); g_free(self->pdb_location); } static void _pdb_state_stack_push(PDBStateStack *self, gint state) { g_assert(self->top < PDB_STATE_STACK_MAX_DEPTH - 1); self->stack[self->top] = state; self->top++; } static gint _pdb_state_stack_pop(PDBStateStack *self) { g_assert(self->top > 0); self->top--; return self->stack[self->top]; } static gchar * _pdb_format_location(PDBLoader *state) { gint line, column; g_markup_parse_context_get_position(state->context, &line, &column); return g_strdup_printf("%s:%d:%d", state->filename, line, column); } static void G_GNUC_PRINTF(3, 4) pdb_loader_set_error(PDBLoader *state, GError **error, const gchar *format, ...) { gchar *error_text; gchar *error_location; gint line_number, col_number; va_list va; va_start(va, format); error_text = g_strdup_vprintf(format, va); va_end(va); g_markup_parse_context_get_position(state->context, &line_number, &col_number); error_location = g_strdup_printf("%s:%d:%d", state->filename, line_number, col_number); g_set_error(error, PDB_ERROR, PDB_ERROR_FAILED, "%s: %s", error_location, error_text); g_free(error_text); g_free(error_location); } static void _push_state(PDBLoader *state, gint new_state) { _pdb_state_stack_push(&state->state_stack, state->current_state); state->current_state = new_state; } static void _pop_state(PDBLoader *state) { state->current_state = _pdb_state_stack_pop(&state->state_stack); } static gboolean _pop_state_for_closing_tag_with_alternatives(PDBLoader *state, const gchar *element_name, const gchar *expected_element, const gchar *alternatives, GError **error) { if (strcmp(element_name, expected_element) != 0) { pdb_loader_set_error(state, error, "Unexpected tag, expected %s%s", element_name, expected_element, alternatives ? ", " : "", alternatives); return FALSE; } _pop_state(state); return TRUE; } static gboolean _pop_state_for_closing_tag(PDBLoader *state, const gchar *element_name, const gchar *expected_element, GError **error) { return _pop_state_for_closing_tag_with_alternatives(state, element_name, expected_element, NULL, error); } static gboolean _is_whitespace_only(const gchar *text, gsize text_len) { gint i; for (i = 0; i < text_len; i++) { if (!g_ascii_isspace(text[i])) return FALSE; } return TRUE; } static void _process_value_element(PDBLoader *state, const gchar **attribute_names, const gchar **attribute_values, GError **error) { for (gint i = 0; attribute_names[i]; i++) { const gchar *attr = attribute_names[i]; const gchar *value = attribute_values[i]; if (g_str_equal(attr, "name")) state->value_name = g_strdup(value); else if (g_str_equal(attr, "type")) state->value_type = g_strdup(value); } if (!state->value_name) { pdb_loader_set_error(state, error, " misses name attribute in rule %s", state->current_rule->rule_id); return; } _push_state(state, PDBL_VALUE); } static void _process_tag_element(PDBLoader *state, const gchar **attribute_names, const gchar **attribute_values, GError **error) { _push_state(state, PDBL_TAG); } static void _process_message_element(PDBLoader *state, const gchar **attribute_names, const gchar **attribute_values, SyntheticMessage *target, GError **error) { gint i; for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "inherit-properties") == 0) synthetic_message_set_inherit_properties_string(target, attribute_values[i], error); else if (strcmp(attribute_names[i], "inherit-mode") == 0) synthetic_message_set_inherit_mode_string(target, attribute_values[i], error); } state->current_message = target; _push_state(state, PDBL_MESSAGE); } static void _process_create_context_element(PDBLoader *state, const gchar **attribute_names, const gchar **attribute_values, SyntheticContext *target, GError **error) { gint i; for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "context-id") == 0) { LogTemplate *template; GError *local_error = NULL; template = log_template_new(state->cfg, NULL); if (!log_template_compile(template, attribute_values[i], &local_error)) { log_template_unref(template); pdb_loader_set_error(state, error, "Error compiling create-context context-id, rule=%s, context-id=%s, error=%s", state->current_rule->rule_id, attribute_values[i], local_error->message); g_clear_error(&local_error); return; } else synthetic_context_set_context_id_template(target, template); } else if (strcmp(attribute_names[i], "context-timeout") == 0) synthetic_context_set_context_timeout(target, strtol(attribute_values[i], NULL, 0)); else if (strcmp(attribute_names[i], "context-scope") == 0) synthetic_context_set_context_scope(target, attribute_values[i], error); } if (!target->id_template) { pdb_loader_set_error(state, error, "context-id attribute is missing from , rule=%s", state->current_rule->rule_id); return; } _push_state(state, PDBL_RULE_ACTION_CREATE_CONTEXT); } /* PDBL_INITIAL */ static void _pdbl_initial_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { gint i; if (strcmp(element_name, "patterndb") == 0) { for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "version") == 0) state->ruleset->version = g_strdup(attribute_values[i]); else if (strcmp(attribute_names[i], "pub_date") == 0) state->ruleset->pub_date = g_strdup(attribute_values[i]); } if (!state->ruleset->version) { msg_warning("patterndb version is unspecified, assuming v4 format"); state->ruleset->version = g_strdup("4"); } else if (state->ruleset->version && atoi(state->ruleset->version) < 2) { pdb_loader_set_error(state, error, "patterndb version too old, this version of syslog-ng only supports v3 and v4 formatted patterndb files, please upgrade it using pdbtool merge"); return; } else if (state->ruleset->version && atoi(state->ruleset->version) > 6) { pdb_loader_set_error(state, error, "patterndb version too new, this version of syslog-ng supports v3..v6 formatted patterndb files."); return; } _push_state(state, PDBL_PATTERNDB); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a ", element_name); } } /* PDBL_PATTERNDB */ static void _pdbl_patterndb_start(PDBLoader *state, const gchar *element_name, GError **error) { if (strcmp(element_name, "ruleset") == 0) { state->ruleset->is_empty = FALSE; state->first_program = TRUE; state->program_patterns = g_array_new(0, 0, sizeof(PDBProgramPattern)); _push_state(state, PDBL_RULESET); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a ", element_name); } } static void _populate_ruleset_radix(gpointer key, gpointer value, gpointer user_data) { PDBLoader *state = (PDBLoader *) user_data; gchar *pattern = key; PDBProgram *program = (PDBProgram *) value; r_insert_node(state->ruleset->programs, pattern, pdb_program_ref(program), state->ruleset->prefix, NULL, program->pdb_location); } static void _pdbl_patterndb_end(PDBLoader *state, const gchar *element_name, GError **error) { if (_pop_state_for_closing_tag(state, element_name, "patterndb", error)) { g_hash_table_foreach(state->ruleset_patterns, _populate_ruleset_radix, state); g_hash_table_remove_all(state->ruleset_patterns); } } /* PDBL_RULESET */ static void _pdbl_ruleset_start(PDBLoader *state, const gchar *element_name, GError **error) { if (strcmp(element_name, "rules") == 0) { _push_state(state, PDBL_RULES); } else if (strcmp(element_name, "patterns") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "urls") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "url") == 0) { _push_state(state, PDBL_RULESET_URL); } else if (strcmp(element_name, "pattern") == 0) { _push_state(state, PDBL_RULESET_PATTERN); } else if (strcmp(element_name, "description") == 0) { _push_state(state, PDBL_RULESET_DESCRIPTION); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a , , , , or ", element_name); } } static void _pdbl_ruleset_end(PDBLoader *state, const gchar *element_name, GError **error) { gint i; PDBProgramPattern *program_pattern; PDBProgram *program; if (strcmp(element_name, "patterns") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "urls") == 0) { /* valid, but we don't do anything */ } else if (_pop_state_for_closing_tag_with_alternatives(state, element_name, "ruleset", " or ", error)) { program = (state->current_program ? state->current_program : state->root_program); /* Copy stored rules into current program */ for (i = 0; i < state->program_patterns->len; i++) { program_pattern = &g_array_index(state->program_patterns, PDBProgramPattern, i); r_insert_node(program->rules, program_pattern->pattern, pdb_rule_ref(program_pattern->rule), state->ruleset->prefix, (RNodeGetValueFunc) pdb_rule_get_name, program_pattern->pdb_location); pdb_program_pattern_clear(program_pattern); } state->current_program = NULL; g_array_free(state->program_patterns, TRUE); state->program_patterns = NULL; } } /* PDBL_RULESET_PATTERN */ static gboolean _pdbl_ruleset_pattern_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { if (state->first_program) { state->current_program = g_hash_table_lookup(state->ruleset_patterns, text); if (state->current_program == NULL) { /* create new program specific radix */ state->current_program = pdb_program_new(); state->current_program->pdb_location = _pdb_format_location(state); g_hash_table_insert(state->ruleset_patterns, g_strdup(text), state->current_program); } state->first_program = FALSE; } else if (state->current_program) { /* secondary program names should point to the same MSG radix */ PDBProgram *program = g_hash_table_lookup(state->ruleset_patterns, text); if (!program) { g_hash_table_insert(state->ruleset_patterns, g_strdup(text), pdb_program_ref(state->current_program)); } else if (program != state->current_program) { pdb_loader_set_error(state, error, "Joining rulesets with mismatching program name sets, program=%s", text); return FALSE; } } return TRUE; } /* PDBL_RULES */ static void _pdbl_rules_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { gint i; if (strcmp(element_name, "rule") == 0) { state->current_rule = pdb_rule_new(); for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "class") == 0) pdb_rule_set_class(state->current_rule, attribute_values[i]); else if (strcmp(attribute_names[i], "id") == 0) pdb_rule_set_rule_id(state->current_rule, attribute_values[i]); else if (strcmp(attribute_names[i], "context-id") == 0) { LogTemplate *template; GError *local_error = NULL; template = log_template_new(state->cfg, NULL); if (!log_template_compile(template, attribute_values[i], &local_error)) { log_template_unref(template); pdb_loader_set_error(state, error, "Error compiling context-id template, rule=%s, context-id=%s, error=%s", state->current_rule->rule_id, attribute_values[i], local_error->message); g_clear_error(&local_error); return; } else synthetic_context_set_context_id_template(&state->current_rule->context, template); } else if (strcmp(attribute_names[i], "context-timeout") == 0) synthetic_context_set_context_timeout(&state->current_rule->context, strtol(attribute_values[i], NULL, 0)); else if (strcmp(attribute_names[i], "context-scope") == 0) synthetic_context_set_context_scope(&state->current_rule->context, attribute_values[i], error); } if (!state->current_rule->rule_id) { pdb_loader_set_error(state, error, "No id attribute for rule element"); pdb_rule_unref(state->current_rule); state->current_rule = NULL; return; } state->current_message = &state->current_rule->msg; synthetic_message_set_prefix(state->current_message, state->ruleset->prefix); state->action_id = 0; _push_state(state, PDBL_RULE); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a ", element_name); } } /* PDBL_RULE */ static void _pdbl_rule_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { if (strcmp(element_name, "patterns") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "pattern") == 0) { _push_state(state, PDBL_RULE_PATTERN); } else if (strcmp(element_name, "tags") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "tag") == 0) { _process_tag_element(state, attribute_names, attribute_values, error); } else if (strcmp(element_name, "values") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "urls") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "description") == 0) { _push_state(state, PDBL_RULE_DESCRIPTION); } else if (strcmp(element_name, "url") == 0) { _push_state(state, PDBL_RULE_URL); } else if (strcmp(element_name, "value") == 0) { _process_value_element(state, attribute_names, attribute_values, error); } else if (strcmp(element_name, "actions") == 0) { _push_state(state, PDBL_RULE_ACTIONS); } else if (strcmp(element_name, "examples") == 0) { _push_state(state, PDBL_RULE_EXAMPLES); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a , , , or ", element_name); } } static void _pdbl_rule_end(PDBLoader *state, const gchar *element_name, GError **error) { if (strcmp(element_name, "patterns") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "description") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "tags") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "urls") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "values") == 0) { /* valid, but we don't do anything */ } else if (_pop_state_for_closing_tag_with_alternatives(state, element_name, "rule", ", , , , ", error)) { if (state->current_rule) { pdb_rule_unref(state->current_rule); state->current_rule = NULL; } state->current_message = NULL; } } /* PDBL_RULE_EXAMPLES */ static void _pdbl_rule_examples_start(PDBLoader *state, const gchar *element_name, GError **error) { if (strcmp(element_name, "example") == 0) { state->current_example = g_new0(PDBExample, 1); state->current_example->rule = pdb_rule_ref(state->current_rule); _push_state(state, PDBL_RULE_EXAMPLE); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a ", element_name); } } /* PDBL_RULE_EXAMPLE */ static void _pdbl_rule_example_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { gint i; if (strcmp(element_name, "test_message") == 0) { for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "program") == 0) state->current_example->program = g_strdup(attribute_values[i]); } _push_state(state, PDBL_RULE_EXAMPLE_TEST_MESSAGE); } else if (strcmp(element_name, "test_values") == 0) { _push_state(state, PDBL_RULE_EXAMPLE_TEST_VALUES); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a , ", element_name); } } static void _pdbl_rule_example_end(PDBLoader *state, const gchar *element_name, GError **error) { if (_pop_state_for_closing_tag(state, element_name, "example", error)) { if (state->load_examples) state->examples = g_list_prepend(state->examples, state->current_example); else pdb_example_free(state->current_example); state->current_example = NULL; } } /* PDBL_RULE_EXAMPLE_TEST_MESSAGE */ static gboolean _pdbl_rule_example_test_message_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { state->current_example->message = g_strdup(text); return TRUE; } /* PDBL_RULE_EXAMPLE_TEST_VALUES */ static void _pdbl_rule_example_test_values_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { if (strcmp(element_name, "test_value") == 0) { for (gint i = 0; attribute_names[i]; i++) { const gchar *attr = attribute_names[i]; const gchar *value = attribute_values[i]; if (g_str_equal(attr, "name")) state->test_value_name = g_strdup(value); else if (g_str_equal(attr, "type")) state->test_value_type = g_strdup(value); } if (!state->test_value_name) { msg_error("No name is specified for test_value", evt_tag_str("rule_id", state->current_rule->rule_id)); pdb_loader_set_error(state, error, " misses name attribute"); return; } _push_state(state, PDBL_RULE_EXAMPLE_TEST_VALUE); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected ", element_name); } } /* PDBL_RULE_EXAMPLE_TEST_VALUE */ static void _pdbl_rule_example_test_value_end(PDBLoader *state, const gchar *element_name, GError **error) { if (_pop_state_for_closing_tag(state, element_name, "test_value", error)) { g_free(state->test_value_name); g_free(state->test_value_type); state->test_value_name = NULL; state->test_value_type = NULL; } } static gboolean _pdbl_rule_example_test_value_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { gchar **nv; if (!state->current_example->values) state->current_example->values = g_ptr_array_new(); nv = g_new(gchar *, 4); nv[0] = state->test_value_name; nv[1] = g_strdup(text); nv[2] = g_strdup(state->test_value_type); nv[3] = NULL; state->test_value_name = NULL; state->test_value_type = NULL; g_ptr_array_add(state->current_example->values, nv); return TRUE; } /* PDBL_RULE_ACTIONS */ static void _pdbl_rule_actions_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { gint i; if (strcmp(element_name, "action") == 0) { if (!state->current_rule) { pdb_loader_set_error(state, error, "Unexpected element, it must be inside a rule"); return; } state->current_action = pdb_action_new(state->action_id++); for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "trigger") == 0) pdb_action_set_trigger(state->current_action, attribute_values[i], error); else if (strcmp(attribute_names[i], "condition") == 0) pdb_action_set_condition(state->current_action, state->cfg, attribute_values[i], error); else if (strcmp(attribute_names[i], "rate") == 0) pdb_action_set_rate(state->current_action, attribute_values[i]); } _push_state(state, PDBL_RULE_ACTION); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a ", element_name); } } /* PDBL_RULE_ACTION */ static void _pdbl_rule_action_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { if (strcmp(element_name, "message") == 0) { state->current_action->content_type = RAC_MESSAGE; _process_message_element(state, attribute_names, attribute_values, &state->current_action->content.message, error); } else if (strcmp(element_name, "create-context") == 0) { state->current_action->content_type = RAC_CREATE_CONTEXT; _process_create_context_element(state, attribute_names, attribute_values, &state->current_action->content.create_context.context, error); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected or ", element_name); } } /* PDBL_RULE_ACTION_CREATE_CONTEXT */ static void _pdbl_rule_action_create_context_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { if (strcmp(element_name, "message") == 0) { _process_message_element(state, attribute_names, attribute_values, &state->current_action->content.create_context.message, error); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected ", element_name); } } /* PDBL_MESSAGE */ static void _pdbl_message_start(PDBLoader *state, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, GError **error) { if (strcmp(element_name, "values") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "value") == 0) { _process_value_element(state, attribute_names, attribute_values, error); } else if (strcmp(element_name, "tags") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "tag") == 0) { _process_tag_element(state, attribute_names, attribute_values, error); } else { pdb_loader_set_error(state, error, "Unexpected <%s> tag, expected a , , or ", element_name); } } /* PDBL_RULE_PATTERN */ static gboolean _pdbl_rule_pattern_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { PDBProgramPattern program_pattern; program_pattern.pattern = g_strdup(text); program_pattern.rule = pdb_rule_ref(state->current_rule); program_pattern.pdb_location = _pdb_format_location(state); g_array_append_val(state->program_patterns, program_pattern); return TRUE; } /* PDBL_RULE_ACTION */ static void _pdbl_rule_action_end(PDBLoader *state, const gchar *element_name, GError **error) { if (_pop_state_for_closing_tag(state, element_name, "action", error)) { pdb_rule_add_action(state->current_rule, state->current_action); state->current_action = NULL; } } /* PDBL_MESSAGE */ static void _pdbl_message_end(PDBLoader *state, const gchar *element_name, GError **error) { if (strcmp(element_name, "values") == 0) { /* valid, but we don't do anything */ } else if (strcmp(element_name, "tags") == 0) { /* valid, but we don't do anything */ } else if (_pop_state_for_closing_tag_with_alternatives(state, element_name, "message", ", ", error)) { state->current_message = &state->current_rule->msg; } } /* PDBL_VALUE */ static void _pdbl_value_end(PDBLoader *state, const gchar *element_name, GError **error) { if (_pop_state_for_closing_tag(state, element_name, "value", error)) { g_free(state->value_name); g_free(state->value_type); state->value_name = NULL; state->value_type = NULL; } } static gboolean _pdbl_value_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { GError *err = NULL; g_assert(state->value_name != NULL); if (!synthetic_message_add_value_template_string_and_type(state->current_message, state->cfg, state->value_name, text, state->value_type, &err)) { pdb_loader_set_error(state, error, "Error compiling value template, rule=%s, name=%s, value=%s, error=%s", state->current_rule->rule_id, state->value_name, text, err->message); return FALSE; } return TRUE; } /* PDBL_TAG */ static gboolean _pdbl_tag_text(PDBLoader *state, const gchar *text, gsize text_len, GError **error) { synthetic_message_add_tag(state->current_message, text); return TRUE; } /* element start callback */ void pdb_loader_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { PDBLoader *state = (PDBLoader *) user_data; switch (state->current_state) { case PDBL_INITIAL: _pdbl_initial_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_PATTERNDB: _pdbl_patterndb_start(state, element_name, error); break; case PDBL_RULESET: _pdbl_ruleset_start(state, element_name, error); break; case PDBL_RULES: _pdbl_rules_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE: _pdbl_rule_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE_EXAMPLES: _pdbl_rule_examples_start(state, element_name, error); break; case PDBL_RULE_EXAMPLE: _pdbl_rule_example_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE_EXAMPLE_TEST_VALUES: _pdbl_rule_example_test_values_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE_ACTIONS: _pdbl_rule_actions_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE_ACTION: _pdbl_rule_action_start(state, element_name, attribute_names, attribute_values, error); break; case PDBL_RULE_ACTION_CREATE_CONTEXT: _pdbl_rule_action_create_context_start(state, element_name, attribute_names, attribute_values, error); break; /* generic states reused by multiple locations in the grammar */ case PDBL_MESSAGE: _pdbl_message_start(state, element_name, attribute_names, attribute_values, error); break; default: pdb_loader_set_error(state, error, "Unexpected state %d, tag <%s>", state->current_state, element_name); break; } } void pdb_loader_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { PDBLoader *state = (PDBLoader *) user_data; switch (state->current_state) { case PDBL_PATTERNDB: _pdbl_patterndb_end(state, element_name, error); break; case PDBL_RULESET: _pdbl_ruleset_end(state, element_name, error); break; case PDBL_RULESET_URL: _pop_state_for_closing_tag(state, element_name, "url", error); break; case PDBL_RULESET_PATTERN: _pop_state_for_closing_tag(state, element_name, "pattern", error); break; case PDBL_RULESET_DESCRIPTION: _pop_state_for_closing_tag(state, element_name, "description", error); break; case PDBL_RULES: _pop_state_for_closing_tag(state, element_name, "rules", error); break; case PDBL_RULE: _pdbl_rule_end(state, element_name, error); break; case PDBL_RULE_DESCRIPTION: _pop_state_for_closing_tag(state, element_name, "description", error); break; case PDBL_RULE_URL: _pop_state_for_closing_tag(state, element_name, "url", error); break; case PDBL_RULE_PATTERN: _pop_state_for_closing_tag(state, element_name, "pattern", error); break; case PDBL_RULE_EXAMPLES: _pop_state_for_closing_tag(state, element_name, "examples", error); break; case PDBL_RULE_EXAMPLE: _pdbl_rule_example_end(state, element_name, error); break; case PDBL_RULE_EXAMPLE_TEST_VALUES: _pop_state_for_closing_tag(state, element_name, "test_values", error); break; case PDBL_RULE_EXAMPLE_TEST_VALUE: _pdbl_rule_example_test_value_end(state, element_name, error); break; case PDBL_RULE_EXAMPLE_TEST_MESSAGE: _pop_state_for_closing_tag(state, element_name, "test_message", error); break; case PDBL_RULE_ACTIONS: _pop_state_for_closing_tag(state, element_name, "actions", error); break; case PDBL_RULE_ACTION: _pdbl_rule_action_end(state, element_name, error); break; case PDBL_RULE_ACTION_CREATE_CONTEXT: _pop_state_for_closing_tag(state, element_name, "create-context", error); break; /* generic states reused by multiple locations in the grammar */ case PDBL_MESSAGE: _pdbl_message_end(state, element_name, error); break; case PDBL_VALUE: _pdbl_value_end(state, element_name, error); break; case PDBL_TAG: _pop_state_for_closing_tag(state, element_name, "tag", error); break; default: pdb_loader_set_error(state, error, "Unexpected state %d, tag ", state->current_state, element_name); break; } } void pdb_loader_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { PDBLoader *state = (PDBLoader *) user_data; switch (state->current_state) { case PDBL_RULESET_DESCRIPTION: break; case PDBL_RULESET_PATTERN: if (!_pdbl_ruleset_pattern_text(state, text, text_len, error)) return; break; case PDBL_RULESET_URL: break; case PDBL_RULE_PATTERN: if (!_pdbl_rule_pattern_text(state, text, text_len, error)) return; break; case PDBL_RULE_EXAMPLE: break; case PDBL_RULE_URL: break; case PDBL_RULE_DESCRIPTION: break; case PDBL_RULE_EXAMPLE_TEST_MESSAGE: if (!_pdbl_rule_example_test_message_text(state, text, text_len, error)) return; break; case PDBL_RULE_EXAMPLE_TEST_VALUE: if (!_pdbl_rule_example_test_value_text(state, text, text_len, error)) return; break; /* generic states reused by multiple locations in the grammar */ case PDBL_VALUE: if (!_pdbl_value_text(state, text, text_len, error)) return; break; case PDBL_TAG: if (!_pdbl_tag_text(state, text, text_len, error)) return; break; default: if (!_is_whitespace_only(text, text_len)) pdb_loader_set_error(state, error, "Unexpected text node in state %d, text=[[%s]]", state->current_state, text); break; } } static GMarkupParser db_parser = { .start_element = pdb_loader_start_element, .end_element = pdb_loader_end_element, .text = pdb_loader_text, .passthrough = NULL, .error = NULL }; gboolean pdb_rule_set_load(PDBRuleSet *self, GlobalConfig *cfg, const gchar *config, GList **examples) { PDBLoader state; GMarkupParseContext *parse_ctx = NULL; GError *error = NULL; FILE *dbfile = NULL; gint bytes_read; gchar buff[4096]; gboolean success = FALSE; if ((dbfile = fopen(config, "r")) == NULL) { msg_error("Error opening classifier configuration file", evt_tag_str(EVT_TAG_FILENAME, config), evt_tag_error(EVT_TAG_OSERROR)); return FALSE; } memset(&state, 0x0, sizeof(state)); state.ruleset = self; state.root_program = pdb_program_new(); state.load_examples = !!examples; state.ruleset_patterns = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) pdb_program_unref); state.cfg = cfg; state.filename = config; state.context = parse_ctx = g_markup_parse_context_new(&db_parser, 0, &state, NULL); self->programs = r_new_node("", state.root_program); while ((bytes_read = fread(buff, sizeof(gchar), 4096, dbfile)) != 0) { if (!g_markup_parse_context_parse(parse_ctx, buff, bytes_read, &error)) { msg_error("Error parsing pattern database file", evt_tag_str(EVT_TAG_FILENAME, config), evt_tag_str("error", error ? error->message : "unknown")); goto error; } } fclose(dbfile); dbfile = NULL; if (!g_markup_parse_context_end_parse(parse_ctx, &error)) { msg_error("Error parsing pattern database file", evt_tag_str(EVT_TAG_FILENAME, config), evt_tag_str("error", error ? error->message : "unknown")); goto error; } if (state.load_examples) *examples = state.examples; success = TRUE; error: if (dbfile) fclose(dbfile); if (parse_ctx) g_markup_parse_context_free(parse_ctx); g_hash_table_unref(state.ruleset_patterns); if (error) g_error_free(error); return success; } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-load.h000066400000000000000000000023121450431004300231750ustar00rootroot00000000000000/* * Copyright (c) 2002-2013, 2015 Balabit * Copyright (c) 1998-2013, 2015 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_LOAD_H_INCLUDED #define CORRELATION_PDB_LOAD_H_INCLUDED #include "syslog-ng.h" #include "pdb-ruleset.h" #include "cfg.h" gboolean pdb_rule_set_load(PDBRuleSet *self, GlobalConfig *cfg, const gchar *config, GList **examples); #endif syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-lookup-params.c000066400000000000000000000027011450431004300250450ustar00rootroot00000000000000/* * Copyright (c) 2019 Balabit * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #include "pdb-lookup-params.h" static void _set_program_template(PDBLookupParams *lookup, LogTemplate *program_template) { if (program_template) { lookup->program_handle = LM_V_NONE; lookup->program_template = program_template; } else { lookup->program_handle = LM_V_PROGRAM; } }; void pdb_lookup_params_init(PDBLookupParams *lookup, LogMessage *msg, LogTemplate *program_template) { lookup->msg = msg; lookup->message_handle = LM_V_MESSAGE; lookup->message_len = 0; _set_program_template(lookup, program_template); } syslog-ng-syslog-ng-4.4.0/modules/correlation/pdb-lookup-params.h000066400000000000000000000032431450431004300250540ustar00rootroot00000000000000/* * Copyright (c) 2002-2017 Balabit * Copyright (c) 1998-2017 Balázs Scheidler * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ #ifndef CORRELATION_PDB_LOOKUP_PARAMS_H_INCLUDED #define CORRELATION_PDB_LOOKUP_PARAMS_H_INCLUDED #include