From 70b19290cea62034ca89b6bab2faafab8b2885af Mon Sep 17 00:00:00 2001 From: liuxueli Date: Fri, 6 Dec 2019 13:17:09 +0800 Subject: [PATCH] create version --- CMakeLists.txt | 73 +++ autorevision.sh | 1268 +++++++++++++++++++++++++++++++++++++++++++ bin/fw_dns_plug.inf | 9 + cmake/Package.cmake | 41 ++ cmake/Version.cmake | 53 ++ src/CMakeLists.txt | 19 + src/fw_dns_plug.cpp | 500 +++++++++++++++++ src/fw_dns_plug.h | 15 + src/fw_dns_rule.cpp | 196 +++++++ src/fw_dns_rule.h | 36 ++ 10 files changed, 2210 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 autorevision.sh create mode 100644 bin/fw_dns_plug.inf create mode 100644 cmake/Package.cmake create mode 100644 cmake/Version.cmake create mode 100644 src/CMakeLists.txt create mode 100644 src/fw_dns_plug.cpp create mode 100644 src/fw_dns_plug.h create mode 100644 src/fw_dns_rule.cpp create mode 100644 src/fw_dns_rule.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f4962b7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required (VERSION 2.8) + +project(fw_dns_plug) + +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +include(Version) + +set(CMAKE_MACOSX_RPATH 0) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + +include_directories(${PROJECT_SOURCE_DIR}/inc/) +include_directories(/opt/MESA/include/) + +option(ENABLE_WARNING_ALL "Enable all optional warnings which are desirable for normal code" TRUE) +option(ENABLE_SANITIZE_ADDRESS "Enable AddressSanitizer" FALSE) +option(ENABLE_SANITIZE_THREAD "Enable ThreadSanitizer" FALSE) + +if(ENABLE_SANITIZE_ADDRESS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan") +elseif(ENABLE_SANITIZE_THREAD) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan") +endif() + +set(CMAKE_INSTALL_PREFIX /home/mesasoft/sapp_run) + +add_subdirectory (src) + +set(CONFLIST /plug/conflist.inf) +set(MASTER_INF "./plug/business/fw_dns_plug/fw_dns_plug.inf") +set(MAIN_CONF /tsgconf/main.conf) + +file(WRITE ${PROJECT_SOURCE_DIR}/install.sh "#!/bin/sh\r\n") +file(WRITE ${PROJECT_SOURCE_DIR}/uninstall.sh "#!/bin/sh\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "DST=\${RPM_INSTALL_PREFIX}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "DST=\${RPM_INSTALL_PREFIX}\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "mkdir -p \${DST}/plug/business/\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "mkdir -p \${DST}/plug/business/\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "touch \${DST}${CONFLIST}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "touch \${DST}${CONFLIST}\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "mkdir -p \${DST}/tsgconf/\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "mkdir -p \${DST}/tsgconf/\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "touch \${DST}${MAIN_CONF}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "touch \${DST}${MAIN_CONF}\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "if [[ -z `grep -rn 'fw_dns_plug.inf' \${DST}${CONFLIST}` ]];then\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "\tsed -i '/\\[business\\]/a\\${MASTER_INF}' \${DST}${CONFLIST}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "fi\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "sed -i '/fw_dns_plug.inf/d' \${DST}${CONFLIST}\r\n") + +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "if [[ -z `grep -rn '\\[DNS_PLUG\\]' \${DST}${MAIN_CONF}` ]];then\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "\tsed -i '1i\\\\[DNS_PLUG\\]' \${DST}${MAIN_CONF}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "\tsed -i '/\\[DNS_PLUG\\]/a\\LOG_LEVEL=30' \${DST}${MAIN_CONF}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "\tsed -i '/\\[DNS_PLUG\\]/a\\LOG_PATH=./tsglog/fw_dns_plug/fw_dns_plug' \${DST}${MAIN_CONF}\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/install.sh "fi\r\n") +file(APPEND ${PROJECT_SOURCE_DIR}/uninstall.sh "sed -i '/\\[DNS_PLUG\\]/,+2d' \${DST}${MAIN_CONF}\r\n") + +SET(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/install.sh") +SET(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/uninstall.sh") + +include(Package) diff --git a/autorevision.sh b/autorevision.sh new file mode 100644 index 0000000..3baa179 --- /dev/null +++ b/autorevision.sh @@ -0,0 +1,1268 @@ +#!/bin/sh + +# Copyright (c) 2012 - 2016 dak180 and contributors. See +# https://opensource.org/licenses/mit-license.php or the included +# COPYING.md for licence terms. +# +# autorevision - extracts metadata about the head version from your +# repository. + +# Usage message. +arUsage() { + cat > "/dev/stderr" << EOF +usage: autorevision {-t output-type | -s symbol} [-o cache-file [-f] ] [-V] + Options include: + -t output-type = specify output type + -s symbol = specify symbol output + -o cache-file = specify cache file location + -f = force the use of cache data + -U = check for untracked files in svn + -V = emit version and exit + -? = help message + +The following are valid output types: + clojure = clojure file + c = C/C++ file + h = Header for use with c/c++ + hpp = Alternate C++ header strings with namespace + ini = INI file + java = Java file + javaprop = Java properties file + js = javascript file + json = JSON file + lua = Lua file + m4 = m4 file + matlab = matlab file + octave = octave file + php = PHP file + pl = Perl file + py = Python file + rpm = rpm file + scheme = scheme file + sh = Bash sytax + swift = Swift file + tex = (La)TeX file + xcode = Header useful for populating info.plist files + cmake = CMake file + + +The following are valid symbols: + VCS_TYPE + VCS_BASENAME + VCS_UUID + VCS_NUM + VCS_DATE + VCS_BRANCH + VCS_TAG + VCS_TICK + VCS_EXTRA + VCS_FULL_HASH + VCS_SHORT_HASH + VCS_WC_MODIFIED + VCS_ACTION_STAMP +EOF + exit 1 +} + +# Config +ARVERSION="&&ARVERSION&&" +TARGETFILE="/dev/stdout" +while getopts ":t:o:s:VfU" OPTION; do + case "${OPTION}" in + t) + AFILETYPE="${OPTARG}" + ;; + o) + CACHEFILE="${OPTARG}" + ;; + f) + CACHEFORCE="1" + ;; + s) + VAROUT="${OPTARG}" + ;; + U) + UNTRACKEDFILES="1" + ;; + V) + echo "autorevision ${ARVERSION}" + exit 0 + ;; + ?) + # If an unknown flag is used (or -?): + arUsage + ;; + esac +done + +if [ ! -z "${VAROUT}" ] && [ ! -z "${AFILETYPE}" ]; then + # If both -s and -t are specified: + echo "error: Improper argument combination." 1>&2 + exit 1 +elif [ -z "${VAROUT}" ] && [ -z "${AFILETYPE}" ]; then + # If neither -s or -t are specified: + arUsage +elif [ -z "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then + # If -f is specified without -o: + arUsage +elif [ ! -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then + # If we are forced to use the cache but it does not exist. + echo "error: Cache forced but no cache found." 1>&2 + exit 1 +fi + +# Make sure that the path we are given is one we can source +# (dash, we are looking at you). +if [ ! -z "${CACHEFILE}" ] && ! echo "${CACHEFILE}" | grep -q '^\.*/'; then + CACHEFILE="./${CACHEFILE}" +fi + +GENERATED_HEADER="Generated by autorevision - do not hand-hack!" + +# Functions to extract data from different repo types. +# For git repos +# shellcheck disable=SC2039,SC2164,SC2155 +gitRepo() { + local oldPath="${PWD}" + + cd "$(git rev-parse --show-toplevel)" + + VCS_TYPE="git" + + VCS_BASENAME="$(basename "${PWD}")" + + VCS_UUID="$(git rev-list --max-parents=0 --date-order --reverse HEAD 2>/dev/null | sed -n 1p)" + if [ -z "${VCS_UUID}" ]; then + VCS_UUID="$(git rev-list --topo-order HEAD | tail -n 1)" + fi + + # Is the working copy clean? + test -z "$(git status --untracked-files=normal --porcelain)" + VCS_WC_MODIFIED="${?}" + + # Enumeration of changesets + VCS_NUM="$(git rev-list --count HEAD 2>/dev/null)" + if [ -z "${VCS_NUM}" ]; then + echo "warning: Counting the number of revisions may be slower due to an outdated git version less than 1.7.2.3. If something breaks, please update it." 1>&2 + VCS_NUM="$(git rev-list HEAD | wc -l)" + fi + + # This may be a git-svn remote. If so, report the Subversion revision. + if [ -z "$(git config svn-remote.svn.url 2>/dev/null)" ]; then + # The full revision hash + VCS_FULL_HASH="$(git rev-parse HEAD)" + + # The short hash + VCS_SHORT_HASH="$(echo "${VCS_FULL_HASH}" | cut -b 1-7)" + else + # The git-svn revision number + VCS_FULL_HASH="$(git svn find-rev HEAD)" + VCS_SHORT_HASH="${VCS_FULL_HASH}" + fi + + # Current branch + VCS_BRANCH="$(git rev-parse --symbolic-full-name --verify "$(git name-rev --name-only --no-undefined HEAD 2>/dev/null)" 2>/dev/null | sed -e 's:refs/heads/::' | sed -e 's:refs/::')" + + # Cache the description + local DESCRIPTION="$(git describe --long --tags 2>/dev/null)" + + # Current or last tag ancestor (empty if no tags) + VCS_TAG="$(echo "${DESCRIPTION}" | sed -e "s:-g${VCS_SHORT_HASH}\$::" -e 's:-[0-9]*$::')" + + # Distance to last tag or an alias of VCS_NUM if there is no tag + if [ ! -z "${DESCRIPTION}" ]; then + VCS_TICK="$(echo "${DESCRIPTION}" | sed -e "s:${VCS_TAG}-::" -e "s:-g${VCS_SHORT_HASH}::")" + else + VCS_TICK="${VCS_NUM}" + fi + + # Date of the current commit + VCS_DATE="$(TZ=UTC git show -s --date=iso-strict-local --pretty=format:%ad | sed -e 's|+00:00|Z|')" + if [ -z "${VCS_DATE}" ]; then + echo "warning: Action stamps require git version 2.7+." 1>&2 + VCS_DATE="$(git log -1 --pretty=format:%ci | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')" + local ASdis="1" + fi + + # Action Stamp + if [ -z "${ASdis}" ]; then + VCS_ACTION_STAMP="${VCS_DATE}!$(git show -s --pretty=format:%cE)" + else + VCS_ACTION_STAMP="" + fi + + cd "${oldPath}" +} + +# For hg repos +# shellcheck disable=SC2039,SC2164 +hgRepo() { + local oldPath="${PWD}" + + cd "$(hg root)" + + VCS_TYPE="hg" + + VCS_BASENAME="$(basename "${PWD}")" + + VCS_UUID="$(hg log -r "0" -l 1 --template '{node}\n')" + + # Is the working copy clean? + test -z "$(hg status -duram)" + VCS_WC_MODIFIED="${?}" + + # Enumeration of changesets + VCS_NUM="$(hg id -n | tr -d '+')" + + # The full revision hash + VCS_FULL_HASH="$(hg log -r "${VCS_NUM}" -l 1 --template '{node}\n')" + + # The short hash + VCS_SHORT_HASH="$(hg id -i | tr -d '+')" + + # Current bookmark (bookmarks are roughly equivalent to git's branches) + # or branch if no bookmark + VCS_BRANCH="$(hg id -B | cut -d ' ' -f 1)" + # Fall back to the branch if there are no bookmarks + if [ -z "${VCS_BRANCH}" ]; then + VCS_BRANCH="$(hg id -b)" + fi + + # Current or last tag ancestor (excluding auto tags, empty if no tags) + VCS_TAG="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttag}\n' 2>/dev/null | sed -e 's:qtip::' -e 's:tip::' -e 's:qbase::' -e 's:qparent::' -e "s:$(hg --config 'extensions.color=' --config 'extensions.mq=' --color never qtop 2>/dev/null)::" | cut -d ' ' -f 1)" + + # Distance to last tag or an alias of VCS_NUM if there is no tag + if [ ! -z "${VCS_TAG}" ]; then + VCS_TICK="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttagdistance}\n' 2>/dev/null)" + else + VCS_TICK="${VCS_NUM}" + fi + + # Date of the current commit + VCS_DATE="$(hg log -r "${VCS_NUM}" -l 1 --template '{date|isodatesec}\n' 2>/dev/null | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')" + + # Action Stamp + VCS_ACTION_STAMP="$(TZ=UTC hg log -r "${VCS_NUM}" -l 1 --template '{date|localdate|rfc3339date}\n' 2>/dev/null | sed -e 's|+00:00|Z|')!$(hg log -r "${VCS_NUM}" -l 1 --template '{author|email}\n' 2>/dev/null)" + + cd "${oldPath}" +} + +# For bzr repos +# shellcheck disable=SC2039,SC2164 +bzrRepo() { + local oldPath="${PWD}" + + cd "$(bzr root)" + + VCS_TYPE="bzr" + + VCS_BASENAME="$(basename "${PWD}")" + + # Currently unimplemented because more investigation is needed. + VCS_UUID="" + + # Is the working copy clean? + bzr version-info --custom --template='{clean}\n' | grep -q '1' + VCS_WC_MODIFIED="${?}" + + # Enumeration of changesets + VCS_NUM="$(bzr revno)" + + # The full revision hash + VCS_FULL_HASH="$(bzr version-info --custom --template='{revision_id}\n')" + + # The short hash + VCS_SHORT_HASH="${VCS_NUM}" + + # Nick of the current branch + VCS_BRANCH="$(bzr nick)" + + # Current or last tag ancestor (excluding auto tags, empty if no tags) + VCS_TAG="$(bzr tags --sort=time | sed '/?$/d' | tail -n1 | cut -d ' ' -f1)" + + # Distance to last tag or an alias of VCS_NUM if there is no tag + if [ ! -z "${VCS_TAG}" ]; then + VCS_TICK="$(bzr log --line -r "tag:${VCS_TAG}.." | tail -n +2 | wc -l | sed -e 's:^ *::')" + else + VCS_TICK="${VCS_NUM}" + fi + + # Date of the current commit + VCS_DATE="$(bzr version-info --custom --template='{date}\n' | sed -e 's: :T:' -e 's: ::')" + + # Action Stamp + # Currently unimplemented because more investigation is needed. + VCS_ACTION_STAMP="" + + cd "${oldPath}" +} + +# For svn repos +# shellcheck disable=SC2039,SC2164,SC2155 +svnRepo() { + local oldPath="${PWD}" + + VCS_TYPE="svn" + + case "${PWD}" in + /*trunk*|/*branches*|/*tags*) + local fn="${PWD}" + while [ "$(basename "${fn}")" != 'trunk' ] && [ "$(basename "${fn}")" != 'branches' ] && [ "$(basename "${fn}")" != 'tags' ] && [ "$(basename "${fn}")" != '/' ]; do + local fn="$(dirname "${fn}")" + done + local fn="$(dirname "${fn}")" + if [ "${fn}" = '/' ]; then + VCS_BASENAME="$(basename "${PWD}")" + else + VCS_BASENAME="$(basename "${fn}")" + fi + ;; + *) VCS_BASENAME="$(basename "${PWD}")" ;; + esac + + VCS_UUID="$(svn info --xml | sed -n -e 's:::' -e 's:::p')" + + # Cache svnversion output + local SVNVERSION="$(svnversion)" + + # Is the working copy clean? + echo "${SVNVERSION}" | grep -q "M" + case "${?}" in + 0) + VCS_WC_MODIFIED="1" + ;; + 1) + if [ ! -z "${UNTRACKEDFILES}" ]; then + # `svnversion` does not detect untracked files and `svn status` is really slow, so only run it if we really have to. + if [ -z "$(svn status)" ]; then + VCS_WC_MODIFIED="0" + else + VCS_WC_MODIFIED="1" + fi + else + VCS_WC_MODIFIED="0" + fi + ;; + esac + + # Enumeration of changesets + VCS_NUM="$(echo "${SVNVERSION}" | cut -d : -f 1 | sed -e 's:M::' -e 's:S::' -e 's:P::')" + + # The full revision hash + VCS_FULL_HASH="${SVNVERSION}" + + # The short hash + VCS_SHORT_HASH="${VCS_NUM}" + + # Current branch + case "${PWD}" in + /*trunk*|/*branches*|/*tags*) + local lastbase="" + local fn="${PWD}" + while : + do + base="$(basename "${fn}")" + if [ "${base}" = 'trunk' ]; then + VCS_BRANCH='trunk' + break + elif [ "${base}" = 'branches' ] || [ "${base}" = 'tags' ]; then + VCS_BRANCH="${lastbase}" + break + elif [ "${base}" = '/' ]; then + VCS_BRANCH="" + break + fi + local lastbase="${base}" + local fn="$(dirname "${fn}")" + done + ;; + *) VCS_BRANCH="" ;; + esac + + # Current or last tag ancestor (empty if no tags). But "current + # tag" can't be extracted reliably because Subversion doesn't + # have tags the way other VCSes do. + VCS_TAG="" + VCS_TICK="" + + # Date of the current commit + VCS_DATE="$(svn info --xml | sed -n -e 's:::' -e 's:::p')" + + # Action Stamp + VCS_ACTION_STAMP="${VCS_DATE}!$(svn log --xml -l 1 -r "${VCS_SHORT_HASH}" | sed -n -e 's:::' -e 's:::p')" + + cd "${oldPath}" +} + + +# Functions to output data in different formats. +# For bash output +shOutput() { + cat > "${TARGETFILE}" << EOF +# ${GENERATED_HEADER} + +VCS_TYPE="${VCS_TYPE}" +VCS_BASENAME="${VCS_BASENAME}" +VCS_UUID="${VCS_UUID}" +VCS_NUM="${VCS_NUM}" +VCS_DATE="${VCS_DATE}" +VCS_BRANCH="${VCS_BRANCH}" +VCS_TAG="${VCS_TAG}" +VCS_TICK="${VCS_TICK}" +VCS_EXTRA="${VCS_EXTRA}" + +VCS_ACTION_STAMP="${VCS_ACTION_STAMP}" +VCS_FULL_HASH="${VCS_FULL_HASH}" +VCS_SHORT_HASH="${VCS_SHORT_HASH}" + +VCS_WC_MODIFIED="${VCS_WC_MODIFIED}" + +# end +EOF +} + +# For source C output +cOutput() { + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ + +const char *VCS_TYPE = "${VCS_TYPE}"; +const char *VCS_BASENAME = "${VCS_BASENAME}"; +const char *VCS_UUID = "${VCS_UUID}"; +const int VCS_NUM = ${VCS_NUM}; +const char *VCS_DATE = "${VCS_DATE}"; +const char *VCS_BRANCH = "${VCS_BRANCH}"; +const char *VCS_TAG = "${VCS_TAG}"; +const int VCS_TICK = ${VCS_TICK}; +const char *VCS_EXTRA = "${VCS_EXTRA}"; + +const char *VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"; +const char *VCS_FULL_HASH = "${VCS_FULL_HASH}"; +const char *VCS_SHORT_HASH = "${VCS_SHORT_HASH}"; + +const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; + +/* end */ +EOF +} + +# For header output +hOutput() { + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ +#ifndef AUTOREVISION_H +#define AUTOREVISION_H + +#define VCS_TYPE "${VCS_TYPE}" +#define VCS_BASENAME "${VCS_BASENAME}" +#define VCS_UUID "${VCS_UUID}" +#define VCS_NUM ${VCS_NUM} +#define VCS_DATE "${VCS_DATE}" +#define VCS_BRANCH "${VCS_BRANCH}" +#define VCS_TAG "${VCS_TAG}" +#define VCS_TICK ${VCS_TICK} +#define VCS_EXTRA "${VCS_EXTRA}" + +#define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}" +#define VCS_FULL_HASH "${VCS_FULL_HASH}" +#define VCS_SHORT_HASH "${VCS_SHORT_HASH}" + +#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED} + +#endif + +/* end */ +EOF +} + +# A header output for use with xcode to populate info.plist strings +xcodeOutput() { + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ +#ifndef AUTOREVISION_H +#define AUTOREVISION_H + +#define VCS_TYPE ${VCS_TYPE} +#define VCS_BASENAME ${VCS_BASENAME} +#define VCS_UUID ${VCS_UUID} +#define VCS_NUM ${VCS_NUM} +#define VCS_DATE ${VCS_DATE} +#define VCS_BRANCH ${VCS_BRANCH} +#define VCS_TAG ${VCS_TAG} +#define VCS_TICK ${VCS_TICK} +#define VCS_EXTRA ${VCS_EXTRA} + +#define VCS_ACTION_STAMP ${VCS_ACTION_STAMP} +#define VCS_FULL_HASH ${VCS_FULL_HASH} +#define VCS_SHORT_HASH ${VCS_SHORT_HASH} + +#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED} + +#endif + +/* end */ +EOF +} + +# For Swift output +swiftOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + # For values that may not exist depending on the type of repo we + # have read from, set them to `nil` when they are empty. + if [ -z "${VCS_UUID}" ]; then + VCS_UUID="nil" + else + VCS_UUID="\"${VCS_UUID}\"" + fi + if [ -z "${VCS_TAG}" ]; then + VCS_TAG="nil" + else + VCS_TAG="\"${VCS_TAG}\"" + fi + : "${VCS_TICK:="nil"}" + if [ -z "${VCS_EXTRA}" ]; then + VCS_EXTRA="nil" + else + VCS_EXTRA="\"${VCS_EXTRA}\"" + fi + if [ -z "${VCS_ACTION_STAMP}" ]; then + VCS_ACTION_STAMP="nil" + else + VCS_ACTION_STAMP="\"${VCS_ACTION_STAMP}\"" + fi + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ + +let VCS_TYPE = "${VCS_TYPE}" +let VCS_BASENAME = "${VCS_BASENAME}" +let VCS_UUID: String? = ${VCS_UUID} +let VCS_NUM: Int = ${VCS_NUM} +let VCS_DATE = "${VCS_DATE}" +let VCS_BRANCH: String = "${VCS_BRANCH}" +let VCS_TAG: String? = ${VCS_TAG} +let VCS_TICK: Int? = ${VCS_TICK} +let VCS_EXTRA: String? = ${VCS_EXTRA} + +let VCS_ACTION_STAMP: String? = ${VCS_ACTION_STAMP} +let VCS_FULL_HASH: String = "${VCS_FULL_HASH}" +let VCS_SHORT_HASH: String = "${VCS_SHORT_HASH}" + +let VCS_WC_MODIFIED: Bool = ${VCS_WC_MODIFIED} + +/* end */ +EOF +} + +# For Python output +pyOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="False" ;; + 1) VCS_WC_MODIFIED="True" ;; + esac + cat > "${TARGETFILE}" << EOF +# ${GENERATED_HEADER} + +VCS_TYPE = "${VCS_TYPE}" +VCS_BASENAME = "${VCS_BASENAME}" +VCS_UUID = "${VCS_UUID}" +VCS_NUM = ${VCS_NUM} +VCS_DATE = "${VCS_DATE}" +VCS_BRANCH = "${VCS_BRANCH}" +VCS_TAG = "${VCS_TAG}" +VCS_TICK = ${VCS_TICK} +VCS_EXTRA = "${VCS_EXTRA}" + +VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}" +VCS_FULL_HASH = "${VCS_FULL_HASH}" +VCS_SHORT_HASH = "${VCS_SHORT_HASH}" + +VCS_WC_MODIFIED = ${VCS_WC_MODIFIED} + +# end +EOF +} + +# For Perl output +plOutput() { + cat << EOF +# ${GENERATED_HEADER} + +\$VCS_TYPE = '${VCS_TYPE}'; +\$VCS_BASENAME = '${VCS_BASENAME}'; +\$VCS_UUID = '${VCS_UUID}'; +\$VCS_NUM = ${VCS_NUM}; +\$VCS_DATE = '${VCS_DATE}'; +\$VCS_BRANCH = '${VCS_BRANCH}'; +\$VCS_TAG = '${VCS_TAG}'; +\$VCS_TICK = ${VCS_TICK}; +\$VCS_EXTRA = '${VCS_EXTRA}'; + +\$VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}'; +\$VCS_FULL_HASH = '${VCS_FULL_HASH}'; +\$VCS_SHORT_HASH = '${VCS_SHORT_HASH}'; + +\$VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; + +# end +1; +EOF +} + +# For lua output +luaOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + cat > "${TARGETFILE}" << EOF +-- ${GENERATED_HEADER} + +VCS_TYPE = "${VCS_TYPE}" +VCS_BASENAME = "${VCS_BASENAME}" +VCS_UUID = "${VCS_UUID}" +VCS_NUM = ${VCS_NUM} +VCS_DATE = "${VCS_DATE}" +VCS_BRANCH = "${VCS_BRANCH}" +VCS_TAG = "${VCS_TAG}" +VCS_TICK = ${VCS_TICK} +VCS_EXTRA = "${VCS_EXTRA}" + +VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}" +VCS_FULL_HASH = "${VCS_FULL_HASH}" +VCS_SHORT_HASH = "${VCS_SHORT_HASH}" + +VCS_WC_MODIFIED = ${VCS_WC_MODIFIED} + +-- end +EOF +} + +# For php output +phpOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + cat > "${TARGETFILE}" << EOF + "${VCS_TYPE}", + "VCS_BASENAME" => "${VCS_BASENAME}", + "VCS_UUID" => "${VCS_UUID}", + "VCS_NUM" => ${VCS_NUM}, + "VCS_DATE" => "${VCS_DATE}", + "VCS_BRANCH" => "${VCS_BRANCH}", + "VCS_TAG" => "${VCS_TAG}", + "VCS_TICK" => ${VCS_TICK}, + "VCS_EXTRA" => "${VCS_EXTRA}", + "VCS_ACTION_STAMP" => "${VCS_ACTION_STAMP}", + "VCS_FULL_HASH" => "${VCS_FULL_HASH}", + "VCS_SHORT_HASH" => "${VCS_SHORT_HASH}", + "VCS_WC_MODIFIED" => ${VCS_WC_MODIFIED} +); + +# end +?> +EOF +} + +# For ini output +iniOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + cat > "${TARGETFILE}" << EOF +; ${GENERATED_HEADER} +[VCS] +VCS_TYPE = "${VCS_TYPE}" +VCS_BASENAME = "${VCS_BASENAME}" +VCS_UUID = "${VCS_UUID}" +VCS_NUM = ${VCS_NUM} +VCS_DATE = "${VCS_DATE}" +VCS_BRANCH = "${VCS_BRANCH}" +VCS_TAG = "${VCS_TAG}" +VCS_TICK = ${VCS_TICK} +VCS_EXTRA = "${VCS_EXTRA}" +VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}" +VCS_FULL_HASH = "${VCS_FULL_HASH}" +VCS_SHORT_HASH = "${VCS_SHORT_HASH}" +VCS_WC_MODIFIED = ${VCS_WC_MODIFIED} +; end +EOF +} + +# For javascript output +jsOutput() { + case "${VCS_WC_MODIFIED}" in + 1) VCS_WC_MODIFIED="true" ;; + 0) VCS_WC_MODIFIED="false" ;; + esac + cat > "${TARGETFILE}" << EOF +/** ${GENERATED_HEADER} */ + +var autorevision = { + VCS_TYPE: "${VCS_TYPE}", + VCS_BASENAME: "${VCS_BASENAME}", + VCS_UUID: "${VCS_UUID}", + VCS_NUM: ${VCS_NUM}, + VCS_DATE: "${VCS_DATE}", + VCS_BRANCH: "${VCS_BRANCH}", + VCS_TAG: "${VCS_TAG}", + VCS_TICK: ${VCS_TICK}, + VCS_EXTRA: "${VCS_EXTRA}", + + VCS_ACTION_STAMP: "${VCS_ACTION_STAMP}", + VCS_FULL_HASH: "${VCS_FULL_HASH}", + VCS_SHORT_HASH: "${VCS_SHORT_HASH}", + + VCS_WC_MODIFIED: ${VCS_WC_MODIFIED} +}; + +/** Node.js compatibility */ +if (typeof module !== 'undefined') { + module.exports = autorevision; +} + +/** end */ +EOF +} + +# For JSON output +jsonOutput() { + case "${VCS_WC_MODIFIED}" in + 1) VCS_WC_MODIFIED="true" ;; + 0) VCS_WC_MODIFIED="false" ;; + esac + cat > "${TARGETFILE}" << EOF +{ + "_comment": "${GENERATED_HEADER}", + "VCS_TYPE": "${VCS_TYPE}", + "VCS_BASENAME": "${VCS_BASENAME}", + "VCS_UUID": "${VCS_UUID}", + "VCS_NUM": ${VCS_NUM}, + "VCS_DATE": "${VCS_DATE}", + "VCS_BRANCH":"${VCS_BRANCH}", + "VCS_TAG": "${VCS_TAG}", + "VCS_TICK": ${VCS_TICK}, + "VCS_EXTRA": "${VCS_EXTRA}", + + "VCS_ACTION_STAMP": "${VCS_ACTION_STAMP}", + "VCS_FULL_HASH": "${VCS_FULL_HASH}", + "VCS_SHORT_HASH": "${VCS_SHORT_HASH}", + + "VCS_WC_MODIFIED": ${VCS_WC_MODIFIED} +} +EOF +} + +# For Java output +javaOutput() { + case "${VCS_WC_MODIFIED}" in + 1) VCS_WC_MODIFIED="true" ;; + 0) VCS_WC_MODIFIED="false" ;; + esac + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ + +public class autorevision { + public static final String VCS_TYPE = "${VCS_TYPE}"; + public static final String VCS_BASENAME = "${VCS_BASENAME}"; + public static final String VCS_UUID = "${VCS_UUID}"; + public static final long VCS_NUM = ${VCS_NUM}; + public static final String VCS_DATE = "${VCS_DATE}"; + public static final String VCS_BRANCH = "${VCS_BRANCH}"; + public static final String VCS_TAG = "${VCS_TAG}"; + public static final long VCS_TICK = ${VCS_TICK}; + public static final String VCS_EXTRA = "${VCS_EXTRA}"; + + public static final String VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"; + public static final String VCS_FULL_HASH = "${VCS_FULL_HASH}"; + public static final String VCS_SHORT_HASH = "${VCS_SHORT_HASH}"; + + public static final boolean VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; +} +EOF +} + +# For Java properties output +javapropOutput() { + case "${VCS_WC_MODIFIED}" in + 1) VCS_WC_MODIFIED="true" ;; + 0) VCS_WC_MODIFIED="false" ;; + esac + cat > "${TARGETFILE}" << EOF +# ${GENERATED_HEADER} + +VCS_TYPE=${VCS_TYPE} +VCS_BASENAME=${VCS_BASENAME} +VCS_UUID=${VCS_UUID} +VCS_NUM=${VCS_NUM} +VCS_DATE=${VCS_DATE} +VCS_BRANCH=${VCS_BRANCH} +VCS_TAG=${VCS_TAG} +VCS_TICK=${VCS_TICK} +VCS_EXTRA=${VCS_EXTRA} + +VCS_ACTION_STAMP=${VCS_ACTION_STAMP} +VCS_FULL_HASH=${VCS_FULL_HASH} +VCS_SHORT_HASH=${VCS_SHORT_HASH} + +VCS_WC_MODIFIED=${VCS_WC_MODIFIED} +EOF +} + +# For m4 output +m4Output() { + cat > "${TARGETFILE}" << EOF +dnl ${GENERATED_HEADER} +define(\`VCS_TYPE', \`${VCS_TYPE}')dnl +define(\`VCS_BASENAME', \`${VCS_BASENAME}')dnl +define(\`VCS_UUID', \`${VCS_UUID}')dnl +define(\`VCS_NUM', \`${VCS_NUM}')dnl +define(\`VCS_DATE', \`${VCS_DATE}')dnl +define(\`VCS_BRANCH', \`${VCS_BRANCH}')dnl +define(\`VCS_TAG', \`${VCS_TAG}')dnl +define(\`VCS_TICK', \`${VCS_TICK}')dnl +define(\`VCS_EXTRA', \`${VCS_EXTRA}')dnl +define(\`VCS_ACTIONSTAMP', \`${VCS_ACTION_STAMP}')dnl +define(\`VCS_FULLHASH', \`${VCS_FULL_HASH}')dnl +define(\`VCS_SHORTHASH', \`${VCS_SHORT_HASH}')dnl +define(\`VCS_WC_MODIFIED', \`${VCS_WC_MODIFIED}')dnl +EOF +} + +# For (La)TeX output +texOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + cat > "${TARGETFILE}" << EOF +% ${GENERATED_HEADER} +\def \vcsType {${VCS_TYPE}} +\def \vcsBasename {${VCS_BASENAME}} +\def \vcsUUID {${VCS_UUID}} +\def \vcsNum {${VCS_NUM}} +\def \vcsDate {${VCS_DATE}} +\def \vcsBranch {${VCS_BRANCH}} +\def \vcsTag {${VCS_TAG}} +\def \vcsTick {${VCS_TICK}} +\def \vcsExtra {${VCS_EXTRA}} +\def \vcsACTIONSTAMP {${VCS_ACTION_STAMP}} +\def \vcsFullHash {${VCS_FULL_HASH}} +\def \vcsShortHash {${VCS_SHORT_HASH}} +\def \vcsWCModified {${VCS_WC_MODIFIED}} +\endinput +EOF +} + +# For scheme output +schemeOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="#f" ;; + 1) VCS_WC_MODIFIED="#t" ;; + esac + cat > "${TARGETFILE}" << EOF +;; ${GENERATED_HEADER} +(define VCS_TYPE "${VCS_TYPE}") +(define VCS_BASENAME "${VCS_BASENAME}") +(define VCS_UUID "${VCS_UUID}") +(define VCS_NUM ${VCS_NUM}) +(define VCS_DATE "${VCS_DATE}") +(define VCS_BRANCH "${VCS_BRANCH}") +(define VCS_TAG "${VCS_TAG}") +(define VCS_TICK ${VCS_TICK}) +(define VCS_EXTRA "${VCS_EXTRA}") + +(define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}") +(define VCS_FULL_HASH "${VCS_FULL_HASH}") +(define VCS_SHORT_HASH "${VCS_SHORT_HASH}") + +(define VCS_WC_MODIFIED ${VCS_WC_MODIFIED}) +;; end +EOF +} + +# For clojure output +clojureOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="false" ;; + 1) VCS_WC_MODIFIED="true" ;; + esac + cat > "${TARGETFILE}" << EOF +;; ${GENERATED_HEADER} +(def VCS_TYPE "${VCS_TYPE}") +(def VCS_BASENAME "${VCS_BASENAME}") +(def VCS_UUID "${VCS_UUID}") +(def VCS_NUM ${VCS_NUM}) +(def VCS_DATE "${VCS_DATE}") +(def VCS_BRANCH "${VCS_BRANCH}") +(def VCS_TAG "${VCS_TAG}") +(def VCS_TICK ${VCS_TICK}) +(def VCS_EXTRA "${VCS_EXTRA}") + +(def VCS_ACTION_STAMP "${VCS_ACTION_STAMP}") +(def VCS_FULL_HASH "${VCS_FULL_HASH}") +(def VCS_SHORT_HASH "${VCS_SHORT_HASH}") + +(def VCS_WC_MODIFIED ${VCS_WC_MODIFIED}) +;; end +EOF +} + +# For rpm spec file output +rpmOutput() { + cat > "${TARGETFILE}" << EOF +# ${GENERATED_HEADER} +$([ "${VCS_TYPE}" ] && echo "%define vcs_type ${VCS_TYPE}") +$([ "${VCS_BASENAME}" ] && echo "%define vcs_basename ${VCS_BASENAME}") +$([ "${VCS_UUID}" ] && echo "%define vcs_uuid ${VCS_UUID}") +$([ "${VCS_NUM}" ] && echo "%define vcs_num ${VCS_NUM}") +$([ "${VCS_DATE}" ] && echo "%define vcs_date ${VCS_DATE}") +$([ "${VCS_BRANCH}" ] && echo "%define vcs_branch ${VCS_BRANCH}") +$([ "${VCS_TAG}" ] && echo "%define vcs_tag ${VCS_TAG}") +$([ "${VCS_TICK}" ] && echo "%define vcs_tick ${VCS_TICK}") +$([ "${VCS_EXTRA}" ] && echo "%define vcs_extra ${VCS_EXTRA}") + +$([ "${VCS_ACTION_STAMP}" ] && echo "%define vcs_action_stamp ${VCS_ACTION_STAMP}") +$([ "${VCS_FULL_HASH}" ] && echo "%define vcs_full_hash ${VCS_FULL_HASH}") +$([ "${VCS_SHORT_HASH}" ] && echo "%define vcs_short_hash ${VCS_SHORT_HASH}") + +$([ "${VCS_WC_MODIFIED}" ] && echo "%define vcs_wc_modified ${VCS_WC_MODIFIED}") +# end +EOF +} + +# shellcheck disable=SC2155,SC2039 +hppOutput() { + local NAMESPACE="$(echo "${VCS_BASENAME}" | sed -e 's:_::g' | tr '[:lower:]' '[:upper:]')" + cat > "${TARGETFILE}" << EOF +/* ${GENERATED_HEADER} */ + +#ifndef ${NAMESPACE}_AUTOREVISION_H +#define ${NAMESPACE}_AUTOREVISION_H + +#include + +namespace $(echo "${NAMESPACE}" | tr '[:upper:]' '[:lower:]') +{ + const std::string VCS_TYPE = "${VCS_TYPE}"; + const std::string VCS_BASENAME = "${VCS_BASENAME}"; + const std::string VCS_UUID = "${VCS_UUID}"; + const int VCS_NUM = ${VCS_NUM}; + const std::string VCS_DATE = "${VCS_DATE}"; + const std::string VCS_BRANCH = "${VCS_BRANCH}"; + const std::string VCS_TAG = "${VCS_TAG}"; + const int VCS_TICK = ${VCS_TICK}; + const std::string VCS_EXTRA = "${VCS_EXTRA}"; + + const std::string VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"; + const std::string VCS_FULL_HASH = "${VCS_FULL_HASH}"; + const std::string VCS_SHORT_HASH = "${VCS_SHORT_HASH}"; + + const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; +} + +#endif + +/* end */ +EOF +} + +matlabOutput() { + case "${VCS_WC_MODIFIED}" in + 0) VCS_WC_MODIFIED="FALSE" ;; + 1) VCS_WC_MODIFIED="TRUE" ;; + esac + cat > "${TARGETFILE}" << EOF +% ${GENERATED_HEADER} + +VCS_TYPE = '${VCS_TYPE}'; +VCS_BASENAME = '${VCS_BASENAME}'; +VCS_UUID = '${VCS_UUID}'; +VCS_NUM = ${VCS_NUM}; +VCS_DATE = '${VCS_DATE}'; +VCS_BRANCH = '${VCS_BRANCH}'; +VCS_TAG = '${VCS_TAG}'; +VCS_TICK = ${VCS_TICK}; +VCS_EXTRA = '${VCS_EXTRA}'; + +VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}'; +VCS_FULL_HASH = '${VCS_FULL_HASH}'; +VCS_SHORT_HASH = '${VCS_SHORT_HASH}'; + +VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; + +% end +EOF +} + +octaveOutput() { + cat > "${TARGETFILE}" << EOF +% ${GENERATED_HEADER} + +VCS_TYPE = '${VCS_TYPE}'; +VCS_BASENAME = '${VCS_BASENAME}'; +VCS_UUID = '${VCS_UUID}'; +VCS_NUM = ${VCS_NUM}; +VCS_DATE = '${VCS_DATE}'; +VCS_BRANCH = '${VCS_BRANCH}'; +VCS_TAG = '${VCS_TAG}'; +VCS_TICK = ${VCS_TICK}; +VCS_EXTRA = '${VCS_EXTRA}'; + +VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}'; +VCS_FULL_HASH = '${VCS_FULL_HASH}'; +VCS_SHORT_HASH = '${VCS_SHORT_HASH}'; + +VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}; + +% end +EOF +} + +cmakeOutput() { + cat > "${TARGETFILE}" << EOF +# ${GENERATED_HEADER} + +set(VCS_TYPE ${VCS_TYPE}) +set(VCS_BASENAME ${VCS_BASENAME}) +set(VCS_UUID ${VCS_UUID}) +set(VCS_NUM ${VCS_NUM}) +set(VCS_DATE ${VCS_DATE}) +set(VCS_BRANCH ${VCS_BRANCH}) +set(VCS_TAG ${VCS_TAG}) +set(VCS_TICK ${VCS_TICK}) +set(VCS_EXTRA ${VCS_EXTRA}) + +set(VCS_ACTION_STAMP ${VCS_ACTION_STAMP}) +set(VCS_FULL_HASH ${VCS_FULL_HASH}) +set(VCS_SHORT_HASH ${VCS_SHORT_HASH}) + +set(VCS_WC_MODIFIED ${VCS_WC_MODIFIED}) + +# end +EOF +} + + +# Helper functions +# Count path segments +# shellcheck disable=SC2039 +pathSegment() { + local pathz="${1}" + local depth="0" + + if [ ! -z "${pathz}" ]; then + # Continue until we are at / or there are no path separators left. + while [ ! "${pathz}" = "/" ] && [ ! "${pathz}" = "$(echo "${pathz}" | sed -e 's:/::')" ]; do + pathz="$(dirname "${pathz}")" + depth="$((depth+1))" + done + fi + echo "${depth}" +} + +# Largest of four numbers +# shellcheck disable=SC2039 +multiCompare() { + local larger="${1}" + local numA="${2}" + local numB="${3}" + local numC="${4}" + + [ "${numA}" -gt "${larger}" ] && larger="${numA}" + [ "${numB}" -gt "${larger}" ] && larger="${numB}" + [ "${numC}" -gt "${larger}" ] && larger="${numC}" + echo "${larger}" +} + +# Test for repositories +# shellcheck disable=SC2155,SC2039 +repoTest() { + REPONUM="0" + if [ ! -z "$(git rev-parse HEAD 2>/dev/null)" ]; then + local gitPath="$(git rev-parse --show-toplevel)" + local gitDepth="$(pathSegment "${gitPath}")" + REPONUM="$((REPONUM+1))" + else + local gitDepth="0" + fi + if [ ! -z "$(hg root 2>/dev/null)" ]; then + local hgPath="$(hg root 2>/dev/null)" + local hgDepth="$(pathSegment "${hgPath}")" + REPONUM="$((REPONUM+1))" + else + local hgDepth="0" + fi + if [ ! -z "$(bzr root 2>/dev/null)" ]; then + local bzrPath="$(bzr root 2>/dev/null)" + local bzrDepth="$(pathSegment "${bzrPath}")" + REPONUM="$((REPONUM+1))" + else + local bzrDepth="0" + fi + if [ ! -z "$(svn info 2>/dev/null)" ]; then + local stringz="" + local stringx="" + local svnPath="$(svn info --xml | sed -n -e "s:${stringz}::" -e "s:${stringx}::p")" + # An old enough svn will not be able give us a path; default + # to 1 for that case. + if [ -z "${svnPath}" ]; then + local svnDepth="1" + else + local svnDepth="$(pathSegment "${svnPath}")" + fi + REPONUM="$((REPONUM+1))" + else + local svnDepth="0" + fi + + # Do not do more work then we have to. + if [ "${REPONUM}" = "0" ]; then + return + fi + + # Figure out which repo is the deepest and use it. + local wonRepo="$(multiCompare "${gitDepth}" "${hgDepth}" "${bzrDepth}" "${svnDepth}")" + if [ "${wonRepo}" = "${gitDepth}" ]; then + gitRepo + elif [ "${wonRepo}" = "${hgDepth}" ]; then + hgRepo + elif [ "${wonRepo}" = "${bzrDepth}" ]; then + bzrRepo + elif [ "${wonRepo}" = "${svnDepth}" ]; then + svnRepo + fi +} + + + +# Detect which repos we are in and gather data. +# shellcheck source=/dev/null +if [ -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then + # When requested only read from the cache to populate our symbols. + . "${CACHEFILE}" +else + # If a value is not set through the environment set VCS_EXTRA to nothing. + : "${VCS_EXTRA:=""}" + repoTest + + if [ -f "${CACHEFILE}" ] && [ "${REPONUM}" = "0" ]; then + # We are not in a repo; try to use a previously generated cache to populate our symbols. + . "${CACHEFILE}" + # Do not overwrite the cache if we know we are not going to write anything new. + CACHEFORCE="1" + elif [ "${REPONUM}" = "0" ]; then + echo "error: No repo or cache detected." 1>&2 + exit 1 + fi +fi + + +# -s output is handled here. +if [ ! -z "${VAROUT}" ]; then + if [ "${VAROUT}" = "VCS_TYPE" ]; then + echo "${VCS_TYPE}" + elif [ "${VAROUT}" = "VCS_BASENAME" ]; then + echo "${VCS_BASENAME}" + elif [ "${VAROUT}" = "VCS_NUM" ]; then + echo "${VCS_NUM}" + elif [ "${VAROUT}" = "VCS_DATE" ]; then + echo "${VCS_DATE}" + elif [ "${VAROUT}" = "VCS_BRANCH" ]; then + echo "${VCS_BRANCH}" + elif [ "${VAROUT}" = "VCS_TAG" ]; then + echo "${VCS_TAG}" + elif [ "${VAROUT}" = "VCS_TICK" ]; then + echo "${VCS_TICK}" + elif [ "${VAROUT}" = "VCS_FULL_HASH" ]; then + echo "${VCS_FULL_HASH}" + elif [ "${VAROUT}" = "VCS_SHORT_HASH" ]; then + echo "${VCS_SHORT_HASH}" + elif [ "${VAROUT}" = "VCS_WC_MODIFIED" ]; then + echo "${VCS_WC_MODIFIED}" + elif [ "${VAROUT}" = "VCS_ACTION_STAMP" ]; then + echo "${VCS_ACTION_STAMP}" + else + echo "error: Not a valid output symbol." 1>&2 + exit 1 + fi +fi + + +# Detect requested output type and use it. +if [ ! -z "${AFILETYPE}" ]; then + if [ "${AFILETYPE}" = "c" ]; then + cOutput + elif [ "${AFILETYPE}" = "h" ]; then + hOutput + elif [ "${AFILETYPE}" = "xcode" ]; then + xcodeOutput + elif [ "${AFILETYPE}" = "swift" ]; then + swiftOutput + elif [ "${AFILETYPE}" = "sh" ]; then + shOutput + elif [ "${AFILETYPE}" = "py" ] || [ "${AFILETYPE}" = "python" ]; then + pyOutput + elif [ "${AFILETYPE}" = "pl" ] || [ "${AFILETYPE}" = "perl" ]; then + plOutput + elif [ "${AFILETYPE}" = "lua" ]; then + luaOutput + elif [ "${AFILETYPE}" = "php" ]; then + phpOutput + elif [ "${AFILETYPE}" = "ini" ]; then + iniOutput + elif [ "${AFILETYPE}" = "js" ]; then + jsOutput + elif [ "${AFILETYPE}" = "json" ]; then + jsonOutput + elif [ "${AFILETYPE}" = "java" ]; then + javaOutput + elif [ "${AFILETYPE}" = "javaprop" ]; then + javapropOutput + elif [ "${AFILETYPE}" = "tex" ]; then + texOutput + elif [ "${AFILETYPE}" = "m4" ]; then + m4Output + elif [ "${AFILETYPE}" = "scheme" ]; then + schemeOutput + elif [ "${AFILETYPE}" = "clojure" ]; then + clojureOutput + elif [ "${AFILETYPE}" = "rpm" ]; then + rpmOutput + elif [ "${AFILETYPE}" = "hpp" ]; then + hppOutput + elif [ "${AFILETYPE}" = "matlab" ]; then + matlabOutput + elif [ "${AFILETYPE}" = "octave" ]; then + octaveOutput + elif [ "${AFILETYPE}" = "cmake" ]; then + cmakeOutput + else + echo "error: Not a valid output type." 1>&2 + exit 1 + fi +fi + + +# If requested, make a cache file. +if [ ! -z "${CACHEFILE}" ] && [ ! "${CACHEFORCE}" = "1" ]; then + TARGETFILE="${CACHEFILE}.tmp" + shOutput + + # Check to see if there have been any actual changes. + if [ ! -f "${CACHEFILE}" ]; then + mv -f "${CACHEFILE}.tmp" "${CACHEFILE}" + elif cmp -s "${CACHEFILE}.tmp" "${CACHEFILE}"; then + rm -f "${CACHEFILE}.tmp" + else + mv -f "${CACHEFILE}.tmp" "${CACHEFILE}" + fi +fi diff --git a/bin/fw_dns_plug.inf b/bin/fw_dns_plug.inf new file mode 100644 index 0000000..922cb6d --- /dev/null +++ b/bin/fw_dns_plug.inf @@ -0,0 +1,9 @@ +[PLUGINFO] +PLUGNAME=FW_DNS_PLUG +SO_PATH=./plug/business/fw_dns_plug/fw_dns_plug.so +INIT_FUNC=FW_DNS_PLUG_INIT +DESTROY_FUNC=FW_DNS_PLUG_DESTORY + +[DNS] +FUNC_FLAG=DNS_ALL +FUNC_NAME=FW_DNS_PLUG_ENTRY diff --git a/cmake/Package.cmake b/cmake/Package.cmake new file mode 100644 index 0000000..69bc509 --- /dev/null +++ b/cmake/Package.cmake @@ -0,0 +1,41 @@ +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-debug") +else() + set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +endif() + +message(STATUS "Package: ${CPACK_PACKAGE_NAME}") + +set(CPACK_PACKAGE_VECDOR "MESA") +set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}.${VERSION_BUILD}") +set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) + +set(CPACK_COMPONENTS_ALL devel) +set(CPACK_RPM_PACKAGE_DEBUG 1) +set(CPACK_RPM_COMPONENT_INSTALL OFF) +set(CPACK_RPM_DEVEL_FILE_NAME "${PROJECT_NAME}-devel.rpm") +set(CPACK_RPM_DEVEL_DEBUGINFO_FILE_NAME "${PROJECT_NAME}-devel-debuginfo.rpm") + +# RPM Build +set(CPACK_GENERATOR "RPM") +set(CPACK_RPM_AUTO_GENERATED_FILE_NAME ON) +set(CPACK_RPM_FILE_NAME "RPM-DEFAULT") +set(CPACK_RPM_PACKAGE_VENDOR "MESA") +set(CPACK_RPM_PACKAGE_AUTOREQPROV "no") +set(CPACK_RPM_PACKAGE_RELEASE_DIST ON) +set(CPACK_RPM_DEBUGINFO_PACKAGE ON) + + +set(CPACK_BUILD_SOURCE_DIRS "${CMAKE_SOURCE_DIR}") + +# Must uninstall the debug package before install release package +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CPACK_RPM_PACKAGE_CONFLICTS "${PROJECT_NAME}-debug") +else() + set(CPACK_RPM_PACKAGE_CONFLICTS ${PROJECT_NAME}) + # set(CPACK_STRIP_FILES TRUE) +endif() + +include(CPack) diff --git a/cmake/Version.cmake b/cmake/Version.cmake new file mode 100644 index 0000000..752f20f --- /dev/null +++ b/cmake/Version.cmake @@ -0,0 +1,53 @@ + +# Using autorevision.sh to generate version information + +set(__SOURCE_AUTORESIVISION ${CMAKE_SOURCE_DIR}/autorevision.sh) +set(__AUTORESIVISION ${CMAKE_BINARY_DIR}/autorevision.sh) +set(__VERSION_CACHE ${CMAKE_SOURCE_DIR}/version.txt) +set(__VERSION_CONFIG ${CMAKE_BINARY_DIR}/version.cmake) + +file(COPY ${__SOURCE_AUTORESIVISION} DESTINATION ${CMAKE_BINARY_DIR} + FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + +# execute autorevision.sh to generate version information +execute_process(COMMAND ${__AUTORESIVISION} -t cmake -o ${__VERSION_CACHE} + OUTPUT_FILE ${__VERSION_CONFIG} ERROR_QUIET) +include(${__VERSION_CONFIG}) + +# extract major, minor, patch version from git tag +string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VCS_TAG}") +string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VCS_TAG}") +string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VCS_TAG}") + +if(NOT VERSION_MAJOR) + set(VERSION_MAJOR 1) +endif() + +if(NOT VERSION_MINOR) + set(VERSION_MINOR 0) +endif() + +if(NOT VERSION_PATCH) + set(VERSION_PATCH 0) +endif() + +set(VERSION "${VERSION_MAJOR}_${VERSION_MINOR}_${VERSION_PATCH}") +set(VERSION_BUILD "${VCS_SHORT_HASH}") + +# print information +message(STATUS "Version: ${VERSION}-${VERSION_BUILD}") + +if(NOT DEFINE_GIT_VERSION) + option(DEFINE_GIT_VERSION "Set DEFINE_GIT_VERSION to OFF" OFF) + +set(GIT_VERSION + "${VERSION}-${CMAKE_BUILD_TYPE}-${VERSION_BUILD}-${VCS_BRANCH}-${VCS_TAG}-${VCS_DATE}") +string(REGEX REPLACE "[-:+/\\.]" "_" GIT_VERSION ${GIT_VERSION}) + +if(DEFINE_GIT_VERSION) + add_definitions(-DGIT_VERSION=${GIT_VERSION}) + option(DEFINE_GIT_VERSION "Set DEFINE_GIT_VERSION to OFF" ON) +endif() + +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..5304d76 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions(-fPIC) + +set(SRC fw_dns_plug.cpp fw_dns_rule.cpp) + +include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(/opt/MESA/include/) +include_directories(/opt/MESA/include/tsg/) + +set(FW_DNS_PLUG_DEPEND_DYN_LIB MESA_handle_logger MESA_prof_load maatframe pthread MESA_field_stat2) + +add_library(fw_dns_plug SHARED ${SRC}) +target_link_libraries(fw_dns_plug ${FW_DNS_PLUG_DEPEND_DYN_LIB}) +set_target_properties(fw_dns_plug PROPERTIES PREFIX "") + +install(TARGETS fw_dns_plug DESTINATION ${CMAKE_INSTALL_PREFIX}/plug/business/fw_dns_plug) +install(FILES ../bin/fw_dns_plug.inf DESTINATION ${CMAKE_INSTALL_PREFIX}/plug/business/fw_dns_plug) + diff --git a/src/fw_dns_plug.cpp b/src/fw_dns_plug.cpp new file mode 100644 index 0000000..34cb993 --- /dev/null +++ b/src/fw_dns_plug.cpp @@ -0,0 +1,500 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tsg_rule.h" +#include "tsg_send_log.h" +#include "fw_dns_plug.h" + + +char *g_fw_dns_conffile=(char *)"tsgconf/main.conf"; +char FW_DNS_PLUG_VERSION_20191206=0; +struct _fw_dns_plug g_fw_dns_plug_info; + +enum TSG_ETHOD_TYPE +{ + TSG_METHOD_TYPE_UNKNOWN=0, + TSG_METHOD_TYPE_DROP, + TSG_METHOD_TYPE_REDIRECTION, + TSG_METHOD_TYPE_MAX +}; + +const struct _str2index method2index[TSG_METHOD_TYPE_MAX]={ {TSG_METHOD_TYPE_UNKNOWN, 7, (char *)"unknown"}, + {TSG_METHOD_TYPE_DROP, 4, (char *)"drop"}, + {TSG_METHOD_TYPE_REDIRECTION, 8, (char *)"redirect"} + }; + +int tsg_get_method_id(char *method) +{ + int i=0; + + for(i=0; ivalueint; + + item=cJSON_GetObjectItem(object, "max"); + max=item->valueint; + + return (rand()%(max-min+1)+min); +} + +static cJSON * get_answer_records(cJSON *object, int qtype) +{ + int i=0; + cJSON *item=NULL; + int resolution_size=0; + int answer_type=DNS_TYPE_UNKNOWN; + + cJSON *resolution_array=cJSON_GetObjectItem(object, "resolution"); + resolution_size=cJSON_GetArraySize(resolution_array); + for(i=0; ivaluestring); + if(answer_type==qtype) + { + return cJSON_GetObjectItem(item, "answer"); + } + } + + return NULL; +} + +static char fw_dns_action(struct streaminfo *a_stream, dns_info_t *dns_info, Maat_rule_t *p_result, const void *a_packet) +{ + int record_id=0; + int i=0,used_num=0; + int answer_size=0,ret=0; + int payload_len=0,ttl=0; + dns_hdr_t *dns_hdr = NULL; + cJSON *item=NULL; + cJSON *a_item=NULL; + cJSON *object=NULL; + cJSON *answer_array=NULL; + char *tmp_buff=NULL; + unsigned char senddir=0; + char state=PROT_STATE_GIVEME; + int answer_type=DNS_TYPE_UNKNOWN; + int method_type=TSG_METHOD_TYPE_UNKNOWN; + cheat_pkt_opt_t cheat_opt[MAX_ANSWER_RECORDS_NUM]; + unsigned char cheat_pkt_payload[MAX_CHEAT_PKT_PAYLOAD_LEN]; + + if(p_result->serv_def_len<128) + { + object=cJSON_Parse(p_result->service_defined); + + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "DO_ACTION", + "Hit policy_id: %d service: %d action: %d user_reagion: %s domain: %s qtype: %d addr: %s", + p_result->config_id, + p_result->service_id, + p_result->action, + p_result->service_defined, + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + printaddr(&a_stream->addr, a_stream->threadnum) + ); + } + else + { + tmp_buff=(char *)calloc(1, p_result->serv_def_len+1); + Maat_read_rule(g_tsg_maat_feather, p_result, MAAT_RULE_SERV_DEFINE, tmp_buff, p_result->serv_def_len); + object=cJSON_Parse(tmp_buff); + + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "DO_ACTION", + "Hit policy_id: %d service: %d action: %d user_reagion: %s domain: %s qtype: %d addr: %s", + p_result->config_id, + p_result->service_id, + p_result->action, + tmp_buff, + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + printaddr(&a_stream->addr, a_stream->threadnum) + ); + } + + if(object==NULL) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_FATAL, + "DO_ACTION", + "Hit policy_id: %d service: %d action: %d user_reagion: %s domain: %s qtype: %d addr: %s", + p_result->config_id, + p_result->service_id, + p_result->action, + (tmp_buff==NULL) ? p_result->service_defined : tmp_buff, + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + printaddr(&a_stream->addr, a_stream->threadnum) + ); + + if(tmp_buff!=NULL) + { + free(tmp_buff); + tmp_buff=NULL; + } + + return PROT_STATE_GIVEME; + } + + item=cJSON_GetObjectItem(object, "method"); + if(item!=NULL) + { + method_type=tsg_get_method_id(item->valuestring); + } + + switch(method_type) + { + case TSG_METHOD_TYPE_DROP: + state=PROT_STATE_DROPME|PROT_STATE_DROPPKT; + break; + case TSG_METHOD_TYPE_REDIRECTION: + answer_array=get_answer_records(object, dns_info->query_question.qtype); + if(answer_array!=NULL) + { + memset(cheat_opt, 0, sizeof(cheat_opt)); + answer_size=cJSON_GetArraySize(answer_array); + for(i=0; ivaluestring); + + a_item=cJSON_GetObjectItem(item, "ttl"); + ttl=get_answer_ttl(a_item); + + a_item=cJSON_GetObjectItem(item, "value"); + if(a_item!=NULL) + { + cheat_opt[used_num].res_type=answer_type; + cheat_opt[used_num].cfg_type=answer_type; + cheat_opt[used_num].ttl=ttl; + + switch(answer_type) + { + case DNS_TYPE_A: + cheat_opt[used_num].res_len=sizeof(unsigned int); + inet_pton(AF_INET, a_item->valuestring, (void *)cheat_opt[used_num].res_info); + break; + case DNS_TYPE_AAAA: + cheat_opt[used_num].res_len=IPV6_ADDR_LEN; + inet_pton(AF_INET6, a_item->valuestring, (void *)cheat_opt[used_num].res_info); + break; + default: + cheat_opt[used_num].res_len=(strlen(a_item->valuestring) > sizeof(cheat_opt[used_num].res_info)-1) ? sizeof(cheat_opt[used_num].res_info)-1 : strlen(a_item->valuestring); + memcpy(cheat_opt[used_num].res_info, a_item->valuestring, cheat_opt[used_num].res_len); + break; + } + used_num++; + } + else + { + a_item=cJSON_GetObjectItem(object, "record_id"); + record_id=a_item->valueint; + + a_item=cJSON_GetObjectItem(object, "selected_num"); + used_num+=get_cheat_opt(record_id, a_item->valueint, ttl, answer_type, cheat_opt+used_num, MAX_ANSWER_RECORDS_NUM-used_num); + } + + } + + memset(cheat_pkt_payload, 0, MAX_CHEAT_PKT_PAYLOAD_LEN); + + dns_hdr = (dns_hdr_t *)cheat_pkt_payload; + dns_hdr->id = dns_info->hdr_info.id; + dns_hdr->qdcount = 1; + dns_hdr->ancount = used_num; + + payload_len=build_cheat_pkt(cheat_pkt_payload, MAX_CHEAT_PKT_PAYLOAD_LEN, &dns_info->query_question, cheat_opt, used_num); + if(payload_len==-1) + { + return -1; + } + + senddir = MESA_dir_reverse(a_stream->routedir); + ret=MESA_inject_pkt(a_stream, (const char *)cheat_pkt_payload, payload_len, (const char *)a_packet, senddir); + if(ret<0) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_FATAL, + "SEND_CHEAT_PKT", + "Return of MESA_inject_pkt_feedback function is %d, qname: %s qtype: %d cfg_id: %d service: %d addr: %s", + ret, + dns_info->query_question.qname, + dns_info->query_question.qtype, + p_result->config_id, + p_result->service_id, + printaddr(&a_stream->addr, a_stream->threadnum) + ); + } + + state=PROT_STATE_DROPME|PROT_STATE_DROPPKT; + } + else + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_FATAL, + "DO_ACTION", + "Hit policy_id: %d service: %d action: %d user_reagion: %s domain: %s qtype: %d addr: %s", + p_result->config_id, + p_result->service_id, + p_result->action, + (tmp_buff==NULL) ? p_result->service_defined : tmp_buff, + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + printaddr(&a_stream->addr, a_stream->threadnum) + ); + state=PROT_STATE_GIVEME; + } + break; + default: + break; + } + + cJSON_Delete(object); + object=NULL; + return state; +} + +static int fw_dns_send_log(struct streaminfo *a_stream, dns_info_t *dns_info, struct Maat_rule_t *result, int result_num, int thread_seq) +{ + int i=0; + dns_rr_t *rr=NULL; + tsg_log_t log_msg; + int cname_use_len=0,dns_sec=1; + struct TLD_handle_t *handle=NULL; + char cname[4096]={0},*rr_buf=NULL; + int cname_size=sizeof(cname); + + handle=TLD_create(thread_seq); + + TLD_append(handle, (char *)"dns_qr", (void *)(long)dns_info->hdr_info.qr, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_aa", (void *)(long)dns_info->hdr_info.aa, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_message_id", (void *)(long)dns_info->hdr_info.id, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_opcode", (void *)(long)dns_info->hdr_info.opcode, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_ra", (void *)(long)dns_info->hdr_info.ra, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_rcode", (void *)(long)dns_info->hdr_info.rcode, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_rd", (void *)(long)dns_info->hdr_info.rd, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_tc", (void *)(long)dns_info->hdr_info.tc, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_qdcount", (void *)(long)dns_info->hdr_info.qdcount, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_ancount", (void *)(long)dns_info->hdr_info.ancount, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_nscount", (void *)(long)dns_info->hdr_info.aucount, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_arcount", (void *)(long)dns_info->hdr_info.adcount, TLD_TYPE_LONG); + + if((strlen((char *)dns_info->query_question.qname)) >0) + { + TLD_append(handle, (char *)"dns_qname", (void *)dns_info->query_question.qname, TLD_TYPE_STRING); + TLD_append(handle, (char *)"dns_qtype", (void *)(long)dns_info->query_question.qtype, TLD_TYPE_LONG); + TLD_append(handle, (char *)"dns_qclass", (void *)(long)dns_info->query_question.qclass, TLD_TYPE_LONG); + } + + for(i=0; irr_count && dns_info->rr != NULL; i++) + { + rr = &dns_info->rr[i]; + if(rr!=NULL && rr->type==DNS_TYPE_CNAME) + { + if(rr->rdata.cname != NULL && cname_size-cname_use_len > (int)strlen((const char *)rr->rdata.cname)) + { + snprintf(cname+cname_use_len, cname_size-cname_use_len, "%s,", rr->rdata.cname); + cname_use_len += strlen((const char *)rr->rdata.cname); + } + } + } + + TLD_append(handle, (char *)"dns_cname", (void *)cname, TLD_TYPE_STRING); + + cJSON * object=cJSON_CreateObject(); + get_rr_str2json(object, dns_info, &dns_sec); + rr_buf=cJSON_PrintUnformatted(object); + TLD_append(handle, (char *)"dns_rr", (void *)rr_buf, TLD_TYPE_STRING); + free(rr_buf); + rr_buf=NULL; + + TLD_append(handle, (char *)"dns_sub", (void *)(long)dns_sec, TLD_TYPE_LONG); + + TLD_append(handle, (char *)"common_schema_type", (void *)"DNS", TLD_TYPE_STRING); + + log_msg.a_stream=a_stream; + log_msg.result=result; + log_msg.result_num=result_num; + + tsg_send_log(g_tsg_log_instance, handle, &log_msg, thread_seq); + + return 0; +} + +extern "C" char FW_DNS_PLUG_ENTRY(stSessionInfo* session_info, void **pme, int thread_seq,struct streaminfo *a_stream,const void *a_packet) +{ + int ret=0,hit_num=0; + scan_status_t mid=NULL; + char state=PROT_STATE_GIVEME; + struct Maat_rule_t result[MAX_RESULT_NUM], *p_result=NULL; + dns_info_t *dns_info=(dns_info_t *)session_info->app_info; + + if(dns_info==NULL || strlen((char *)dns_info->query_question.qname)==0) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_FATAL, + "DNS_PLUG", + "Qname is %s, addr: %s", + (dns_info==NULL) ? "NULL" : ((strlen((char *)dns_info->query_question.qname)==0) ? "NULL" : (char *)dns_info->query_question.qname), + printaddr(&a_stream->addr, thread_seq) + ); + return state; + } + + ret=tsg_scan_nesting_addr(g_tsg_maat_feather, a_stream, PROTO_DNS, &mid, result, MAX_RESULT_NUM-hit_num); + if(ret>0) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "SCAN_NEST_ADDR", + "Hit policy_id: %d service: %d action: %d domain: %s qtype: %d addr: %s", + result[hit_num].config_id, + result[hit_num].service_id, + result[hit_num].action, + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + printaddr(&a_stream->addr, thread_seq) + ); + hit_num+=ret; + } + else + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "SCAN_NEST_ADDR", + "Scan domain: %s qtype: %d ret: %d addr: %s", + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + ret, + printaddr(&a_stream->addr, thread_seq) + ); + + } + + ret=Maat_full_scan_string(g_tsg_maat_feather, + g_fw_dns_plug_info.table_qname_id, + CHARSET_UTF8, + (char *)dns_info->query_question.qname, + strlen((char *)dns_info->query_question.qname), + result+hit_num, + NULL, + MAX_RESULT_NUM-hit_num, + &mid, + thread_seq); + + if(ret>0) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "SCAN_DOMAIN", + "Hit domain: %s qtype: %d policy_id: %d service: %d action: %d addr: %s", + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + result[hit_num].config_id, + result[hit_num].service_id, + result[hit_num].action, + printaddr(&a_stream->addr, thread_seq) + ); + hit_num+=ret; + } + else + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, + RLOG_LV_DEBUG, + "SCAN_DOMAIN", + "Scan domain: %s qtype: %d ret: %d addr: %s", + (char *)dns_info->query_question.qname, + dns_info->query_question.qtype, + ret, + printaddr(&a_stream->addr, thread_seq) + ); + + } + + if(hit_num>0) + { + p_result=tsg_fetch_deny_rule(result, hit_num); + + if(p_result!=NULL) + { + state=fw_dns_action(a_stream, dns_info, p_result, a_packet); + hit_num=1; + } + + fw_dns_send_log(a_stream, dns_info, result, hit_num, thread_seq); + } + + + return state; +} + +extern "C" int FW_DNS_PLUG_INIT(void) +{ + int level=30,ret=0; + char log_path[256]={0}; + memset(&g_fw_dns_plug_info, 0, sizeof(g_fw_dns_plug_info)); + + MESA_load_profile_int_def(g_fw_dns_conffile, "DNS_PLUG", "LOG_LEVEL", &level, 30); + MESA_load_profile_string_def(g_fw_dns_conffile, "DNS_PLUG", "LOG_PATH", log_path, sizeof(log_path), "tsglog/fw_dns_plug/fw_dns_plug"); + + + MESA_load_profile_string_def(g_fw_dns_conffile, "DNS_PLUG", "TABLE_QNAME", g_fw_dns_plug_info.table_qname, MAX_TABLE_NAME_LEN, "TSG_FIELD_DNS_QNAME"); + + g_fw_dns_plug_info.logger=MESA_create_runtime_log_handle(log_path, level); + if(g_fw_dns_plug_info.logger==NULL) + { + printf("MESA_create_runtime_log_handle failed, log_path: %s level: %d", (log_path==NULL) ? NULL : log_path, level); + return -1; + } + + g_fw_dns_plug_info.table_qname_id=Maat_table_register(g_tsg_maat_feather, g_fw_dns_plug_info.table_qname); + if(g_fw_dns_plug_info.table_qname_id<0) + { + MESA_handle_runtime_log(g_fw_dns_plug_info.logger, RLOG_LV_FATAL, "REGISTER_TABLE", "Maat_table_register failed, table_name: %s", g_fw_dns_plug_info.table_qname); + return -1; + } + + ret=fw_dns_rule_init(g_fw_dns_conffile, g_fw_dns_plug_info.logger); + if(ret<0) + { + return -1; + } + + return 0; +} + + +extern "C" void FW_DNS_PLUG_DESTORY(void) +{ + return ; +} + diff --git a/src/fw_dns_plug.h b/src/fw_dns_plug.h new file mode 100644 index 0000000..ea95307 --- /dev/null +++ b/src/fw_dns_plug.h @@ -0,0 +1,15 @@ +#ifndef __FW_DNS_PLUG_H__ +#define __FW_DNS_PLUG_H__ + +#include "fw_dns_rule.h" + +#define MAX_ANSWER_RECORDS_NUM 32 + +struct _fw_dns_plug +{ + int table_qname_id; + char table_qname[MAX_TABLE_NAME_LEN]; + void *logger; +}; + +#endif \ No newline at end of file diff --git a/src/fw_dns_rule.cpp b/src/fw_dns_rule.cpp new file mode 100644 index 0000000..3756a4d --- /dev/null +++ b/src/fw_dns_rule.cpp @@ -0,0 +1,196 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "tsg_rule.h" +#include "fw_dns_rule.h" + +fw_dns_rule_t g_fw_dns_rule_info; +char FW_DNS_RULE_VERSION_20191201=0; + +struct _str2index str2index[]={{DNS_TYPE_CNAME, 5, (char *)"CNAME"}, + {DNS_TYPE_MX, 2, (char *)"MX"}, + {DNS_TYPE_A, 1, (char *)"A"}, + {DNS_TYPE_NS, 2, (char *)"NS"}, + {DNS_TYPE_AAAA, 4, (char *)"AAAA"}, + {DNS_TYPE_TXT, 3, (char *)"TXT"}, + {DNS_TYPE_PTR, 3, (char *)"PTR"} + }; + +int fw_dns_type2index(char *type) +{ + int i=0; + + for(i=0; i<(int)(sizeof(str2index)/sizeof(struct _str2index)); i++) + { + if(str2index[i].len==(int)strlen(type) && (strncasecmp(str2index[i].type, type, str2index[i].len))==0) + { + return str2index[i].index; + } + } + + return -1; +} + +int get_cheat_opt(int record_id, int select_num, int ttl, int atype, cheat_pkt_opt_t* cheat_opt, int cheat_opt_num) +{ + int i=0,idx=0; + int used_num=0,real_num=0; + cb_rule_t *cb_rule=NULL; + + real_num=(select_num>cheat_opt_num) ? cheat_opt_num : select_num; + + cb_rule=(cb_rule_t *)Maat_plugin_get_EX_data(g_tsg_maat_feather, g_fw_dns_rule_info.table_records_id, (char *)&record_id); + if(cb_rule!=NULL && real_num>0) + { + idx = (cb_rule->record_num>=real_num) ? (random()%(cb_rule->record_num-real_num+1)) : 0; + for(i=0; irecord_num; i++) + { + cheat_opt[used_num].ttl=ttl; + cheat_opt[used_num].res_type=atype; + cheat_opt[used_num].cfg_type=atype; + switch(atype) + { + case DNS_TYPE_A: + cheat_opt[used_num].res_len=sizeof(unsigned int); + break; + case DNS_TYPE_AAAA: + cheat_opt[used_num].res_len=IPV6_ADDR_LEN; + break; + default: + cheat_opt[used_num].res_len=MIN(strlen((char *)(cb_rule->record_values[i+idx])), sizeof(cheat_opt[used_num].res_info)-1); + break; + } + + memcpy(cheat_opt[used_num].res_info, (char *)(cb_rule->record_values[i+idx]), cheat_opt[used_num].res_len); + used_num++; + } + } + + return used_num; +} + + +void fw_dns_EX_data_create(int table_id, const char* key, const char* table_line, MAAT_PLUGIN_EX_DATA* ad, long argl, void *argp) +{ + int i=0; + cJSON *pSub=NULL; + cb_rule_t *cb_rule=(cb_rule_t *)calloc(1, sizeof(cb_rule_t)); + char *tmp_records=(char *)calloc(1, strlen(table_line)+1); + + sscanf(table_line, "%d %s %s %s %d", &cb_rule->record_id, cb_rule->record_name, cb_rule->record_type, tmp_records, &cb_rule->is_valid); + + int index=fw_dns_type2index(cb_rule->record_type); + + cJSON *tmp_array=cJSON_Parse(tmp_records); + if(tmp_array != NULL) + { + cb_rule->record_num=cJSON_GetArraySize(tmp_array); + *cb_rule->record_values=(void *)malloc(cb_rule->record_num*sizeof(void *)); + + for(i=0; irecord_num; i++) + { + pSub = cJSON_GetArrayItem(tmp_array, i); + if(NULL==pSub ) + { + continue; + } + + switch(index) + { + case DNS_TYPE_A: + cb_rule->record_values[i]=calloc(1, sizeof(unsigned int)); + inet_pton(AF_INET, pSub->valuestring, cb_rule->record_values[i]); + break; + case DNS_TYPE_AAAA: + cb_rule->record_values[i]=calloc(1, IPV6_ADDR_LEN); + inet_pton(AF_INET6, pSub->valuestring, cb_rule->record_values[i]); + break; + case DNS_TYPE_MX: + break; + case DNS_TYPE_NS: + case DNS_TYPE_TXT: + case DNS_TYPE_PTR: + case DNS_TYPE_CNAME: + cb_rule->record_values[i]=calloc(1, strlen(pSub->valuestring)+1); + memcpy(cb_rule->record_values[i], pSub->valuestring, strlen(pSub->valuestring)); + break; + default: + continue; + } + } + } + + free(tmp_records); +} + +void fw_dns_EX_data_free(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void *argp) +{ + int i=0; + cb_rule_t *cb_rule=(cb_rule_t *)*ad; + + if(cb_rule!=NULL) + { + for(i=0; irecord_num; i++) + { + free(cb_rule->record_values[i]); + cb_rule->record_values[i]=NULL; + } + free(*cb_rule->record_values); + *cb_rule->record_values=NULL; + + free(cb_rule); + cb_rule=NULL; + } +} +void fw_dns_EX_data_dup(int table_id, MAAT_PLUGIN_EX_DATA *to, MAAT_PLUGIN_EX_DATA *from, long argl, void *argp) +{ + +} + +int fw_dns_EX_data_key2index(const char* key) +{ + return 0; +} + + +int fw_dns_rule_init(const char *conffile, void *logger) +{ + int ret=0; + long arg=0; + memset(&g_fw_dns_rule_info, 0, sizeof(g_fw_dns_rule_info)); + + MESA_load_profile_string_def(conffile, "DNS_PLUG", "TABLE_RECORDS", g_fw_dns_rule_info.table_records_name, MAX_TABLE_NAME_LEN, (char *)"FW_PROFILE_DNS_RECORDS"); + + g_fw_dns_rule_info.table_records_id=Maat_table_register(g_tsg_maat_feather, g_fw_dns_rule_info.table_records_name); + if(g_fw_dns_rule_info.table_records_id<0) + { + MESA_handle_runtime_log(logger, RLOG_LV_FATAL, "REGISTER_TABLE", "Maat_table_register failed, table_name: %s", g_fw_dns_rule_info.table_records_name); + return -1; + } + + ret=Maat_plugin_EX_register(g_tsg_maat_feather, + g_fw_dns_rule_info.table_records_id, + fw_dns_EX_data_create, + fw_dns_EX_data_free, + fw_dns_EX_data_dup, + fw_dns_EX_data_key2index, + arg, + NULL); + + if(ret<0) + { + MESA_handle_runtime_log(logger, RLOG_LV_FATAL, "REGISTER_TABLE", "Maat_plugin_EX_register failed, table_name: %s", g_fw_dns_rule_info.table_records_name); + return -1; + } + + return 0; +} + diff --git a/src/fw_dns_rule.h b/src/fw_dns_rule.h new file mode 100644 index 0000000..5933b71 --- /dev/null +++ b/src/fw_dns_rule.h @@ -0,0 +1,36 @@ +#ifndef __FW_DNS_RULE_H__ +#define __FW_DNS_RULE_H__ + +#define MIN(a, b) ((a>b) ? b: a) + +#define MAX_TABLE_NAME_LEN 32 + +struct _str2index +{ + int index; + int len; + char *type; +}; + +typedef struct _cb_rule +{ + int record_id; + int record_num; + int is_valid; + char record_type[128]; + char record_name[MAX_TABLE_NAME_LEN]; + void **record_values; +}cb_rule_t; + +typedef struct _fw_dns_rule +{ + int table_records_id; + char table_records_name[MAX_TABLE_NAME_LEN]; +}fw_dns_rule_t; + + +int fw_dns_type2index(char *type); +int fw_dns_rule_init(const char *conffile, void *logger); +int get_cheat_opt(int record_id, int select_num, int ttl, int atype, cheat_pkt_opt_t* cheat_opt, int cheat_opt_num); + +#endif