diff --git a/decoders/CMakeLists.txt b/decoders/CMakeLists.txt index 2d71d23..8b3f7a9 100644 --- a/decoders/CMakeLists.txt +++ b/decoders/CMakeLists.txt @@ -1,2 +1,5 @@ add_subdirectory(http) add_subdirectory(lpi) +add_subdirectory(socks) +add_subdirectory(stratum) +add_subdirectory(session_flags) \ No newline at end of file diff --git a/decoders/session_flags/CMakeLists.txt b/decoders/session_flags/CMakeLists.txt new file mode 100644 index 0000000..3302328 --- /dev/null +++ b/decoders/session_flags/CMakeLists.txt @@ -0,0 +1,15 @@ +add_subdirectory(mesa_sts) +add_definitions(-fPIC) + +set(SESSION_FLAGS_SRC session_flags_plugin.cpp session_flags.cpp fet.cpp tunneling.cpp onlinemean.c) + +add_library(session_flags STATIC ${SESSION_FLAGS_SRC}) +add_library(session_flags_dyn SHARED ${SESSION_FLAGS_SRC}) +set_target_properties(session_flags PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map") +target_include_directories(session_flags PUBLIC ${CMAKE_SOURCE_DIR}/deps/) +include_directories(${CMAKE_BINARY_DIR}/vendors/cjson/src/cjson/include) +target_link_libraries(session_flags toml cjson-static hyperscan_static hyperscan_runtime_static libmesa_sts) +set_target_properties(session_flags PROPERTIES PREFIX "") + +set_target_properties(session_flags_dyn PROPERTIES PREFIX "") +target_link_libraries(session_flags_dyn toml cjson-static hyperscan_static hyperscan_runtime_static libmesa_sts) \ No newline at end of file diff --git a/decoders/session_flags/fet.cpp b/decoders/session_flags/fet.cpp new file mode 100644 index 0000000..61327d4 --- /dev/null +++ b/decoders/session_flags/fet.cpp @@ -0,0 +1,123 @@ +/*ref: https://github.com/apernet/OpenGFW/blob/1dce82745d0bc8b3813aea147954ba3a2294ef30/analyzer/tcp/fet.go +https://www.usenix.org/system/files/usenixsecurity23-wu-mingshi.pdf +*/ + +#include +#include +#include "fet.h" + +bool isPrintable(unsigned char b) { + return b >= 0x20 && b <= 0x7e; +} + +int popCount(unsigned char b) { + int count = 0; + while (b != 0) { + count += (int)(b & 1); + b >>= 1; + } + return count; +} + +float averagePopCount(const unsigned char* bytes, int bytes_len) { + if (bytes_len == 0) { + return 0; + } + int total = 0; + for (int i = 0; i < bytes_len; i++) { + total += popCount(bytes[i]); + } + return (float)total / (float)bytes_len; +} + +bool isFirstSixPrintable(const unsigned char* bytes, int bytes_len) { + if (bytes_len < 6) { + return false; + } + for (int i = 0; i < 6; i++) { + if (!isPrintable(bytes[i])) { + return false; + } + } + return true; +} + +float printablePercentage(const unsigned char* bytes, int bytes_len) { + if (bytes_len == 0) { + return 0; + } + int count = 0; + for (int i = 0; i < bytes_len; i++) { + if (isPrintable(bytes[i])) { + count++; + } + } + return (float)count / (float)bytes_len; +} + +int contiguousPrintable(const unsigned char* bytes, int bytes_len) { + if (bytes_len == 0) { + return 0; + } + int maxCount = 0; + int current = 0; + for (int i = 0; i < bytes_len; i++) { + if (isPrintable(bytes[i])) { + current++; + } else { + if (current > maxCount) { + maxCount = current; + } + current = 0; + } + } + if (current > maxCount) { + maxCount = current; + } + return maxCount; +} + +bool isTLS(const unsigned char* bytes, int bytes_len) { + if (bytes_len < 3) { + return false; + } + // "We observe that the GFW exempts any connection whose first + // three bytes match the following regular expression: + // [\x16-\x17]\x03[\x00-\x09]" - from the paper in Section 4.3 + if (bytes[0] >= 0x16 && bytes[0] <= 0x17 && + bytes[1] == 0x03 && bytes[2] <= 0x09) { + return true; + } + + return false; +} + +bool isHTTP(const unsigned char* bytes, int bytes_len) { + if (bytes_len < 3) { + return false; + } + + // HTTP request + bool result = memcmp(bytes, "GET", 3) == 0 || memcmp(bytes, "HEA", 3) == 0 || memcmp(bytes, "POS", 3) == 0 || + memcmp(bytes, "PUT", 3) == 0 || memcmp(bytes, "DEL", 3) == 0 || memcmp(bytes, "CON", 3) == 0 || + memcmp(bytes, "OPT", 3) == 0 || memcmp(bytes, "TRA", 3) == 0 || memcmp(bytes, "PAT", 3) == 0; + + return result; +} + +int is_data_fet(unsigned char* data, int data_len, struct fet_detail* detail) { + if (data_len == 0) { + return 0; + } + float ex1 = averagePopCount(data, data_len); + bool ex2 = isFirstSixPrintable(data, data_len); + float ex3 = printablePercentage(data, data_len); + int ex4 = contiguousPrintable(data, data_len); + bool ex5 = isTLS(data, data_len); + bool ex6 = isHTTP(data, data_len); + bool exempt = (ex1 <= 3.4 || ex1 >= 4.6) || ex2 || ex3 > 0.5 || ex4 > 20 || ex5 || ex6; + + detail->is_tls = ex5; + + return !exempt; +} \ No newline at end of file diff --git a/decoders/session_flags/fet.h b/decoders/session_flags/fet.h new file mode 100644 index 0000000..d752ec3 --- /dev/null +++ b/decoders/session_flags/fet.h @@ -0,0 +1,7 @@ +#pragma once + +struct fet_detail { + bool is_tls; +}; + +int is_data_fet(unsigned char* data, int data_len, struct fet_detail* detail); \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/CMakeLists.txt b/decoders/session_flags/mesa_sts/CMakeLists.txt new file mode 100644 index 0000000..fc6f629 --- /dev/null +++ b/decoders/session_flags/mesa_sts/CMakeLists.txt @@ -0,0 +1,15 @@ + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/) + +file(GLOB STS_SRC + "src/*.c" +) + +#add_compile_options(-Wno-error=unused-parameter -Wno-unused-but-set-variable -Wno-error=misleading-indentation -Wno-unused-variable -Wno-maybe-uninitialized -Wno-error=unused-function) +add_library(libmesa_sts ${STS_SRC}) +target_include_directories(libmesa_sts PUBLIC ${CMAKE_SOURCE_DIR}/decoders/session_flags/mesa_sts/include) +target_compile_options(libmesa_sts PRIVATE -Wno-error=unused-parameter -Wno-unused-but-set-variable -Wno-error=misleading-indentation -Wno-unused-variable -Wno-maybe-uninitialized -Wno-error=unused-function) +set_target_properties(libmesa_sts PROPERTIES LINK_FLAGS + "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map") + +add_subdirectory(test) diff --git a/decoders/session_flags/mesa_sts/include/mesa_sts.h b/decoders/session_flags/mesa_sts/include/mesa_sts.h new file mode 100644 index 0000000..ee56102 --- /dev/null +++ b/decoders/session_flags/mesa_sts/include/mesa_sts.h @@ -0,0 +1,57 @@ +#ifndef _MESA_STS_H_ +#define _MESA_STS_H_ + +#define STS_RANDOM_JUDGE_NUM 15 + +#define STS_SET_FLAG(flag, idx) (flag |= (1 << idx)) +#define STS_TEST_FLAG(flag, idx) (flag & (1 << idx)) + +enum sts_random_judge_list_idx +{ + STS_FREQUENCY = 0, + STS_BLOCK_FREQUENCY, + STS_CUMULATIVE_SUMS, + STS_RUNS, + STS_LONGEST_RUN, + STS_RANK, + STS_NON_OVERLAPPING_TEMPLATE_MATCHING, + STS_OVERLAPPING_TEMPLATE_MATCHING, + STS_UNIVERSAL, + STS_RANDOM_EXCURSIONS, + STS_RANDOM_EXCURSIONS_VARIANT, + STS_POKER_DETECT, + STS_RUNS_DISTRIBUTION, + STS_SELF_CORRELATION, + STS_BINARY_DERIVATE, + STS_RANDOM_IDX_MAX +}; + +struct sts_result { + unsigned char frequency; + unsigned char block_frequency; + unsigned char cumulative_sums; + unsigned char runs; + unsigned char longest_run; + unsigned char rank; + unsigned char non_overlapping_template_matching; + unsigned char overlapping_template_matching; + unsigned char universal; + unsigned char random_excursions; + unsigned char random_excursions_variant; + unsigned char poker_detect; + unsigned char runs_distribution; + unsigned char self_correlation; + unsigned char binary_derivative; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int mesa_statistical_test_suite(void* data,unsigned int datalen, struct sts_result* result, unsigned int random_judge_switch_flag); + +#ifdef __cplusplus +} +#endif + +#endif /* _MESA_STS_H_ */ diff --git a/decoders/session_flags/mesa_sts/src/approximateEntropy.c b/decoders/session_flags/mesa_sts/src/approximateEntropy.c new file mode 100644 index 0000000..b386056 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/approximateEntropy.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + A P P R O X I M A T E E N T R O P Y T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +ApproximateEntropy(int m, int n, BitSequence *epsilon) +{ + int i, j, k, r, blockSize, seqLength, powLen, index; + double sum, numOfBlocks, ApEn[2], apen, chi_squared, p_value; + unsigned int *P; + + seqLength = n; + r = 0; + + for ( blockSize=m; blockSize<=m+1; blockSize++ ) { + if ( blockSize == 0 ) { + ApEn[0] = 0.00; + r++; + } + else { + numOfBlocks = (double)seqLength; + powLen = (int)pow(2, blockSize+1)-1; + if ( (P = (unsigned int*)calloc(powLen,sizeof(unsigned int)))== NULL ) { + return 0; + } + for ( i=1; i 0 ) + sum += P[index]*log(P[index]/numOfBlocks); + index++; + } + sum /= numOfBlocks; + ApEn[r] = sum; + r++; + free(P); + } + } + apen = ApEn[0] - ApEn[1]; + + chi_squared = 2.0*seqLength*(log(2) - apen); + p_value = cephes_igamc(pow(2, m-1), chi_squared/2.0); + + if ( m > (int)(log(seqLength)/log(2)-5) ) { + return 0; + } + + if (p_value < ALPHA) { + return 0; + } else { + return 1; + } +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/binaryDerivate.c b/decoders/session_flags/mesa_sts/src/binaryDerivate.c new file mode 100644 index 0000000..6d2dc4a --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/binaryDerivate.c @@ -0,0 +1,30 @@ +#include +#include "include/stat_fncs.h" + +int BinaryDerivate(int k, int n, BitSequence *epsilon, int epsilon_l) +{ + int i = 0, j = 0; + int Sn_k = 0; + int n_k = n - k; + double V = 0.0, p_value = 0.0, sqrt2 = 1.41421356237309504880; + + for (i = 0; i < k; ++i) { + for (j = 0; j < epsilon_l - 1; ++j) { + epsilon[j] = epsilon[j] ^ epsilon[j + 1]; + } + } + + for (i = 0; i < n_k; ++i) { + Sn_k += (2 * (int)epsilon[i]) - 1; + } + + V = fabs(Sn_k) / sqrt(n_k); + + p_value = erfc(fabs(V) / sqrt2); + + if (p_value < ALPHA) { + return 0; + } else { + return 1; + } +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/blockFrequency.c b/decoders/session_flags/mesa_sts/src/blockFrequency.c new file mode 100644 index 0000000..ba4ad34 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/blockFrequency.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + B L O C K F R E Q U E N C Y T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +BlockFrequency(int M, int n, BitSequence *epsilon) +{ + int i, j, N, blockSum; + double p_value, sum, pi, v, chi_squared; + + N = n/M; /* # OF SUBSTRING BLOCKS */ + sum = 0.0; + + for ( i=0; i +#include +#include "include/cephes.h" + +static const double rel_error = 1E-12; + +double MACHEP = 1.11022302462515654042E-16; // 2**-53 +double MAXLOG = 7.09782712893383996732224E2; // log(MAXNUM) +double MAXNUM = 1.7976931348623158E308; // 2**1024*(1-MACHEP) +double PI = 3.14159265358979323846; // pi, duh! + +static double big = 4.503599627370496e15; +static double biginv = 2.22044604925031308085e-16; + +int sgngam = 0; + +double +cephes_igamc(double a, double x) +{ + double ans, ax, c, yc, r, t, y, z; + double pk, pkm1, pkm2, qk, qkm1, qkm2; + + if ( (x <= 0) || ( a <= 0) ) + return( 1.0 ); + + if ( (x < 1.0) || (x < a) ) + return( 1.e0 - cephes_igam(a,x) ); + + ax = a * log(x) - x - cephes_lgam(a); + + if ( ax < -MAXLOG ) { + printf("igamc: UNDERFLOW\n"); + return 0.0; + } + ax = exp(ax); + + /* continued fraction */ + y = 1.0 - a; + z = x + y + 1.0; + c = 0.0; + pkm2 = 1.0; + qkm2 = x; + pkm1 = x + 1.0; + qkm1 = z * x; + ans = pkm1/qkm1; + + do { + c += 1.0; + y += 1.0; + z += 2.0; + yc = y * c; + pk = pkm1 * z - pkm2 * yc; + qk = qkm1 * z - qkm2 * yc; + if ( qk != 0 ) { + r = pk/qk; + t = fabs( (ans - r)/r ); + ans = r; + } + else + t = 1.0; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if ( fabs(pk) > big ) { + pkm2 *= biginv; + pkm1 *= biginv; + qkm2 *= biginv; + qkm1 *= biginv; + } + } while ( t > MACHEP ); + + return ans*ax; +} + +double +cephes_igam(double a, double x) +{ + double ans, ax, c, r; + + if ( (x <= 0) || ( a <= 0) ) + return 0.0; + + if ( (x > 1.0) && (x > a ) ) + return 1.e0 - cephes_igamc(a,x); + + /* Compute x**a * exp(-x) / gamma(a) */ + ax = a * log(x) - x - cephes_lgam(a); + if ( ax < -MAXLOG ) { + printf("igam: UNDERFLOW\n"); + return 0.0; + } + ax = exp(ax); + + /* power series */ + r = a; + c = 1.0; + ans = 1.0; + + do { + r += 1.0; + c *= x/r; + ans += c; + } while ( c/ans > MACHEP ); + + return ans * ax/a; +} + +union A_Array { + double d[5]; + unsigned short us[20]; +}; + + +union BC_Array { + double d[6]; + unsigned short us[24]; +}; + +/* A[]: Stirling's formula expansion of log gamma + * B[], C[]: log gamma function between 2 and 3 + */ + +/**/ +static union A_Array A = { + .us = { + 0x6661,0x2733,0x9850,0x3f4a, + 0xe943,0xb580,0x7fbd,0xbf43, + 0x5ebb,0x20dc,0x019f,0x3f4a, + 0xa5a1,0x16b0,0xc16c,0xbf66, + 0x554b,0x5555,0x5555,0x3fb5 + } +}; +static union BC_Array B = { + .us = { + 0x6761,0x8ff3,0x8901,0xc095, + 0xb93e,0x355b,0xf234,0xc0e2, + 0x89e5,0xf890,0x3d73,0xc114, + 0xdb51,0xf994,0xbc82,0xc131, + 0xf20b,0x0219,0x4589,0xc13a, + 0x055e,0x5418,0x0c67,0xc12a + } +}; +static union BC_Array C = { + /*0x0000,0x0000,0x0000,0x3ff0,*/ + .us = { + 0x12b2,0x1cf3,0xfd0d,0xc075, + 0xd757,0x7b89,0xaa0d,0xc0d0, + 0x4c9b,0xb974,0xeb84,0xc10a, + 0x0043,0x7195,0x6286,0xc131, + 0xf34c,0x892f,0x5255,0xc143, + 0xe14a,0x6a11,0xce4b,0xc13e + } +}; + +#define MAXLGM 2.556348e305 + + +/* Logarithm of gamma function */ +double +cephes_lgam(double x) +{ + double p, q, u, w, z; + int i; + + sgngam = 1; + + if ( x < -34.0 ) { + q = -x; + w = cephes_lgam(q); /* note this modifies sgngam! */ + p = floor(q); + if ( p == q ) { +lgsing: + goto loverf; + } + i = (int)p; + if ( (i & 1) == 0 ) + sgngam = -1; + else + sgngam = 1; + z = q - p; + if ( z > 0.5 ) { + p += 1.0; + z = p - q; + } + z = q * sin( PI * z ); + if ( z == 0.0 ) + goto lgsing; + /* z = log(PI) - log( z ) - w;*/ + z = log(PI) - log( z ) - w; + return z; + } + + if ( x < 13.0 ) { + z = 1.0; + p = 0.0; + u = x; + while ( u >= 3.0 ) { + p -= 1.0; + u = x + p; + z *= u; + } + while ( u < 2.0 ) { + if ( u == 0.0 ) + goto lgsing; + z /= u; + p += 1.0; + u = x + p; + } + if ( z < 0.0 ) { + sgngam = -1; + z = -z; + } + else + sgngam = 1; + if ( u == 2.0 ) + return( log(z) ); + p -= 2.0; + x = x + p; + p = x * cephes_polevl( x, (double *)B.d, 5 ) / cephes_p1evl( x, (double *)C.d, 6); + + return log(z) + p; + } + + if ( x > MAXLGM ) { +loverf: + printf("lgam: OVERFLOW\n"); + + return sgngam * MAXNUM; + } + + q = ( x - 0.5 ) * log(x) - x + log( sqrt( 2*PI ) ); + if ( x > 1.0e8 ) + return q; + + p = 1.0/(x*x); + if ( x >= 1000.0 ) + q += (( 7.9365079365079365079365e-4 * p + - 2.7777777777777777777778e-3) *p + + 0.0833333333333333333333) / x; + else + q += cephes_polevl( p, (double *)A.d, 4 ) / x; + + return q; +} + +double +cephes_polevl(double x, double *coef, int N) +{ + double ans; + int i; + double *p; + + p = coef; + ans = *p++; + i = N; + + do + ans = ans * x + *p++; + while ( --i ); + + return ans; +} + +double +cephes_p1evl(double x, double *coef, int N) +{ + double ans; + double *p; + int i; + + p = coef; + ans = x + *p++; + i = N-1; + + do + ans = ans * x + *p++; + while ( --i ); + + return ans; +} + +double +cephes_erf(double x) +{ + static const double two_sqrtpi = 1.128379167095512574; + double sum = x, term = x, xsqr = x * x; + int j = 1; + + if ( fabs(x) > 2.2 ) + return 1.0 - cephes_erfc(x); + + do { + term *= xsqr/j; + sum -= term/(2*j+1); + j++; + term *= xsqr/j; + sum += term/(2*j+1); + j++; + } while ( fabs(term)/sum > rel_error ); + + return two_sqrtpi*sum; +} + +double +cephes_erfc(double x) +{ + static const double one_sqrtpi = 0.564189583547756287; + double a = 1, b = x, c = x, d = x*x + 0.5; + double q1, q2 = b/d, n = 1.0, t; + + if ( fabs(x) < 2.2 ) + return 1.0 - cephes_erf(x); + if ( x < 0 ) + return 2.0 - cephes_erfc(-x); + + do { + t = a*n + b*x; + a = b; + b = t; + t = c*n + d*x; + c = d; + d = t; + n += 0.5; + q1 = q2; + q2 = b/d; + } while ( fabs(q1-q2)/q2 > rel_error ); + + return one_sqrtpi*exp(-x*x)*q2; +} + + +double +cephes_normal(double x) +{ + double arg, result, sqrt2=1.414213562373095048801688724209698078569672; + + if (x > 0) { + arg = x/sqrt2; + result = 0.5 * ( 1 + erf(arg) ); + } + else { + arg = -x/sqrt2; + result = 0.5 * (erfc(arg) ); + } + + return( result); +} diff --git a/decoders/session_flags/mesa_sts/src/cusum.c b/decoders/session_flags/mesa_sts/src/cusum.c new file mode 100644 index 0000000..d9be4e1 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/cusum.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + C U M U L A T I V E S U M S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +CumulativeSums(int n, BitSequence *epsilon) +{ + int S, sup, inf, z=1, zrev, k; + double sum1, sum2, p_value; + + S = 0; + sup = 0; + inf = 0; + for ( k=0; k sup ) + sup++; + if ( S < inf ) + inf--; + z = (sup > -inf) ? sup : -inf; + zrev = (sup-S > S-inf) ? sup-S : S-inf; + } + + // forward + sum1 = 0.0; + for ( k=(-n/z+1)/4; k<=(n/z-1)/4; k++ ) { + sum1 += cephes_normal(((4*k+1)*z)/sqrt(n)); + sum1 -= cephes_normal(((4*k-1)*z)/sqrt(n)); + } + sum2 = 0.0; + for ( k=(-n/z-3)/4; k<=(n/z-1)/4; k++ ) { + sum2 += cephes_normal(((4*k+3)*z)/sqrt(n)); + sum2 -= cephes_normal(((4*k+1)*z)/sqrt(n)); + } + + p_value = 1.0 - sum1 + sum2; + +// fprintf(stats[TEST_CUSUM], "\t\t CUMULATIVE SUMS (FORWARD) TEST\n"); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); +// fprintf(stats[TEST_CUSUM], "\t\tCOMPUTATIONAL INFORMATION:\n"); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); +// fprintf(stats[TEST_CUSUM], "\t\t(a) The maximum partial sum = %d\n", z); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); + + if ( isNegative(p_value) || isGreaterThanOne(p_value) ) { +// fprintf(stats[TEST_CUSUM], "\t\tWARNING: P_VALUE IS OUT OF RANGE\n"); + return 0; + } + +// fprintf(stats[TEST_CUSUM], "%s\t\tp_value = %f\n\n", p_value < ALPHA ? "FAILURE" : "SUCCESS", p_value); +// fprintf(results[TEST_CUSUM], "%f\n", p_value); + if (p_value < ALPHA) { + return 0; + } + + // backwards + sum1 = 0.0; + for ( k=(-n/zrev+1)/4; k<=(n/zrev-1)/4; k++ ) { + sum1 += cephes_normal(((4*k+1)*zrev)/sqrt(n)); + sum1 -= cephes_normal(((4*k-1)*zrev)/sqrt(n)); + } + sum2 = 0.0; + for ( k=(-n/zrev-3)/4; k<=(n/zrev-1)/4; k++ ) { + sum2 += cephes_normal(((4*k+3)*zrev)/sqrt(n)); + sum2 -= cephes_normal(((4*k+1)*zrev)/sqrt(n)); + } + p_value = 1.0 - sum1 + sum2; + +// fprintf(stats[TEST_CUSUM], "\t\t CUMULATIVE SUMS (REVERSE) TEST\n"); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); +// fprintf(stats[TEST_CUSUM], "\t\tCOMPUTATIONAL INFORMATION:\n"); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); +// fprintf(stats[TEST_CUSUM], "\t\t(a) The maximum partial sum = %d\n", zrev); +// fprintf(stats[TEST_CUSUM], "\t\t-------------------------------------------\n"); + + if ( isNegative(p_value) || isGreaterThanOne(p_value) ) { +// fprintf(stats[TEST_CUSUM], "\t\tWARNING: P_VALUE IS OUT OF RANGE\n"); + return 0; + } + +// fprintf(stats[TEST_CUSUM], "%s\t\tp_value = %f\n\n", p_value < ALPHA ? "FAILURE" : "SUCCESS", p_value); fflush(stats[TEST_CUSUM]); +// fprintf(results[TEST_CUSUM], "%f\n", p_value); fflush(results[TEST_CUSUM]); + if (p_value < ALPHA) { + return 0; + } else { + return 1; + } +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/dfft.c b/decoders/session_flags/mesa_sts/src/dfft.c new file mode 100644 index 0000000..71c0efd --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/dfft.c @@ -0,0 +1,1462 @@ +/* Notes from RFB: + +Looks like the user-level routines are: + +Real FFT + +void __ogg_fdrffti(int n, double *wsave, int *ifac) +void __ogg_fdrfftf(int n, double *r, double *wsave, int *ifac) +void __ogg_fdrfftb(int n, double *r, double *wsave, int *ifac) + +__ogg_fdrffti == initialization +__ogg_fdrfftf == forward transform +__ogg_fdrfftb == backward transform + +Parameters are +n == length of sequence +r == sequence to be transformed (input) +== transformed sequence (output) +wsave == work array of length 2n (allocated by caller) +ifac == work array of length 15 (allocated by caller) + +Cosine quarter-wave FFT + +void __ogg_fdcosqi(int n, double *wsave, int *ifac) +void __ogg_fdcosqf(int n, double *x, double *wsave, int *ifac) +void __ogg_fdcosqb(int n, double *x, double *wsave, int *ifac) +*/ + +/******************************************************************** +* * +* THIS FILE IS PART OF THE OggSQUISH SOFTWARE CODEC SOURCE CODE. * +* * +******************************************************************** + +file: fft.c +function: Fast discrete Fourier and cosine transforms and inverses +author: Monty +modifications by: Monty +last modification date: Jul 1 1996 + +********************************************************************/ + +/* These Fourier routines were originally based on the Fourier +routines of the same names from the NETLIB bihar and fftpack +fortran libraries developed by Paul N. Swarztrauber at the National +Center for Atmospheric Research in Boulder, CO USA. They have been +reimplemented in C and optimized in a few ways for OggSquish. */ + +/* As the original fortran libraries are public domain, the C Fourier +routines in this file are hereby released to the public domain as +well. The C routines here produce output exactly equivalent to the +original fortran routines. Of particular interest are the facts +that (like the original fortran), these routines can work on +arbitrary length vectors that need not be powers of two in +length. */ + +#include +#define STIN static + +static void drfti1(int n, double *wa, int *ifac) +{ + static const int ntryh[4] = { 4,2,3,5 }; + static double tpi = 6.28318530717958647692528676655900577; + double arg, argh, argld, fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + +L101: + j++; + if ( j < 4 ) + ntry = ntryh[j]; + else + ntry += 2; + +L104: + nq = nl/ntry; + nr = nl-ntry*nq; + if ( nr != 0 ) + goto L101; + + nf++; + ifac[nf+1] = ntry; + nl = nq; + if ( ntry != 2 ) + goto L107; + if ( nf == 1 ) + goto L107; + + for ( i=1; i>1; + ipp2 = ip; + idp2 = ido; + nbd = (ido-1)>>1; + t0 = l1*ido; + t10 = ip*ido; + + if ( ido == 1 ) + goto L119; + for ( ik=0; ik l1 ) { + for ( j=1; j>1; + np2 = n; + + kc = np2; + for ( k=1; k>1; + ipp2 = ip; + ipph = (ip+1)>>1; + if ( ido < l1 ) + goto L103; + + t1 = 0; + t2 = 0; + for ( k=0; k l1 ) + goto L139; + + is = -ido-1; + t1 =0; + for ( j=1; j>1; + np2 = n; + + for ( i=2; i +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + D I S C R E T E F O U R I E R T R A N S F O R M T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +void __ogg_fdrffti(int n, double *wsave, int *ifac); +void __ogg_fdrfftf(int n, double *X, double *wsave, int *ifac); + +int +DiscreteFourierTransform(int n, BitSequence *epsilon) +{ + double p_value, upperBound, percentile, N_l, N_o, d, *m, *X, *wsave; + int i, count, ifac[15]; + + if ( ((X = (double*) calloc(n,sizeof(double))) == NULL) || + ((wsave = (double *)calloc(2*n,sizeof(double))) == NULL) || + ((m = (double*)calloc(n/2+1, sizeof(double))) == NULL) ) { + if( X != NULL ) + free(X); + if( wsave != NULL ) + free(wsave); + if( m != NULL ) + free(m); + return 0; + } + for ( i=0; i +#include +#include +#include "include/externs.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + F R E Q U E N C Y T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Frequency(int n, BitSequence *epsilon) +{ + int i; + double f, s_obs, p_value, sum, sqrt2 = 1.41421356237309504880; + + sum = 0.0; + for ( i=0; i y * +** * +** Returns TRUE (1) if x greater than y, * +** otherwise FALSE (0). * +** * +** Parameters: * +** * +** x Address of array x * +** y Address of array y * +** l Length both x and y in bytes * +** * +******************************************/ +int greater(BYTE *x, BYTE *y, int l) +{ + int i; + + for ( i=0; i y[i] ) + return 1; + + return 0; +} + + +/***************************************** +** less - Test if x < y * +** * +** Returns TRUE (1) if x less than y, * +** otherwise FALSE (0). * +** * +** Parameters: * +** * +** x Address of array x * +** y Address of array y * +** l Length both x and y in bytes * +** * +******************************************/ +int less(BYTE *x, BYTE *y, int l) +{ + int i; + + for ( i=0; i>= 1; /* shift the word right once (ms bit = 0) */ + if ( c1 ) + *p |= 0x80; + c1 = c2; + c2 = 0; + p++; + } + + *p >>= 1; /* shift the word right once (ms bit = 0) */ + if ( c1 ) + *p |= 0x80; +} + + +/***************************************** +** Mult - Multiply two integers * +** * +** A = B * C * +** * +** Parameters: * +** * +** A Address of the result * +** B Address of the multiplier * +** C Address of the multiplicand * +** LB Length of B in bytes * +** LC Length of C in bytes * +** * +** NOTE: A MUST be LB+LC in length * +** * +******************************************/ +int Mult(BYTE *A, BYTE *B, int LB, BYTE *C, int LC) +{ + int i, j, k, LA; + DIGIT result; + + LA = LB + LC; + + for ( i=LB-1; i>=0; i-- ) { + result = 0; + for ( j=LC-1; j>=0; j-- ) { + k = i+j+1; + result = (DIGIT)A[k] + ((DIGIT)(B[i] * C[j])) + (result >> 8); + A[k] = (BYTE)result; + } + A[--k] = (BYTE)(result >> 8); + } + + return 0; +} + + +void ModSqr(BYTE *A, BYTE *B, int LB, BYTE *M, int LM) +{ + + Square(A, B, LB); + Mod(A, 2*LB, M, LM); +} + +void ModMult(BYTE *A, BYTE *B, int LB, BYTE *C, int LC, BYTE *M, int LM) +{ + Mult(A, B, LB, C, LC); + Mod(A, (LB+LC), M, LM); +} + + +/***************************************** +** smult - Multiply array by a scalar. * +** * +** A = b * C * +** * +** Parameters: * +** * +** A Address of the result * +** b Scalar (1 BYTE) * +** C Address of the multiplicand * +** L Length of C in bytes * +** * +** NOTE: A MUST be L+1 in length * +** * +******************************************/ +void smult(BYTE *A, BYTE b, BYTE *C, int L) +{ + int i; + DIGIT result; + + result = 0; + for ( i=L-1; i>0; i-- ) { + result = A[i] + ((DIGIT)b * C[i]) + (result >> 8); + A[i] = (BYTE)(result & 0xff); + A[i-1] = (BYTE)(result >> 8); + } +} + +/***************************************** +** Square() - Square an integer * +** * +** A = B^2 * +** * +** Parameters: * +** * +** A Address of the result * +** B Address of the operand * +** L Length of B in bytes * +** * +** NOTE: A MUST be 2*L in length * +** * +******************************************/ +void Square(BYTE *A, BYTE *B, int L) +{ + Mult(A, B, L, B, L); +} + +/***************************************** +** ModExp - Modular Exponentiation * +** * +** A = B ** C (MOD M) * +** * +** Parameters: * +** * +** A Address of result * +** B Address of mantissa * +** C Address of exponent * +** M Address of modulus * +** LB Length of B in bytes * +** LC Length of C in bytes * +** LM Length of M in bytes * +** * +** NOTE: The integer B must be less * +** than the modulus M. * +** NOTE: A must be at least 3*LM * +** bytes long. However, the * +** result stored in A will be * +** only LM bytes long. * +******************************************/ +void ModExp(BYTE *A, BYTE *B, int LB, BYTE *C, int LC, BYTE *M, int LM) +{ + BYTE wmask; + int bits; + + bits = LC*8; + wmask = 0x80; + + A[LM-1] = 1; + + while ( !sniff_bit(C,wmask) ) { + wmask >>= 1; + bits--; + if ( !wmask ) { + wmask = 0x80; + C++; + } + } + + while ( bits-- ) { + memset(A+LM, 0x00, LM*2); + + /* temp = A*A (MOD M) */ + ModSqr(A+LM, A,LM, M,LM); + + /* A = lower L bytes of temp */ + memcpy(A, A+LM*2, LM); + memset(A+LM, 0x00, 2*LM); + + if ( sniff_bit(C,wmask) ) { + memset(A+LM, 0x00, (LM+LB)); + ModMult(A+LM, B,LB, A,LM, M,LM); /* temp = B * A (MOD M) */ + memcpy(A, A+LM+(LM+LB)-LM, LM); /* A = lower LM bytes of temp */ + memset(A+LM, 0x00, 2*LM); + } + + wmask >>= 1; + if ( !wmask ) { + wmask = 0x80; + C++; + } + } +} + + +/* DivMod: + * + * computes: + * quot = x / n + * rem = x % n + * returns: + * length of "quot" + * + * len of rem is lenx+1 + */ +int DivMod(BYTE *x, int lenx, BYTE *n, int lenn, BYTE *quot, BYTE *rem) +{ + BYTE *tx, *tn, *ttx, *ts, bmult[1]; + int i, shift, lgth_x, lgth_n, t_len, lenq; + DIGIT tMSn, mult; + unsigned long tMSx; + int underflow; + + tx = x; + tn = n; + + /* point to the MSD of n */ + for ( i=0, lgth_n=lenn; i n, WATCH OUT if lgth_x == lgth_n */ + while ( (lgth_x > lgth_n) || ((lgth_x == lgth_n) && !less(tx, tn, lgth_n)) ) { + shift = 1; + if ( lgth_n == 1 ) { + if ( *tx < *tn ) { + tMSx = (DIGIT) (((*tx) << 8) | *(tx+1)); + tMSn = *tn; + shift = 0; + } + else { + tMSx = *tx; + tMSn = *tn; + } + } + else if ( lgth_n > 1 ) { + tMSx = (DIGIT) (((*tx) << 8) | *(tx+1)); + tMSn = (DIGIT) (((*tn) << 8) | *(tn+1)); + if ( (tMSx < tMSn) || ((tMSx == tMSn) && less(tx, tn, lgth_n)) ) { + tMSx = (tMSx << 8) | *(tx+2); + shift = 0; + } + } + else { + tMSx = (DIGIT) (((*tx) << 8) | *(tx+1)); + tMSn = *tn; + shift = 0; + } + + mult = (DIGIT) (tMSx / tMSn); + if ( mult > 0xff ) + mult = 0xff; + bmult[0] = mult & 0xff; + + ts = rem; + do { + memset(ts, 0x00, lgth_x+1); + Mult(ts, tn, lgth_n, bmult, 1); + + underflow = 0; + if ( shift ) { + if ( ts[0] != 0 ) + underflow = 1; + else { + for ( i=0; i= 0) ) { + accum += A[tL]; + A[tL--] = (BYTE)(accum & 0xff); + accum = accum >> 8; + } + + return accum; +} + + +/* + * add() + * + * A = A + B + * + * LB must be <= LA + * + */ +BYTE add(BYTE *A, int LA, BYTE *B, int LB) +{ + int i, indexA, indexB; + DIGIT accum; + + indexA = LA - 1; /* LSD of result */ + indexB = LB - 1; /* LSD of B */ + + accum = 0; + for ( i = 0; i < LB; i++ ) { + accum += A[indexA]; + accum += B[indexB--]; + A[indexA--] = (BYTE)(accum & 0xff); + accum = accum >> 8; + } + + if ( LA > LB ) + while ( accum && (indexA >= 0) ) { + accum += A[indexA]; + A[indexA--] = (BYTE)(accum & 0xff); + accum = accum >> 8; + } + + return (BYTE)accum; +} + + +void prettyprintBstr(char *S, BYTE *A, int L) +{ + int i, extra, ctrb, ctrl; + + if ( L == 0 ) + printf("%s ", S); + else + printf("%s\n\t", S); + extra = L % 24; + if ( extra ) { + ctrb = 0; + for ( i=0; i<24-extra; i++ ) { + printf(" "); + if ( ++ctrb == 4) { + printf(" "); + ctrb = 0; + } + } + + for ( i=0; i> 16 ); + buffer[ count ] = ( ( value & 0xFF00FF00L ) >> 8 ) | ( ( value & 0x00FF00FFL ) << 8 ); + } +} + +void +ahtopb (char *ascii_hex, BYTE *p_binary, int bin_len) +{ + BYTE nibble; + int i; + + for ( i=0; i 'F' ) + nibble -= 0x20; + if ( nibble > '9' ) + nibble -= 7; + nibble -= '0'; + p_binary[i] = nibble << 4; + + nibble = ascii_hex[i * 2 + 1]; + if ( nibble > 'F' ) + nibble -= 0x20; + if ( nibble > '9' ) + nibble -= 7; + nibble -= '0'; + p_binary[i] += nibble; + } +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/cephes.h b/decoders/session_flags/mesa_sts/src/include/cephes.h new file mode 100644 index 0000000..64c2b1f --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/cephes.h @@ -0,0 +1,13 @@ +#ifndef _NIST_CEPHES_H_ +#define _NIST_CEPHES_H_ + +double cephes_igamc(double a, double x); +double cephes_igam(double a, double x); +double cephes_lgam(double x); +double cephes_p1evl(double x, double *coef, int N); +double cephes_polevl(double x, double *coef, int N); +double cephes_erf(double x); +double cephes_erfc(double x); +double cephes_normal(double x); + +#endif /* _CEPHES_H_ */ diff --git a/decoders/session_flags/mesa_sts/src/include/config.h b/decoders/session_flags/mesa_sts/src/include/config.h new file mode 100644 index 0000000..f31f50f --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/config.h @@ -0,0 +1,52 @@ + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef _NIST_CONFIG_H_ +#define _NIST_CONFIG_H_ + +#define WINDOWS32 +//#define PROTOTYPES +//#define LITTLE_ENDIAN +//#define LOWHI + +/* + * AUTO DEFINES (DON'T TOUCH!) + */ + +#ifndef CSTRTD +typedef char *CSTRTD; +#endif +#ifndef BSTRTD +typedef unsigned char *BSTRTD; +#endif + +#ifndef BYTE +typedef unsigned char BYTE; +#endif +#ifndef UINT +typedef unsigned int UINT; +#endif +#ifndef USHORT +typedef unsigned short USHORT; +#endif +//#ifndef ULONG +//typedef unsigned long ULONG; +//#endif +#ifndef DIGIT +typedef USHORT DIGIT; /* 16-bit word */ +#endif +#ifndef DBLWORD +typedef unsigned long DBLWORD; /* 32-bit word */ +#endif + +#ifndef WORD64 +typedef unsigned long WORD64[2]; /* 64-bit word */ +#endif + +#endif /* _CONFIG_H_ */ + +#if defined(__cplusplus) +} +#endif \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/decls.h b/decoders/session_flags/mesa_sts/src/include/decls.h new file mode 100644 index 0000000..510ae47 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/decls.h @@ -0,0 +1,24 @@ +#ifndef _NIST_DECLS_H_ +#define _NIST_DECLS_H_ + +#include +#include "defs.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + G L O B A L D A T A S T R U C T U R E S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +BitSequence *epsilon; // BIT STREAM +TP tp; // TEST PARAMETER STRUCTURE +FILE *stats[NUMOFTESTS+1]; // FILE OUTPUT STREAM +FILE *results[NUMOFTESTS+1]; // FILE OUTPUT STREAM +FILE *freqfp; // FILE OUTPUT STREAM +FILE *summary; // FILE OUTPUT STREAM +int testVector[NUMOFTESTS+1]; + +char generatorDir[NUMOFGENERATORS][20] = { "AlgorithmTesting", "LCG", "QCG1", "QCG2","CCG", "XOR", + "MODEXP", "BBS", "MS", "G-SHA1" }; + + + +#endif \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/defs.h b/decoders/session_flags/mesa_sts/src/include/defs.h new file mode 100644 index 0000000..e0e93f7 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/defs.h @@ -0,0 +1,73 @@ +#ifndef _NIST_DEFS_H_ +#define _NIST_DEFS_H_ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + D E B U G G I N G A I D E S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "config.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + M A C R O S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define MAX(x,y) ((x) < (y) ? (y) : (x)) +#define MIN(x,y) ((x) > (y) ? (y) : (x)) +#define isNonPositive(x) ((x) <= 0.e0 ? 1 : 0) +#define isPositive(x) ((x) > 0.e0 ? 1 : 0) +#define isNegative(x) ((x) < 0.e0 ? 1 : 0) +#define isGreaterThanOne(x) ((x) > 1.e0 ? 1 : 0) +#define isZero(x) ((x) == 0.e0 ? 1 : 0) +#define isOne(x) ((x) == 1.e0 ? 1 : 0) + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + G L O B A L C O N S T A N T S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define ALPHA 0.01 /* SIGNIFICANCE LEVEL */ +#define MAXNUMOFTEMPLATES 148 /* APERIODIC TEMPLATES: 148=>temp_length=9 */ + +#define NUMOFGENERATORS 10 /* MAX PRNGs */ +#define MAXFILESPERMITTEDFORPARTITION 148 + +#define TEST_FREQUENCY 1 +#define TEST_BLOCK_FREQUENCY 2 +#define TEST_CUSUM 3 +#define TEST_RUNS 4 +#define TEST_LONGEST_RUN 5 +#define TEST_RANK 6 +#define TEST_FFT 7 +#define TEST_NONPERIODIC 8 +#define TEST_OVERLAPPING 9 +#define TEST_UNIVERSAL 10 +#define TEST_APEN 11 +#define TEST_RND_EXCURSION 12 +#define TEST_RND_EXCURSION_VAR 13 +#define TEST_SERIAL 14 +#define TEST_LINEARCOMPLEXITY 15 +#define TEST_POKER_DETECT 16 +#define TEST_RUNS_DISTRIBUTION 17 +#define TEST_BIN_DERIVATE 18 +#define TEST_SELF_CORR 19 + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + G L O B A L D A T A S T R U C T U R E S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +typedef unsigned char BitSequence; + +typedef struct _testParameters { + int n; + int blockFrequencyBlockLength; + int nonOverlappingTemplateBlockLength; + int overlappingTemplateBlockLength; + int serialBlockLength; + int linearComplexitySequenceLength; + int approximateEntropyBlockLength; + int PokerDetectMLength; + int BinaryDerivateKLength; + int SelfCorrelationDLength; + int numOfBitStreams; +} TP; + +#endif \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/externs.h b/decoders/session_flags/mesa_sts/src/include/externs.h new file mode 100644 index 0000000..9f6ea9b --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/externs.h @@ -0,0 +1,21 @@ +#ifndef _NIST_EXTERNS_H_ +#define _NIST_EXTERNS_H_ + +#include "defs.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + G L O B A L D A T A S T R U C T U R E S + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +//extern BitSequence *epsilon; // BIT STREAM +//extern TP tp; // TEST PARAMETER STRUCTURE +//extern FILE *stats[NUMOFTESTS+1]; // FILE OUTPUT STREAM +//extern FILE *results[NUMOFTESTS+1]; // FILE OUTPUT STREAM +//extern FILE *freqfp; // FILE OUTPUT STREAM +//extern FILE *summary; // FILE OUTPUT STREAM +//extern int testVector[NUMOFTESTS+1]; +// +//extern char generatorDir[NUMOFGENERATORS][20]; +//extern char testNames[NUMOFTESTS+1][32]; + +#endif \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/generators.h b/decoders/session_flags/mesa_sts/src/include/generators.h new file mode 100644 index 0000000..183d05e --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/generators.h @@ -0,0 +1,78 @@ +#ifndef _NIST_GENERATORS_H_ +#define _NIST_GENERATORS_H_ + + +/* The circular shifts. */ +#define CS1(x) ((((ULONG)x)<<1)|(((ULONG)x)>>31)) +#define CS5(x) ((((ULONG)x)<<5)|(((ULONG)x)>>27)) +#define CS30(x) ((((ULONG)x)<<30)|(((ULONG)x)>>2)) + +/* K constants */ + +#define K0 0x5a827999L +#define K1 0x6ed9eba1L +#define K2 0x8f1bbcdcL +#define K3 0xca62c1d6L + +#define f1(x,y,z) ( (x & (y ^ z)) ^ z ) + +#define f3(x,y,z) ( (x & ( y ^ z )) ^ (z & y) ) + +#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ + +#define expand(x) Wbuff[x%16] = CS1(Wbuff[(x - 3)%16 ] ^ Wbuff[(x - 8)%16 ] ^ Wbuff[(x - 14)%16] ^ Wbuff[x%16]) + +#define sub1Round1(count) { \ + temp = CS5(A) + f1(B, C, D) + E + Wbuff[count] + K0; \ + E = D; \ + D = C; \ + C = CS30( B ); \ + B = A; \ + A = temp; \ + } \ + +#define sub2Round1(count) \ + { \ + expand(count); \ + temp = CS5(A) + f1(B, C, D) + E + Wbuff[count%16] + K0; \ + E = D; \ + D = C; \ + C = CS30( B ); \ + B = A; \ + A = temp; \ + } \ + +#define Round2(count) \ + { \ + expand(count); \ + temp = CS5( A ) + f2( B, C, D ) + E + Wbuff[count%16] + K1; \ + E = D; \ + D = C; \ + C = CS30( B ); \ + B = A; \ + A = temp; \ + } \ + +#define Round3(count) \ + { \ + expand(count); \ + temp = CS5( A ) + f3( B, C, D ) + E + Wbuff[count%16] + K2; \ + E = D; \ + D = C; \ + C = CS30( B ); \ + B = A; \ + A = temp; \ + } + +#define Round4(count) \ + { \ + expand(count); \ + temp = CS5( A ) + f2( B, C, D ) + E + Wbuff[count%16] + K3; \ + E = D; \ + D = C; \ + C = CS30( B ); \ + B = A; \ + A = temp; \ + } + +#endif \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/include/genutils.h b/decoders/session_flags/mesa_sts/src/include/genutils.h new file mode 100644 index 0000000..3d61ed4 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/include/genutils.h @@ -0,0 +1,47 @@ +#ifndef _NIST_GENUTILS_H_ +#define _NIST_GENUTILS_H_ + +#include +#include +#include +#include "config.h" + +typedef struct _MP_struct { + int size; /* in bytes */ + int bitlen; /* in bits, duh */ + BYTE *val; + } MP; + +#define FREE(A) if ( (A) ) { free((A)); (A) = NULL; } +#define ASCII2BIN(ch) ( (((ch) >= '0') && ((ch) <= '9')) ? ((ch) - '0') : (((ch) >= 'A') && ((ch) <= 'F')) ? ((ch) - 'A' + 10) : ((ch) - 'a' + 10) ) + +#ifndef EXPWD +#define EXPWD ((DBLWORD)1< +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +int +LinearComplexity(int M, int n, BitSequence *epsilon) +{ + int i, ii, j, d, N, L, m, N_, parity, sign, K = 6; + double p_value, T_, mean, nu[7], chi2; + const double pi[7] = { 0.01047, 0.03125, 0.12500, 0.50000, 0.25000, 0.06250, 0.020833 }; + BitSequence *T, *P, *B_, *C; + + N = (int)floor(n/M); + if ( ((B_ = (BitSequence *) calloc(M, sizeof(BitSequence))) == NULL) || + ((C = (BitSequence *) calloc(M, sizeof(BitSequence))) == NULL) || + ((P = (BitSequence *) calloc(M, sizeof(BitSequence))) == NULL) || + ((T = (BitSequence *) calloc(M, sizeof(BitSequence))) == NULL) ) { + printf("Insufficient Memory for Work Space:: Linear Complexity Test\n"); + if ( B_!= NULL ) + free(B_); + if ( C != NULL ) + free(C); + if ( P != NULL ) + free(P); + if ( T != NULL ) + free(T); + return 0; + } + + +// fprintf(stats[TEST_LINEARCOMPLEXITY], "-----------------------------------------------------\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "\tL I N E A R C O M P L E X I T Y\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "-----------------------------------------------------\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "\tM (substring length) = %d\n", M); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "\tN (number of substrings) = %d\n", N); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "-----------------------------------------------------\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], " F R E Q U E N C Y \n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "-----------------------------------------------------\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], " C0 C1 C2 C3 C4 C5 C6 CHI2 P-value\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "-----------------------------------------------------\n"); +// fprintf(stats[TEST_LINEARCOMPLEXITY], "\tNote: %d bits were discarded!\n", n%M); + + for ( i=0; i +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + L O N G E S T R U N S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +LongestRunOfOnes(int n, BitSequence *epsilon) +{ + double pval, chi2, pi[7]; + int run, v_n_obs, N, i, j, K, M, V[7]; + unsigned int nu[7] = { 0, 0, 0, 0, 0, 0, 0 }; + + if ( n < 128 ) { +// fprintf(stats[TEST_LONGEST_RUN], "\t\t\t LONGEST RUNS OF ONES TEST\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t---------------------------------------------\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t n=%d is too short\n", n); + return 0; + } + if ( n < 6272 ) { + K = 3; + M = 8; + V[0] = 1; V[1] = 2; V[2] = 3; V[3] = 4; + pi[0] = 0.21484375; + pi[1] = 0.3671875; + pi[2] = 0.23046875; + pi[3] = 0.1875; + } + else if ( n < 750000 ) { + K = 5; + M = 128; + V[0] = 4; V[1] = 5; V[2] = 6; V[3] = 7; V[4] = 8; V[5] = 9; + pi[0] = 0.1174035788; + pi[1] = 0.242955959; + pi[2] = 0.249363483; + pi[3] = 0.17517706; + pi[4] = 0.102701071; + pi[5] = 0.112398847; + } + else { + K = 6; + M = 10000; + V[0] = 10; V[1] = 11; V[2] = 12; V[3] = 13; V[4] = 14; V[5] = 15; V[6] = 16; + pi[0] = 0.0882; + pi[1] = 0.2092; + pi[2] = 0.2483; + pi[3] = 0.1933; + pi[4] = 0.1208; + pi[5] = 0.0675; + pi[6] = 0.0727; + } + + N = n/M; + for ( i=0; i v_n_obs ) + v_n_obs = run; + } + else + run = 0; + } + if ( v_n_obs < V[0] ) + nu[0]++; + for ( j=0; j<=K; j++ ) { + if ( v_n_obs == V[j] ) + nu[j]++; + } + if ( v_n_obs > V[K] ) + nu[K]++; + } + + chi2 = 0.0; + for ( i=0; i<=K; i++ ) + chi2 += ((nu[i] - N * pi[i]) * (nu[i] - N * pi[i])) / (N * pi[i]); + + pval = cephes_igamc((double)(K/2.0), chi2 / 2.0); + +// fprintf(stats[TEST_LONGEST_RUN], "\t\t\t LONGEST RUNS OF ONES TEST\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t---------------------------------------------\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\tCOMPUTATIONAL INFORMATION:\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t---------------------------------------------\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t(a) N (# of substrings) = %d\n", N); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t(b) M (Substring Length) = %d\n", M); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t(c) Chi^2 = %f\n", chi2); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t---------------------------------------------\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t F R E Q U E N C Y\n"); +// fprintf(stats[TEST_LONGEST_RUN], "\t\t---------------------------------------------\n"); + +// if ( K == 3 ) { +// fprintf(stats[TEST_LONGEST_RUN], "\t\t <=1 2 3 >=4 P-value Assignment"); +// fprintf(stats[TEST_LONGEST_RUN], "\n\t\t %3d %3d %3d %3d ", nu[0], nu[1], nu[2], nu[3]); +// } +// else if ( K == 5 ) { +// fprintf(stats[TEST_LONGEST_RUN], "\t\t<=4 5 6 7 8 >=9 P-value Assignment"); +// fprintf(stats[TEST_LONGEST_RUN], "\n\t\t %3d %3d %3d %3d %3d %3d ", nu[0], nu[1], nu[2], +// nu[3], nu[4], nu[5]); +// } +// else { +// fprintf(stats[TEST_LONGEST_RUN],"\t\t<=10 11 12 13 14 15 >=16 P-value Assignment"); +// fprintf(stats[TEST_LONGEST_RUN],"\n\t\t %3d %3d %3d %3d %3d %3d %3d ", nu[0], nu[1], nu[2], +// nu[3], nu[4], nu[5], nu[6]); +// } + if ( isNegative(pval) || isGreaterThanOne(pval) ) { +// fprintf(stats[TEST_LONGEST_RUN], "WARNING: P_VALUE IS OUT OF RANGE.\n"); + return 0; + } + +// fprintf(stats[TEST_LONGEST_RUN], "%s\t\tp_value = %f\n\n", pval < ALPHA ? "FAILURE" : "SUCCESS", pval); fflush(stats[TEST_LONGEST_RUN]); +// fprintf(results[TEST_LONGEST_RUN], "%f\n", pval); fflush(results[TEST_LONGEST_RUN]); + if (pval < ALPHA) { + return 0; + } else { + return 1; + } +} diff --git a/decoders/session_flags/mesa_sts/src/matrix.c b/decoders/session_flags/mesa_sts/src/matrix.c new file mode 100644 index 0000000..c456187 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/matrix.c @@ -0,0 +1,170 @@ +#include +#include +#include "include/externs.h" +#include "include/matrix.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +R A N K A L G O R I T H M R O U T I N E S +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define MATRIX_FORWARD_ELIMINATION 0 +#define MATRIX_BACKWARD_ELIMINATION 1 + +int +computeRank(int M, int Q, BitSequence **matrix) +{ + int i, rank, m=MIN(M,Q); + + /* FORWARD APPLICATION OF ELEMENTARY ROW OPERATIONS */ + for ( i=0; i0; i-- ) { + if ( matrix[i][i] == 1 ) + perform_elementary_row_operations(MATRIX_BACKWARD_ELIMINATION, i, M, Q, matrix); + else { /* matrix[i][i] = 0 */ + if ( find_unit_element_and_swap(MATRIX_BACKWARD_ELIMINATION, i, M, Q, matrix) == 1 ) + perform_elementary_row_operations(MATRIX_BACKWARD_ELIMINATION, i, M, Q, matrix); + } + } + + rank = determine_rank(m, M, Q, matrix); + + return rank; +} + +void +perform_elementary_row_operations(int flag, int i, int M, int Q, BitSequence **A) +{ + int j, k; + + if ( flag == MATRIX_FORWARD_ELIMINATION ) { + for ( j=i+1; j=0; j-- ) + if ( A[j][i] == 1 ) + for ( k=0; k= 0) && (A[index][i] == 0) ) + index--; + if ( index >= 0 ) + row_op = swap_rows(i, index, Q, A); + } + + return row_op; +} + +int +swap_rows(int i, int index, int Q, BitSequence **A) +{ + int p; + BitSequence temp; + + for ( p=0; p +#include "include/utilities.h" +#include "include/stat_fncs.h" +#include "mesa_sts.h" + +int mesa_statistical_test_suite(void* data,unsigned int datalen, struct sts_result* result, unsigned int random_judge_switch_flag) +{ + TP tp; + tp.n = datalen; + tp.blockFrequencyBlockLength = 128; + tp.nonOverlappingTemplateBlockLength = 9; + tp.overlappingTemplateBlockLength = 9; + tp.approximateEntropyBlockLength = 10; + tp.serialBlockLength = 16; + tp.linearComplexitySequenceLength = 500; + tp.numOfBitStreams = 1; + tp.PokerDetectMLength = 8; + tp.BinaryDerivateKLength = 3; + tp.SelfCorrelationDLength = 8; + + BitSequence* epsilon = (BitSequence *)calloc(tp.n,sizeof(BitSequence)); + int done, num_0s, num_1s, bitsRead; + num_0s = 0; + num_1s = 0; + bitsRead = 0; + done = 0; + done = convertToBits((BYTE*)data,datalen,tp.n,&num_0s,&num_1s,&bitsRead,epsilon); + if (STS_TEST_FLAG(random_judge_switch_flag, STS_FREQUENCY)) + { + result->frequency = Frequency(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_BLOCK_FREQUENCY)) + { + result->block_frequency = BlockFrequency(tp.blockFrequencyBlockLength, tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_CUMULATIVE_SUMS)) + { + result->cumulative_sums = CumulativeSums(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_RUNS)) + { + result->runs = Runs(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_LONGEST_RUN)) + { + result->longest_run = LongestRunOfOnes(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_RANK)) + { + result->rank = Rank(tp.n,epsilon); + } + + //result->discrete_fourier_transform = DiscreteFourierTransform(tp.n,epsilon);//cost too much time + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_NON_OVERLAPPING_TEMPLATE_MATCHING)) + { + result->non_overlapping_template_matching = NonOverlappingTemplateMatchings(tp.nonOverlappingTemplateBlockLength, tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_OVERLAPPING_TEMPLATE_MATCHING)) + { + result->overlapping_template_matching = OverlappingTemplateMatchings(tp.overlappingTemplateBlockLength, tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_UNIVERSAL)) + { + result->universal = Universal(tp.n,epsilon); + } + + //result->approximate_entropy = ApproximateEntropy(tp.approximateEntropyBlockLength, tp.n,epsilon);//cost too much time + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_RANDOM_EXCURSIONS)) + { + result->random_excursions = RandomExcursions(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_RANDOM_EXCURSIONS_VARIANT)) + { + result->random_excursions_variant = RandomExcursionsVariant(tp.n,epsilon); + } + + //result->serial = Serial(tp.serialBlockLength,tp.n,epsilon);//cost too much time + //sresult->linear_complexity = LinearComplexity(tp.linearComplexitySequenceLength, tp.n,epsilon);//cost too much time + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_POKER_DETECT)) + { + result->poker_detect = PokerDetect(tp.PokerDetectMLength,tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_RUNS_DISTRIBUTION)) + { + result->runs_distribution = RunsDistribution(tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_SELF_CORRELATION)) + { + result->self_correlation = SelfCorrelation(tp.SelfCorrelationDLength,tp.n,epsilon); + } + + if (STS_TEST_FLAG(random_judge_switch_flag, STS_BINARY_DERIVATE)) + { + result->binary_derivative = BinaryDerivate(tp.BinaryDerivateKLength,tp.n,epsilon,tp.n);//this function will change the value of epsilon, must be the last one + } + + free(epsilon); + epsilon = NULL; + + return 0; +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/nonOverlappingTemplateMatchings.c b/decoders/session_flags/mesa_sts/src/nonOverlappingTemplateMatchings.c new file mode 100644 index 0000000..1bc47db --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/nonOverlappingTemplateMatchings.c @@ -0,0 +1,281 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + N O N O V E R L A P P I N G T E M P L A T E T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +static unsigned int template9[] = { +0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,1,1, +0,0,0,0,0,0,1,0,1, +0,0,0,0,0,0,1,1,1, +0,0,0,0,0,1,0,0,1, +0,0,0,0,0,1,0,1,1, +0,0,0,0,0,1,1,0,1, +0,0,0,0,0,1,1,1,1, +0,0,0,0,1,0,0,0,1, +0,0,0,0,1,0,0,1,1, +0,0,0,0,1,0,1,0,1, +0,0,0,0,1,0,1,1,1, +0,0,0,0,1,1,0,0,1, +0,0,0,0,1,1,0,1,1, +0,0,0,0,1,1,1,0,1, +0,0,0,0,1,1,1,1,1, +0,0,0,1,0,0,0,1,1, +0,0,0,1,0,0,1,0,1, +0,0,0,1,0,0,1,1,1, +0,0,0,1,0,1,0,0,1, +0,0,0,1,0,1,0,1,1, +0,0,0,1,0,1,1,0,1, +0,0,0,1,0,1,1,1,1, +0,0,0,1,1,0,0,1,1, +0,0,0,1,1,0,1,0,1, +0,0,0,1,1,0,1,1,1, +0,0,0,1,1,1,0,0,1, +0,0,0,1,1,1,0,1,1, +0,0,0,1,1,1,1,0,1, +0,0,0,1,1,1,1,1,1, +0,0,1,0,0,0,0,1,1, +0,0,1,0,0,0,1,0,1, +0,0,1,0,0,0,1,1,1, +0,0,1,0,0,1,0,1,1, +0,0,1,0,0,1,1,0,1, +0,0,1,0,0,1,1,1,1, +0,0,1,0,1,0,0,1,1, +0,0,1,0,1,0,1,0,1, +0,0,1,0,1,0,1,1,1, +0,0,1,0,1,1,0,1,1, +0,0,1,0,1,1,1,0,1, +0,0,1,0,1,1,1,1,1, +0,0,1,1,0,0,1,0,1, +0,0,1,1,0,0,1,1,1, +0,0,1,1,0,1,0,1,1, +0,0,1,1,0,1,1,0,1, +0,0,1,1,0,1,1,1,1, +0,0,1,1,1,0,1,0,1, +0,0,1,1,1,0,1,1,1, +0,0,1,1,1,1,0,1,1, +0,0,1,1,1,1,1,0,1, +0,0,1,1,1,1,1,1,1, +0,1,0,0,0,0,0,1,1, +0,1,0,0,0,0,1,1,1, +0,1,0,0,0,1,0,1,1, +0,1,0,0,0,1,1,1,1, +0,1,0,0,1,0,0,1,1, +0,1,0,0,1,0,1,1,1, +0,1,0,0,1,1,0,1,1, +0,1,0,0,1,1,1,1,1, +0,1,0,1,0,0,0,1,1, +0,1,0,1,0,0,1,1,1, +0,1,0,1,0,1,0,1,1, +0,1,0,1,0,1,1,1,1, +0,1,0,1,1,0,0,1,1, +0,1,0,1,1,0,1,1,1, +0,1,0,1,1,1,0,1,1, +0,1,0,1,1,1,1,1,1, +0,1,1,0,0,0,1,1,1, +0,1,1,0,0,1,1,1,1, +0,1,1,0,1,0,1,1,1, +0,1,1,0,1,1,1,1,1, +0,1,1,1,0,1,1,1,1, +0,1,1,1,1,1,1,1,1, +1,0,0,0,0,0,0,0,0, +1,0,0,0,1,0,0,0,0, +1,0,0,1,0,0,0,0,0, +1,0,0,1,0,1,0,0,0, +1,0,0,1,1,0,0,0,0, +1,0,0,1,1,1,0,0,0, +1,0,1,0,0,0,0,0,0, +1,0,1,0,0,0,1,0,0, +1,0,1,0,0,1,0,0,0, +1,0,1,0,0,1,1,0,0, +1,0,1,0,1,0,0,0,0, +1,0,1,0,1,0,1,0,0, +1,0,1,0,1,1,0,0,0, +1,0,1,0,1,1,1,0,0, +1,0,1,1,0,0,0,0,0, +1,0,1,1,0,0,1,0,0, +1,0,1,1,0,1,0,0,0, +1,0,1,1,0,1,1,0,0, +1,0,1,1,1,0,0,0,0, +1,0,1,1,1,0,1,0,0, +1,0,1,1,1,1,0,0,0, +1,0,1,1,1,1,1,0,0, +1,1,0,0,0,0,0,0,0, +1,1,0,0,0,0,0,1,0, +1,1,0,0,0,0,1,0,0, +1,1,0,0,0,1,0,0,0, +1,1,0,0,0,1,0,1,0, +1,1,0,0,1,0,0,0,0, +1,1,0,0,1,0,0,1,0, +1,1,0,0,1,0,1,0,0, +1,1,0,0,1,1,0,0,0, +1,1,0,0,1,1,0,1,0, +1,1,0,1,0,0,0,0,0, +1,1,0,1,0,0,0,1,0, +1,1,0,1,0,0,1,0,0, +1,1,0,1,0,1,0,0,0, +1,1,0,1,0,1,0,1,0, +1,1,0,1,0,1,1,0,0, +1,1,0,1,1,0,0,0,0, +1,1,0,1,1,0,0,1,0, +1,1,0,1,1,0,1,0,0, +1,1,0,1,1,1,0,0,0, +1,1,0,1,1,1,0,1,0, +1,1,0,1,1,1,1,0,0, +1,1,1,0,0,0,0,0,0, +1,1,1,0,0,0,0,1,0, +1,1,1,0,0,0,1,0,0, +1,1,1,0,0,0,1,1,0, +1,1,1,0,0,1,0,0,0, +1,1,1,0,0,1,0,1,0, +1,1,1,0,0,1,1,0,0, +1,1,1,0,1,0,0,0,0, +1,1,1,0,1,0,0,1,0, +1,1,1,0,1,0,1,0,0, +1,1,1,0,1,0,1,1,0, +1,1,1,0,1,1,0,0,0, +1,1,1,0,1,1,0,1,0, +1,1,1,0,1,1,1,0,0, +1,1,1,1,0,0,0,0,0, +1,1,1,1,0,0,0,1,0, +1,1,1,1,0,0,1,0,0, +1,1,1,1,0,0,1,1,0, +1,1,1,1,0,1,0,0,0, +1,1,1,1,0,1,0,1,0, +1,1,1,1,0,1,1,0,0, +1,1,1,1,0,1,1,1,0, +1,1,1,1,1,0,0,0,0, +1,1,1,1,1,0,0,1,0, +1,1,1,1,1,0,1,0,0, +1,1,1,1,1,0,1,1,0, +1,1,1,1,1,1,0,0,0, +1,1,1,1,1,1,0,1,0, +1,1,1,1,1,1,1,0,0, +1,1,1,1,1,1,1,1,0, +}; +static size_t template_size = sizeof(template9)/sizeof(template9[0]); + +int +NonOverlappingTemplateMatchings(int m, int n, BitSequence *epsilon) +{ + int ret = 0; + int numOfTemplates[100] = {0, 0, 2, 4, 6, 12, 20, 40, 74, 148, 284, 568, 1116, + 2232, 4424, 8848, 17622, 35244, 70340, 140680, 281076, 562152}; + /*---------------------------------------------------------------------------- + NOTE: Should additional templates lengths beyond 21 be desired, they must + first be constructed, saved into files and then the corresponding + number of nonperiodic templates for that file be stored in the m-th + position in the numOfTemplates variable. + ----------------------------------------------------------------------------*/ + unsigned int W_obs, nu[6], *Wj = NULL; + size_t template_idx = 0; + double sum, chi2, p_value, lambda, pi[6], varWj; + int i, j, jj, k, match, SKIP, M, N, K = 5; + BitSequence *sequence = NULL; + + N = 8; + M = n/N; + + if ( (Wj = (unsigned int*)calloc(N, sizeof(unsigned int))) == NULL ) { + return 0; + } + lambda = (M-m+1)/pow(2, m); + varWj = M*(1.0/pow(2.0, m) - (2.0*m-1.0)/pow(2.0, 2.0*m)); + + if ( ((isNegative(lambda)) || (isZero(lambda))) || + ((sequence = (BitSequence *) calloc(m, sizeof(BitSequence))) == NULL) ) { + goto end; + } + else { + if ( numOfTemplates[m] < MAXNUMOFTEMPLATES ) + SKIP = 1; + else + SKIP = (int)(numOfTemplates[m]/MAXNUMOFTEMPLATES); + numOfTemplates[m] = (int)numOfTemplates[m]/SKIP; + + sum = 0.0; + for ( i=0; i<2; i++ ) { /* Compute Probabilities */ + pi[i] = exp(-lambda+i*log(lambda)-cephes_lgam(i+1)); + sum += pi[i]; + } + pi[0] = sum; + for ( i=2; i<=K; i++ ) { /* Compute Probabilities */ + pi[i-1] = exp(-lambda+i*log(lambda)-cephes_lgam(i+1)); + sum += pi[i-1]; + } + pi[K] = 1 - sum; + + for( jj=0; jj 1 ) + template_idx += (SKIP-1)*2*m; +// fprintf(results[TEST_NONPERIODIC], "%f\n", p_value); fflush(results[TEST_NONPERIODIC]); + if (p_value < ALPHA) { + goto end; + } + } + } + + ret = 1; +// fprintf(stats[TEST_NONPERIODIC], "\n"); fflush(stats[TEST_NONPERIODIC]); + + end: + if (Wj != NULL) { + free(Wj); + } + if (sequence != NULL) { + free(sequence); + } + return ret; +} diff --git a/decoders/session_flags/mesa_sts/src/overlappingTemplateMatchings.c b/decoders/session_flags/mesa_sts/src/overlappingTemplateMatchings.c new file mode 100644 index 0000000..70eabdf --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/overlappingTemplateMatchings.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + O V E R L A P P I N G T E M P L A T E T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +double Pr(int u, double eta); + +int +OverlappingTemplateMatchings(int m, int n, BitSequence *epsilon) +{ + int ret = 0; + int i, k, match; + double W_obs, eta, sum, chi2, p_value, lambda; + int M, N, j, K = 5; + unsigned int nu[6] = { 0, 0, 0, 0, 0, 0 }; + double pi[6] = { 0.143783, 0.139430, 0.137319, 0.124314, 0.106209, 0.348945 }; + BitSequence *sequence; + + M = 1032; + N = n/M; + + if ( (sequence = (BitSequence *) calloc(m, sizeof(BitSequence))) == NULL ) { + return 0; + } + else { + for (i = 0; i < m; i++) + sequence[i] = 1; + } + + lambda = (double)(M-m+1)/pow(2,m); + eta = lambda/2.0; + sum = 0.0; + for ( i=0; i +#include +#include "include/stat_fncs.h" +#include "include/cephes.h" + +typedef struct _PokerNi { + unsigned int flag; + unsigned int count; +} PokerNi; + +unsigned char toByte(BitSequence *subEpsilon, int M) +{ + int i = 0; + unsigned char result = 0; + for (i = 0; i < M; ++i) { + result |= (subEpsilon[i] << (M - i - 1)); + } + return result; +} + +int findIndex(PokerNi *tab, int tabSize, unsigned int flag) +{ + int i = 0; + for (i = 0; i < tabSize; ++i) { + if (tab[i].flag == flag) { + return i; + } + } + return -1; +} + +int PokerDetect(int M, int n, BitSequence *epsilon) +{ + int ret = 0; + int i = 0, j = 0, N = n / M, index = 0, c = 0; + int maxElements = (int) pow(2, M); + double p_value = 0.0, sum_ni = 0.0, mp = 0.0, V = 0.0; + unsigned int flag = 0; + PokerNi *tab = NULL; + + if (M > 8) { + return 0; + } + + tab = (PokerNi *)calloc(maxElements, sizeof(PokerNi)); + if (NULL == tab) { + return 0; + } + for (i = 0; i < maxElements; ++i) { + tab[i].flag = (unsigned int) i; + tab[i].count = 0; + } + + for (i = 0, j = 0; j < N; ++j, i += M) { + flag = toByte(epsilon + i, M); + index = findIndex(tab, maxElements, flag); + if (-1 == index) { + goto end; + } + tab[index].count += 1; + } + + for (i = 0; i < maxElements; ++i) { + sum_ni += pow(tab[i].count, 2); + } + mp = (double)maxElements / N; + V = mp * sum_ni - N; + + p_value = cephes_igamc((double)(maxElements - 1) / 2, V / 2); + if (p_value < ALPHA) { + goto end; + } + + ret = 1; + + end: + free(tab); + return ret; +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/src/randomExcursions.c b/decoders/session_flags/mesa_sts/src/randomExcursions.c new file mode 100644 index 0000000..135396d --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/randomExcursions.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N D O M E X C U R S I O N S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +RandomExcursions(int n, BitSequence *epsilon) +{ + int ret = 0; + int b, i, j, k, J, x; + int cycleStart, cycleStop, *cycle = NULL, *S_k = NULL; + const int stateX[8] = { -4, -3, -2, -1, 1, 2, 3, 4 }; + int counter[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + double p_value, sum, constraint, nu[6][8]; + double pi[5][6] = { {0.0000000000, 0.00000000000, 0.00000000000, 0.00000000000, 0.00000000000, 0.0000000000}, + {0.5000000000, 0.25000000000, 0.12500000000, 0.06250000000, 0.03125000000, 0.0312500000}, + {0.7500000000, 0.06250000000, 0.04687500000, 0.03515625000, 0.02636718750, 0.0791015625}, + {0.8333333333, 0.02777777778, 0.02314814815, 0.01929012346, 0.01607510288, 0.0803755143}, + {0.8750000000, 0.01562500000, 0.01367187500, 0.01196289063, 0.01046752930, 0.0732727051} }; + + if ( ((S_k = (int *)calloc(n, sizeof(int))) == NULL) || + ((cycle = (int *)calloc(MAX(1000, n/100), sizeof(int))) == NULL) ) { + printf("Random Excursions Test: Insufficent Work Space Allocated.\n"); + if ( S_k != NULL ) + free(S_k); + if ( cycle != NULL ) + free(cycle); + return 0; + } + + J = 0; /* DETERMINE CYCLES */ + S_k[0] = 2*(int)epsilon[0] - 1; + for( i=1; i MAX(1000, n/100) ) { + printf("ERROR IN FUNCTION randomExcursions: EXCEEDING THE MAX NUMBER OF CYCLES EXPECTED\n."); + goto end; + } + cycle[J] = i; + } + } + if ( S_k[n-1] != 0 ) + J++; + cycle[J] = n; + + constraint = MAX(0.005*pow(n, 0.5), 500); + if (J < constraint) { + ret = 1; //TODO + goto end; + } + else { + cycleStart = 0; + cycleStop = cycle[1]; + for ( k=0; k<6; k++ ) + for ( i=0; i<8; i++ ) + nu[k][i] = 0.; + for ( j=1; j<=J; j++ ) { /* FOR EACH CYCLE */ + for ( i=0; i<8; i++ ) + counter[i] = 0; + for ( i=cycleStart; i= 1 && S_k[i] <= 4) || (S_k[i] >= -4 && S_k[i] <= -1) ) { + if ( S_k[i] < 0 ) + b = 4; + else + b = 3; + counter[S_k[i]+b]++; + } + } + cycleStart = cycle[j]+1; + if ( j < J ) + cycleStop = cycle[j+1]; + + for ( i=0; i<8; i++ ) { + if ( (counter[i] >= 0) && (counter[i] <= 4) ) + nu[counter[i]][i]++; + else if ( counter[i] >= 5 ) + nu[5][i]++; + } + } + + for ( i=0; i<8; i++ ) { + x = stateX[i]; + sum = 0.; + for ( k=0; k<6; k++ ) + sum += pow(nu[k][i] - J*pi[(int)fabs(x)][k], 2) / (J*pi[(int)fabs(x)][k]); + p_value = cephes_igamc(2.5, sum/2.0); + + if ( isNegative(p_value) || isGreaterThanOne(p_value) ) { +// fprintf(stats[TEST_RND_EXCURSION], "WARNING: P_VALUE IS OUT OF RANGE.\n"); + goto end; + } + +// fprintf(stats[TEST_RND_EXCURSION], "%s\t\tx = %2d chi^2 = %9.6f p_value = %f\n", +// p_value < ALPHA ? "FAILURE" : "SUCCESS", x, sum, p_value); +// fprintf(results[TEST_RND_EXCURSION], "%f\n", p_value); fflush(results[TEST_RND_EXCURSION]); + if (p_value < ALPHA) { + goto end; + } + } + } +// fprintf(stats[TEST_RND_EXCURSION], "\n"); fflush(stats[TEST_RND_EXCURSION]); + ret = 1; + + end: + free(S_k); + free(cycle); + return ret; +} diff --git a/decoders/session_flags/mesa_sts/src/randomExcursionsVariant.c b/decoders/session_flags/mesa_sts/src/randomExcursionsVariant.c new file mode 100644 index 0000000..447ddf6 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/randomExcursionsVariant.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N D O M E X C U R S I O N S V A R I A N T T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +RandomExcursionsVariant(int n, BitSequence *epsilon) +{ + int ret = 0; + int i, p, J, x, constraint, count, *S_k = NULL; + const int stateX[18] = { -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + double p_value; + + if ( (S_k = (int *)calloc(n, sizeof(int))) == NULL ) { + return 0; + } + J = 0; + S_k[0] = 2*(int)epsilon[0] - 1; + for ( i=1; i +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" +#include "include/matrix.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R A N K T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Rank(int n, BitSequence *epsilon) +{ + int ret = 0; + int N, i, k, r; + double p_value, product, chi_squared, arg1, p_32, p_31, p_30, R, F_32, F_31, F_30; + BitSequence **matrix = create_matrix(32, 32); + + N = n/(32*32); + if ( isZero(N) ) { + p_value = 0.00; + } + else { + r = 32; /* COMPUTE PROBABILITIES */ + product = 1; + for ( i=0; i<=r-1; i++ ) + product *= ((1.e0-pow(2, i-32))*(1.e0-pow(2, i-32)))/(1.e0-pow(2, i-r)); + p_32 = pow(2, r*(32+32-r)-32*32) * product; + + r = 31; + product = 1; + for ( i=0; i<=r-1; i++ ) + product *= ((1.e0-pow(2, i-32))*(1.e0-pow(2, i-32)))/(1.e0-pow(2, i-r)); + p_31 = pow(2, r*(32+32-r)-32*32) * product; + + p_30 = 1 - (p_32+p_31); + + F_32 = 0; + F_31 = 0; + for ( k=0; k +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + R U N S T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Runs(int n, BitSequence *epsilon) +{ + int S, k; + double pi, V, erfc_arg, p_value; + + S = 0; + for ( k=0; k (2.0 / sqrt(n)) ) { + p_value = 0.0; + } + else { + + V = 1; + for ( k=1; k +#include +#include "include/stat_fncs.h" +#include "include/cephes.h" + +int RunsDistribution(int n, BitSequence *epsilon) +{ + int ret = 0; + int i = 0, j = 0, k = 0; + unsigned char runFlag = 0x00; + double p_value = 0.0, sum_bi = 0.0, sum_gi = 0.0, V = 0.0; + double *bi = NULL, *gi = NULL, *e = NULL; + double bit = 0.0, git = 0.0, et = 0.0; + + bi = (double *)calloc(n, sizeof(double)); + if (NULL == bi) { + goto end; + } + gi = (double *)calloc(n, sizeof(double)); + if (NULL == gi) { + goto end; + } + e = (double *)calloc(n, sizeof(double)); + if (NULL == e) { + goto end; + } + + for (i = 1; i <= n; ++i) { + e[i - 1] = (double)(n - i + 3) / pow(2, i + 2); + if (e[i - 1] >= 5) { + k = i; + } + } + + runFlag = epsilon[0]; + j = 1; + for (i = 1; i < n; ++i) { + if (epsilon[i] != runFlag) { + if (runFlag == 0x00) { + gi[j - 1] += 1; + } else if (runFlag == 0x01) { + bi[j - 1] += 1; + } + runFlag = epsilon[i]; + j = 1; + } else { + ++j; + } + } + + for (i = 0; i < k; ++i) { + bit = bi[i]; + et = e[i]; + sum_bi += pow(bit - et, 2) / et; + } + for (i = 0; i < k; ++i) { + git = gi[i]; + et = e[i]; + sum_gi += pow(git - et, 2) / et; + } + V = sum_bi + sum_gi; + + p_value = cephes_igamc(k - 1, V / 2); + if (p_value < ALPHA) { + goto end; + } + + ret = 1; + + end: + if (NULL != bi) { + free(bi); + } + if (NULL != gi) { + free(gi); + } + if (NULL != e) { + free(e); + } + return ret; +} + diff --git a/decoders/session_flags/mesa_sts/src/selfCorrelation.c b/decoders/session_flags/mesa_sts/src/selfCorrelation.c new file mode 100644 index 0000000..d47a67b --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/selfCorrelation.c @@ -0,0 +1,25 @@ +#include +#include "include/stat_fncs.h" + +int SelfCorrelation(int d, int n, BitSequence *epsilon) +{ + int i = 0; + int n_d = n - d; + int Ad = 0; + double V = 0.0, p_value = 0.0, sqrt2 = 1.41421356237309504880; + + for (i = 0; i < n_d - 1; ++i) { + Ad += (epsilon[i] ^ epsilon[i + d]); + } + + V = 2 * ((double)Ad - ((double)n_d / 2)) / sqrt(n_d); + + p_value = erfc(fabs(V) / sqrt2); + + if (p_value < ALPHA) { + return 0; + } else { + return 1; + } +} + diff --git a/decoders/session_flags/mesa_sts/src/serial.c b/decoders/session_flags/mesa_sts/src/serial.c new file mode 100644 index 0000000..3d37272 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/serial.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +double psi2(int m, int n, BitSequence *epsilon); + +int +Serial(int m, int n, BitSequence *epsilon) +{ + double p_value1, p_value2, psim0, psim1, psim2, del1, del2; + + psim0 = psi2(m, n, epsilon); + psim1 = psi2(m - 1, n, epsilon); + psim2 = psi2(m - 2, n, epsilon); + del1 = psim0 - psim1; + del2 = psim0 - 2.0*psim1 + psim2; + p_value1 = cephes_igamc(pow(2, m-1)/2, del1/2.0); + p_value2 = cephes_igamc(pow(2, m-2)/2, del2/2.0); + + if (p_value1 < ALPHA || p_value2 < ALPHA) { + return 0; + } else { + return 1; + } +} + +double +psi2(int m, int n, BitSequence *epsilon) +{ + int i, j, k, powLen; + double sum, numOfBlocks; + unsigned int *P; + + if ( (m == 0) || (m == -1) ) + return 0.0; + numOfBlocks = n; + powLen = (int)pow(2, m+1)-1; + if ( (P = (unsigned int*)calloc(powLen,sizeof(unsigned int)))== NULL ) { +// fprintf(stats[TEST_SERIAL], "Serial Test: Insufficient memory available.\n"); +// fflush(stats[TEST_SERIAL]); + return 0.0; + } + for ( i=1; i +#include +#include +#include +#include "include/externs.h" +#include "include/cephes.h" + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + U N I V E R S A L T E S T + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +int +Universal(int n, BitSequence *epsilon) +{ + int ret = 0; + int i, j, p, L, Q, K; + double arg, sqrt2, sigma, phi, sum, p_value, c; + long *T, decRep; + const double expected_value[17] = { 0, 0, 0, 0, 0, 0, 5.2177052, 6.1962507, 7.1836656, + 8.1764248, 9.1723243, 10.170032, 11.168765, + 12.168070, 13.167693, 14.167488, 15.167379 }; + const double variance[17] = { 0, 0, 0, 0, 0, 0, 2.954, 3.125, 3.238, 3.311, 3.356, 3.384, + 3.401, 3.410, 3.416, 3.419, 3.421 }; + + /* * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * THE FOLLOWING REDEFINES L, SHOULD THE CONDITION: n >= 1010*2^L*L * + * NOT BE MET, FOR THE BLOCK LENGTH L. * + * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + L = 5; + if ( n >= 387840 ) L = 6; + if ( n >= 904960 ) L = 7; + if ( n >= 2068480 ) L = 8; + if ( n >= 4654080 ) L = 9; + if ( n >= 10342400 ) L = 10; + if ( n >= 22753280 ) L = 11; + if ( n >= 49643520 ) L = 12; + if ( n >= 107560960 ) L = 13; + if ( n >= 231669760 ) L = 14; + if ( n >= 496435200 ) L = 15; + if ( n >= 1059061760 ) L = 16; + + Q = 10*(int)pow(2, L); + K = (int) (floor(n/L) - (double)Q); /* BLOCKS TO TEST */ + + p = (int)pow(2, L); + if ( (L < 6) || (L > 16) || ((double)Q < 10*pow(2, L)) || + ((T = (long *)calloc(p, sizeof(long))) == NULL) ) { + return 0; + } + + /* COMPUTE THE EXPECTED: Formula 16, in Marsaglia's Paper */ + c = 0.7 - 0.8/(double)L + (4 + 32/(double)L)*pow(K, -3/(double)L)/15; + sigma = c * sqrt(variance[L]/(double)K); + sqrt2 = sqrt(2); + sum = 0.0; + for ( i=0; i +#include +#include +#include +#include "include/utilities.h" + +int +convertToBits(BYTE *x, int xBitLength, int bitsNeeded, int *num_0s, int *num_1s, int *bitsRead, BitSequence* epsilon) +{ + int i, j, count, bit; + BYTE mask; + int zeros, ones; + + count = 0; + zeros = ones = 0; + for ( i=0; i<(xBitLength+7)/8; i++ ) { + mask = 0x80; + for ( j=0; j<8; j++ ) { + if ( *(x+i) & mask ) { + bit = 1; + (*num_1s)++; + ones++; + } + else { + bit = 0; + (*num_0s)++; + zeros++; + } + mask >>= 1; + epsilon[*bitsRead] = bit; + (*bitsRead)++; + if ( *bitsRead == bitsNeeded ) + return 1; + if ( ++count == xBitLength ) + return 0; + } + } + + return 0; +} + diff --git a/decoders/session_flags/mesa_sts/src/version.map b/decoders/session_flags/mesa_sts/src/version.map new file mode 100644 index 0000000..ea17166 --- /dev/null +++ b/decoders/session_flags/mesa_sts/src/version.map @@ -0,0 +1,6 @@ +{ + global: + statistical_test_suite; + GIT_VERSION*; + local: *; +}; \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/test/CMakeLists.txt b/decoders/session_flags/mesa_sts/test/CMakeLists.txt new file mode 100644 index 0000000..f4e7678 --- /dev/null +++ b/decoders/session_flags/mesa_sts/test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required (VERSION 3.5) + +add_executable(gtest_mesa gtest_mesa_sts.cpp) +target_link_libraries(gtest_mesa gtest pcap pthread libmesa_sts) + +file(COPY pcap DESTINATION ./) diff --git a/decoders/session_flags/mesa_sts/test/gtest_mesa_sts.cpp b/decoders/session_flags/mesa_sts/test/gtest_mesa_sts.cpp new file mode 100644 index 0000000..2d9658f --- /dev/null +++ b/decoders/session_flags/mesa_sts/test/gtest_mesa_sts.cpp @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "mesa_sts.h" + +#define MAX_PKT_CNT 1 + +static int read_pcap_and_judge_randomness(const char* pcap_file, struct sts_result* result) +{ + pcap_t *handle; + struct pcap_pkthdr *header; // pcap报文头部结构 + const u_char *packet; // 报文数据指针 + char errbuf[PCAP_ERRBUF_SIZE]; + char content[2048] = {0}; + int content_len = 0; + int payload_len; + char *payload; + int pkt_cnt = 0; + + handle = pcap_open_offline(pcap_file, errbuf); + while (pcap_next_ex(handle, &header, &packet) > 0) { + unsigned short eth_type = ntohs(*(unsigned short *)(packet + 12)); + if (eth_type == ETH_P_IP) { + int l4_proto = *(unsigned char *)(packet + sizeof(struct ethhdr) + 9); + if (l4_proto == IPPROTO_TCP) { + int tcp_header_len = (*(unsigned char *)(packet + sizeof(struct ethhdr) + sizeof(struct iphdr) + 12) & 0xf0) >> 2; + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct iphdr) - tcp_header_len; + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct iphdr) + tcp_header_len; + } else if (l4_proto == IPPROTO_UDP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct iphdr) - sizeof(struct udphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr); + } else { + continue; + } + + } else if (eth_type == ETH_P_IPV6) { + int l4_proto = *(unsigned char *)(packet + sizeof(struct ethhdr) + 6); + if (l4_proto == IPPROTO_TCP) { + int tcp_header_len = (*(unsigned char *)(packet + sizeof(struct ethhdr) + sizeof(struct ip6_hdr) + 12) & 0xf0) >> 2; + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct ip6_hdr) - tcp_header_len; + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct ip6_hdr) + tcp_header_len; + } else if (l4_proto == IPPROTO_UDP) { + payload_len = header->caplen - sizeof(struct ethhdr) - sizeof(struct ip6_hdr) - sizeof(struct udphdr); + payload = (char *)packet + sizeof(struct ethhdr) + sizeof(struct ip6_hdr) + sizeof(struct udphdr); + } else { + continue; + } + } + + if (payload_len < 100) { + continue; + } + + memcpy(content + content_len, payload, payload_len); + content_len += payload_len; + pkt_cnt++; + if (pkt_cnt == MAX_PKT_CNT) { + break; + } + } + + mesa_statistical_test_suite(content, content_len, result, 0xffffffff); + + pcap_close(handle); + + return 0; +} + +TEST(random_looking, telegram_mtproto_ipv4_key1) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_1.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv4_key2) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_2_dd.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv4_key3) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv4_key_3_ee.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 0); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key1) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_1.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key2) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_2_dd.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(random_looking, telegram_mtproto_ipv6_key3) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/telegram_mtproto_ipv6_key_3_ee.pcap", &result); + + EXPECT_EQ(result.frequency, 1); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 1); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 1); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 1); + EXPECT_EQ(result.self_correlation, 1); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(non_random_looking, wechat_voice_call) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap", &result); + + EXPECT_EQ(result.frequency, 0); + EXPECT_EQ(result.block_frequency, 1); + EXPECT_EQ(result.cumulative_sums, 0); + EXPECT_EQ(result.runs, 0); + EXPECT_EQ(result.longest_run, 0); + EXPECT_EQ(result.rank, 0); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 1); + EXPECT_EQ(result.runs_distribution, 0); + EXPECT_EQ(result.self_correlation, 0); + EXPECT_EQ(result.binary_derivative, 1); +} + +TEST(non_random_looking, http) +{ + struct sts_result result; + read_pcap_and_judge_randomness("pcap/xingongsuo_kouling_http_C2S.pcap", &result); + + EXPECT_EQ(result.frequency, 0); + EXPECT_EQ(result.block_frequency, 0); + EXPECT_EQ(result.cumulative_sums, 0); + EXPECT_EQ(result.runs, 1); + EXPECT_EQ(result.longest_run, 0); + EXPECT_EQ(result.rank, 1); + EXPECT_EQ(result.non_overlapping_template_matching, 0); + EXPECT_EQ(result.overlapping_template_matching, 1); + EXPECT_EQ(result.universal, 0); + EXPECT_EQ(result.random_excursions, 1); + EXPECT_EQ(result.random_excursions_variant, 1); + EXPECT_EQ(result.poker_detect, 0); + EXPECT_EQ(result.runs_distribution, 0); + EXPECT_EQ(result.self_correlation, 0); + EXPECT_EQ(result.binary_derivative, 1); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + //testing::GTEST_FLAG(filter) = "random_looking.telegram_mtproto_ipv6_key1"; + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/decoders/session_flags/mesa_sts/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap b/decoders/session_flags/mesa_sts/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap new file mode 100644 index 0000000..63787b7 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/202202161604_win_wifi_30M_pure_wechat_wechat3.5.0.46_voice-call_120s_2_multinat.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_1.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_1.pcap new file mode 100644 index 0000000..7b966dd Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_1.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap new file mode 100644 index 0000000..59eb480 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_2_dd.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap new file mode 100644 index 0000000..8c70a1b Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv4_key_3_ee.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_1.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_1.pcap new file mode 100644 index 0000000..e0b3144 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_1.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap new file mode 100644 index 0000000..0659281 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_2_dd.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap new file mode 100644 index 0000000..03a3678 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/telegram_mtproto_ipv6_key_3_ee.pcap differ diff --git a/decoders/session_flags/mesa_sts/test/pcap/xingongsuo_kouling_http_C2S.pcap b/decoders/session_flags/mesa_sts/test/pcap/xingongsuo_kouling_http_C2S.pcap new file mode 100644 index 0000000..cd05da7 Binary files /dev/null and b/decoders/session_flags/mesa_sts/test/pcap/xingongsuo_kouling_http_C2S.pcap differ diff --git a/decoders/session_flags/onlinemean.c b/decoders/session_flags/onlinemean.c new file mode 100644 index 0000000..aeb7427 --- /dev/null +++ b/decoders/session_flags/onlinemean.c @@ -0,0 +1,37 @@ +#include +#include "onlinemean.h" + +void OnlineMean_Init(OnlineMean_t *oMean) { + OnlineMean_Reset(oMean); +} + +void OnlineMean_Update(OnlineMean_t *oMean, float newValue) { + oMean->count++; + if (oMean->count > 1) { + float delta = newValue - oMean->mean; + oMean->mean += delta / oMean->count; + oMean->varsum += delta * (newValue - oMean->mean); + } else { + oMean->mean = newValue; + } +} + +float OnlineMean_GetMean(OnlineMean_t *oMean) { + return oMean->mean; +} + +float OnlineMean_GetStd(OnlineMean_t *oMean) { + if (oMean->count == 0) + return 0; +#if UNBIASED_ESTIMATOR + return sqrt(oMean->varsum / (oMean->count - 1)); +#else + return sqrt(oMean->varsum / oMean->count); +#endif /* UNBIASED_ESTIMATOR */ +} + +void OnlineMean_Reset(OnlineMean_t *oMean) { + oMean->count = 0; + oMean->mean = 0.f; + oMean->varsum = 0.f; +} diff --git a/decoders/session_flags/onlinemean.h b/decoders/session_flags/onlinemean.h new file mode 100644 index 0000000..6cb5c95 --- /dev/null +++ b/decoders/session_flags/onlinemean.h @@ -0,0 +1,30 @@ +#ifndef ONLINEMEAN_H_ +#define ONLINEMEAN_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Set to 1 to return unbiased (sample) variance + * rather than a population variance */ +#define UNBIASED_ESTIMATOR 0 + +#include + +typedef struct OnlineMean { + float mean; + float varsum; // variance sum + uint32_t count; +} OnlineMean_t; + +void OnlineMean_Init(OnlineMean_t *oMean); +void OnlineMean_Update(OnlineMean_t *oMean, float newValue); +float OnlineMean_GetMean(OnlineMean_t *oMean); +float OnlineMean_GetStd(OnlineMean_t *oMean); +void OnlineMean_Reset(OnlineMean_t *oMean); + +#ifdef __cplusplus +} +#endif + +#endif /* ONLINEMEAN_H_ */ diff --git a/decoders/session_flags/session_flags.cpp b/decoders/session_flags/session_flags.cpp new file mode 100644 index 0000000..6f7443f --- /dev/null +++ b/decoders/session_flags/session_flags.cpp @@ -0,0 +1,824 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onlinemean.h" +#include "session_flags_internal.h" +#include "fet.h" +#include "stellar/stellar.h" +#include "mesa_sts.h" +#include "stellar/session.h" +#include "stellar/log.h" + +#define SESSION_BUKLY_THRESHORD 0.95 +#define SESSION_DOWNLOAD_THRESHORD 0.95 +#define SESSION_CBR_STREAMING_THRESHORD 0.15 +#define SESSION_STREAMING_THRESHORD 0.86 +#define SESSION_PSEUDO_UNIDIRECTIONA_THRESHORD 0.95 +#define SESSION_INTERACTIVE_THRESHORD 0.7 + +#define SESSION_BIDIRECTIONAL_THRESHORD_MIN 0.7 +#define SESSION_BIDIRECTIONAL_THRESHORD_MAX 1.43 +#define SESSION_EWMA_FACTOR 0.9 + + +#define SESSION_RANDOM_LOOKING_PAYLOAD_LEN_MIN 100 + +#define SESSION_ITER_INTERVAL_MS 1000 +#define SESSION_EWMA_ITER_CNT_MIN 5 + +#define LARGE_PKT_SIZE_MIN 600 +#define LARGE_PKT_SIZE_MAX 1400 + +#define SESSION_FLAGS_IDENTIFY_STR_LEN 256 + +extern struct session_flags_init_conf g_sf_conf; + +extern uint32_t sts_random_switch; + +thread_local OnlineMean_t g_large_pkt_omean = { + .mean = 0, + .varsum = 0, + .count = 0 +};//record the mean and std of packet size, to calculate large packet size +thread_local uint64_t g_large_pkt_size_update_ms = 0; +thread_local uint32_t g_large_pkt_size = 0; +#define LARGE_PKT_SIZE_UPDATE_COUNT_MIN 10000 +#define LARGE_PKT_SIZE_UPDATE_INTERVAL_MS 10000 + +static void session_flags_calculate_local(struct session_flags_stat *stat, enum session_direction session_dir) +{ + if (session_dir == SESSION_DIRECTION_INBOUND) + { + stat->result.flags |= SESSION_FLAGS_LOCAL_SERVER; + stat->result.identify[session_flags_local_server_mask] = 1; + } + else + { + stat->result.flags |= SESSION_FLAGS_LOCAL_CLIENT; + stat->result.identify[session_flags_local_client_mask] = 1; + } + + return; +} + +void session_flags_stat_init(struct session_flags_stat *stat, enum session_direction session_dir) +{ + session_flags_calculate_local(stat, session_dir); + + OnlineMean_Init(&stat->iter.c2s.omean); + OnlineMean_Init(&stat->iter.s2c.omean); + + stat->main_dir = MAIN_DIR_UNKONWN; + + return; +}; + +static void session_flags_EWMA_iter(float *ori_value, float iter_value) +{ + float temp = *ori_value; + + if (temp == 0) + { + temp = iter_value; + } + else + { + temp = SESSION_EWMA_FACTOR * temp + (1 - SESSION_EWMA_FACTOR) * iter_value; + } + + *ori_value = temp; +} + +static void session_flags_calculate_pseudo_unidirection(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL) + return ; + + float c2s_ratio, s2c_ratio; + float pseudo_unidirectional; + uint64_t delta_payload_pkts = stat->c2s.delta_payload_pkts + stat->s2c.delta_payload_pkts; + + if (delta_payload_pkts == 0) + { + return; + } + + c2s_ratio = stat->c2s.delta_payload_pkts * 1.f / delta_payload_pkts; + s2c_ratio = stat->s2c.delta_payload_pkts * 1.f / delta_payload_pkts; + + session_flags_EWMA_iter(&stat->iter.c2s.pseudo_unidirectional, c2s_ratio); + session_flags_EWMA_iter(&stat->iter.s2c.pseudo_unidirectional, s2c_ratio); + + if (stat->iter.iter_cnt < SESSION_EWMA_ITER_CNT_MIN || stat->main_dir == MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->main_dir == FLOW_TYPE_C2S) + { + pseudo_unidirectional = stat->iter.c2s.pseudo_unidirectional; + } + else + { + pseudo_unidirectional = stat->iter.s2c.pseudo_unidirectional; + } + + if (pseudo_unidirectional > SESSION_PSEUDO_UNIDIRECTIONA_THRESHORD) + { + stat->result.flags |= SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL; + stat->result.identify[session_flags_pseudo_unidirectional_mask] = all_pkts; + } +} + +static void session_flags_calculate_unidirection(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_UNIDIRECTIONAL || stat->s2c.pkts == 0 || stat->c2s.pkts == 0) + return ; + + if (stat->c2s.payload_pkts == 0 || stat->s2c.payload_pkts == 0) + { + stat->result.flags |= SESSION_FLAGS_UNIDIRECTIONAL; + stat->result.identify[session_flags_unidirectional_mask] = all_pkts; + } +} + +static void session_flags_calculate_streaming(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_STREAMING) + return; + + float c2s_ratio, s2c_ratio; + float streaming; + uint64_t delta_bytes = stat->c2s.delta_bytes + stat->s2c.delta_bytes; + + if (delta_bytes == 0) + { + return; + } + + c2s_ratio = stat->c2s.delta_bytes * 1.f / delta_bytes; + s2c_ratio = stat->s2c.delta_bytes * 1.f / delta_bytes; + + session_flags_EWMA_iter(&stat->iter.c2s.streaming, c2s_ratio); + session_flags_EWMA_iter(&stat->iter.s2c.streaming, s2c_ratio); + + if (stat->iter.iter_cnt < SESSION_EWMA_ITER_CNT_MIN || stat->main_dir == MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->main_dir == FLOW_TYPE_C2S) + { + streaming = stat->iter.c2s.streaming; + } + else + { + streaming = stat->iter.s2c.streaming; + } + + if (streaming > SESSION_STREAMING_THRESHORD) + { + stat->result.flags |= SESSION_FLAGS_STREAMING; + stat->result.identify[session_flags_streaming_mask] = all_pkts; + } +} + +static void session_flags_calculate_download(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_DOWNLOAD) + return ; + + float c2s_ratio, s2c_ratio; + float download; + uint64_t delta_payload_pkts = stat->c2s.delta_payload_pkts + stat->s2c.delta_payload_pkts; + + if (delta_payload_pkts == 0) + { + return; + } + + c2s_ratio = stat->c2s.delta_large_pkts * 1.f / delta_payload_pkts; + s2c_ratio = stat->s2c.delta_large_pkts * 1.f / delta_payload_pkts; + + session_flags_EWMA_iter(&stat->iter.c2s.download, c2s_ratio); + session_flags_EWMA_iter(&stat->iter.s2c.download, s2c_ratio); + + if (stat->iter.iter_cnt < SESSION_EWMA_ITER_CNT_MIN || stat->main_dir == MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->main_dir == FLOW_TYPE_C2S) + { + download = stat->iter.c2s.download; + } + else + { + download = stat->iter.s2c.download; + } + + if (download > SESSION_DOWNLOAD_THRESHORD) + { + stat->result.flags |= SESSION_FLAGS_DOWNLOAD; + stat->result.identify[session_flags_download_mask] = all_pkts; + } +} + +static void session_flags_calculate_bulky(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_BULKY) + return ; + + float bulky; + + if (stat->c2s.delta_pkts != 0) + { + float c2s_ratio; + c2s_ratio = stat->c2s.delta_large_pkts * 1.f / stat->c2s.delta_pkts; + session_flags_EWMA_iter(&stat->iter.c2s.bulky, c2s_ratio); + } + + if (stat->s2c.delta_pkts != 0) + { + float s2c_ratio; + s2c_ratio = stat->s2c.delta_large_pkts * 1.f / stat->s2c.delta_pkts; + session_flags_EWMA_iter(&stat->iter.s2c.bulky, s2c_ratio); + } + + if (stat->iter.iter_cnt < SESSION_EWMA_ITER_CNT_MIN || stat->main_dir == MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->main_dir == FLOW_TYPE_C2S) + { + bulky = stat->iter.c2s.bulky; + } + else + { + bulky = stat->iter.s2c.bulky; + } + + if (bulky > SESSION_BUKLY_THRESHORD) + { + stat->result.flags |= SESSION_FLAGS_BULKY; + stat->result.identify[session_flags_bulky_mask] = all_pkts; + } +} + +static void flow_stat_update(struct session *session, struct flow_stat *flow, uint64_t bytes) +{ + flow->bytes += bytes; + flow->pkts++; + + flow->delta_pkts++; + flow->delta_bytes += bytes; + + const struct packet *pkt = session_get0_current_packet(session); + size_t payload_len = packet_get_payload_len(pkt); + + if (payload_len > 0) + { + flow->payload_pkts++; + flow->delta_payload_pkts++; + } + + if (bytes > g_large_pkt_size) + { + flow->large_pkts++; + flow->delta_large_pkts++; + } + + return; +} + +static void session_flags_calculate_main_dir(struct session_flags_stat *stat) +{ + if (stat->main_dir != MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->c2s.bytes > stat->s2c.bytes) + { + stat->main_dir = FLOW_TYPE_C2S; + } + else + { + stat->main_dir = FLOW_TYPE_S2C; + } +} + +float session_flags_calculate_CV(OnlineMean_t * omean) +{ + float CV = -1.f; + float mean = OnlineMean_GetMean(omean); + if (mean!= 0) + { + CV = OnlineMean_GetStd(omean) / mean; + } + // printf("CV:%lf\n", CV); + return CV; +} + +static void session_flags_calculate_CBR(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_CBR) + return; + + float CBR; + + OnlineMean_Update(&stat->iter.c2s.omean, stat->c2s.rate); + OnlineMean_Update(&stat->iter.s2c.omean, stat->s2c.rate); + + stat->iter.c2s.CBR = session_flags_calculate_CV(&stat->iter.c2s.omean); + stat->iter.s2c.CBR = session_flags_calculate_CV(&stat->iter.s2c.omean); + + if (stat->main_dir == MAIN_DIR_UNKONWN) + { + return; + } + + if (stat->main_dir == FLOW_TYPE_C2S) + { + CBR = stat->iter.c2s.CBR; + } + else + { + CBR = stat->iter.s2c.CBR; + } + + if (CBR < SESSION_CBR_STREAMING_THRESHORD && CBR > 0.0) + { + stat->result.flags |= SESSION_FLAGS_CBR; + stat->result.identify[session_flags_cbr_mask] = all_pkts; + } +} + +static void session_flags_calculate_interactive(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_INTERACTIVE || stat->c2s.pkts == 0 || stat->s2c.pkts == 0) + return; + + if (stat->stream_live_time_ms > g_sf_conf.interactive_starttime_ms && stat->interactive_pulse_num > g_sf_conf.interactive_pulse_num) + { + stat->result.flags |= SESSION_FLAGS_INTERACTIVE; + stat->result.identify[session_flags_interactive_mask] = all_pkts; + } +} + +static void session_flags_calculate_interactive_pulse(struct session_flags_stat *stat, uint64_t cur_ms, uint64_t all_pkts) +{ + uint64_t delta_ms = 0; + if (cur_ms > stat->last_pkt_ts_ms) + { + delta_ms = cur_ms - stat->last_pkt_ts_ms; + } + + if (delta_ms > g_sf_conf.interactive_latency_ms) + { + stat->interactive_pulse_num++; + session_flags_calculate_interactive(stat, all_pkts); + } +} + +static void session_flags_calculate_bound(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat == NULL || stat->c2s.pkts == 0 || stat->s2c.pkts == 0) + { + return; + } + + if (!(stat->result.flags & SESSION_FLAGS_INBOUND) && !(stat->result.flags & SESSION_FLAGS_OUTBOUND)) + { + if (stat->result.flags & SESSION_FLAGS_LOCAL_CLIENT) + { + if (stat->main_dir == FLOW_TYPE_C2S) + { + stat->result.flags |= SESSION_FLAGS_OUTBOUND; + stat->result.identify[session_flags_outbound_mask] = all_pkts; + } + else + { + stat->result.flags |= SESSION_FLAGS_INBOUND; + stat->result.identify[session_flags_inbound_mask] = all_pkts; + } + } + else + { + if (stat->main_dir == FLOW_TYPE_C2S) + { + stat->result.flags |= SESSION_FLAGS_INBOUND; + stat->result.identify[session_flags_inbound_mask] = all_pkts; + } + else + { + stat->result.flags |= SESSION_FLAGS_OUTBOUND; + stat->result.identify[session_flags_outbound_mask] = all_pkts; + } + } + } +} + +static void session_flags_calculate_dir(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->c2s.pkts != 0 && !(stat->result.flags & SESSION_FLAGS_C2S)) + { + stat->result.flags |= SESSION_FLAGS_C2S; + stat->result.identify[session_flags_c2s_mask] = all_pkts; + } + if (stat->s2c.pkts != 0 && !(stat->result.flags & SESSION_FLAGS_S2C)) + { + stat->result.flags |= SESSION_FLAGS_S2C; + stat->result.identify[session_flags_s2c_mask] = all_pkts; + } +} + +static void session_flags_calculate_bidirectional(struct session_flags_stat *stat, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_BIDIRECTIONAL) + { + return; + } + + float rate_ratio = stat->c2s.rate / stat->s2c.rate; + if (stat->iter.bidirectional == 0) + { + stat->iter.bidirectional = rate_ratio; + } + else + {//EWMA + stat->iter.bidirectional = SESSION_EWMA_FACTOR * stat->iter.bidirectional + (1 - SESSION_EWMA_FACTOR) * rate_ratio; + } + + if (stat->iter.iter_cnt >= SESSION_EWMA_ITER_CNT_MIN) + { + if (stat->iter.bidirectional > SESSION_BIDIRECTIONAL_THRESHORD_MIN && stat->iter.bidirectional < SESSION_BIDIRECTIONAL_THRESHORD_MAX) + { + stat->result.flags |= SESSION_FLAGS_BIDIRECTIONAL; + stat->result.identify[session_flags_bidirectional_mask] = all_pkts; + } + } + + return; +} + +static void session_flags_calculate_randomness_by_fet(struct session_flags_stat *stat, size_t payload_len, const char *payload, uint64_t all_pkts) +{ + if (stat->random_looking_stat.has_judged_fet) + { + return; + } + + stat->random_looking_stat.has_judged_fet = 1; + + if (g_sf_conf.fet_enabled) + { + struct fet_detail detail; + int is_fet = is_data_fet((unsigned char *)payload, payload_len, &detail); + + stat->result.is_tls = detail.is_tls; + + if (is_fet) + {//if payload is fet data, then it is definitely random looking + stat->result.flags |= SESSION_FLAGS_RANDOM_LOOKING; + stat->result.identify[session_flags_random_looking_mask] = all_pkts; + } + } + + return; +} + +static void session_flags_calculate_randomness_by_sts(struct session_flags_plugin_info *sf_plugin_info, struct session *session, struct session_flags_stat *stat, size_t payload_len, const char *payload, uint64_t all_pkts) +{ + if (stat->random_looking_stat.has_judged_sts || sts_random_switch == 0) + { + return; + } + + if (payload_len < SESSION_RANDOM_LOOKING_PAYLOAD_LEN_MIN) + { + return; + } + + stat->random_looking_stat.has_judged_sts = 1; + + struct sts_result result; + uint32_t random_flags_count = 0; + memset(&result, 0, sizeof(result)); + + mesa_statistical_test_suite((void*)payload, payload_len, &result, sts_random_switch); + + if (result.frequency) + { + stat->result.random_looking_flags |= SESSION_FLAGS_FREQUENCY; + random_flags_count++; + } + if (result.block_frequency) + { + stat->result.random_looking_flags |= SESSION_FLAGS_BLOCK_FREQUENCY; + random_flags_count++; + } + if (result.cumulative_sums) + { + stat->result.random_looking_flags |= SESSION_FLAGS_CUMULATIVE_SUMS; + random_flags_count++; + } + if (result.runs) + { + stat->result.random_looking_flags |= SESSION_FLAGS_RUNS; + random_flags_count++; + } + if (result.longest_run) + { + stat->result.random_looking_flags |= SESSION_FLAGS_LONGEST_RUN; + random_flags_count++; + } + if (result.rank) + { + stat->result.random_looking_flags |= SESSION_FLAGS_RANK; + random_flags_count++; + } + if (result.non_overlapping_template_matching) + { + stat->result.random_looking_flags |= SESSION_FLAGS_NON_OVERLAPPING_TEMPLATE_MATCHING; + random_flags_count++; + } + if (result.overlapping_template_matching) + { + stat->result.random_looking_flags |= SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING; + random_flags_count++; + } + if (result.universal) + { + stat->result.random_looking_flags |= SESSION_FLAGS_UNIVERSAL; + random_flags_count++; + } + if (result.random_excursions) + { + stat->result.random_looking_flags |= SESSION_FLAGS_RANDOM_EXCURSIONS; + random_flags_count++; + } + if (result.random_excursions_variant) + { + stat->result.random_looking_flags |= SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT; + random_flags_count++; + } + if (result.poker_detect) + { + stat->result.random_looking_flags |= SESSION_FLAGS_POKER_DETECT; + random_flags_count++; + } + if (result.runs_distribution) + { + stat->result.random_looking_flags |= SESSION_FLAGS_RUNS_DISTRIBUTION; + random_flags_count++; + } + if (result.self_correlation) + { + stat->result.random_looking_flags |= SESSION_FLAGS_SELF_CORRELATION; + random_flags_count++; + } + if (result.binary_derivative) + { + stat->result.random_looking_flags |= SESSION_FLAGS_BINARY_DERIVATIVE; + random_flags_count++; + } + + if (random_flags_count > (g_sf_conf.random_judge_flags_cnt / 2)) + { + stat->result.flags |= SESSION_FLAGS_RANDOM_LOOKING; + stat->result.identify[session_flags_random_looking_mask] = all_pkts; + } + + STELLAR_LOG_DEBUG(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "[%s] calculate random looking flags, flags:0x%x, pkts_num:%d", session_get0_readable_addr(session), stat->result.random_looking_flags, all_pkts); +} + +static void session_flags_calculate_random_looking(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_stat *stat, struct session *session, int topic_id, uint64_t all_pkts) +{ + if (stat->result.flags & SESSION_FLAGS_RANDOM_LOOKING) + { + return; + } + + int udp_topic_id = sf_plugin_info->udp_topic_id; + + const struct packet *pkt = session_get0_current_packet(session); + size_t payload_len = packet_get_payload_len(pkt); + const char *payload = packet_get_payload(pkt); + + if ((topic_id == udp_topic_id) && g_sf_conf.random_looking_udp_ignore_pkts < 0)// disable random looking udp when random_looking_udp_ignore_pkts<0 + { + return; + } + + if (payload_len == 0 || payload == NULL) + { + return; + } + + stat->random_looking_stat.payload_pkt_num++; + if ((topic_id == udp_topic_id) && stat->random_looking_stat.payload_pkt_num <= g_sf_conf.random_looking_udp_ignore_pkts) + { + return; + } + + session_flags_calculate_randomness_by_fet(stat, payload_len, payload, all_pkts); + if (stat->result.flags & SESSION_FLAGS_RANDOM_LOOKING) + { + return; + } + + session_flags_calculate_randomness_by_sts(sf_plugin_info, session, stat, payload_len, payload, all_pkts); + + return; +} + +static void session_flags_reset_delta(struct session_flags_stat *stat) +{ + stat->c2s.delta_bytes = 0; + stat->c2s.delta_pkts = 0; + stat->c2s.delta_large_pkts = 0; + stat->c2s.delta_payload_pkts = 0; + + stat->s2c.delta_bytes = 0; + stat->s2c.delta_pkts = 0; + stat->s2c.delta_large_pkts = 0; + stat->s2c.delta_payload_pkts = 0; + + return; +} + +static void session_flags_calculate_rate(struct session_flags_stat *stat, uint64_t delta_ms) +{ + stat->c2s.rate = stat->c2s.delta_bytes * 1.f / delta_ms; + stat->s2c.rate = stat->s2c.delta_bytes * 1.f / delta_ms; + + return; +} + +static void session_flags_update_large_pkt_size(struct session_flags_plugin_info *sf_plugin_info, uint32_t pkt_len, uint64_t ms) +{ + if (pkt_len > 1500) + { + return; + } + + OnlineMean_Update(&g_large_pkt_omean, pkt_len); + + if (g_large_pkt_size_update_ms == 0) + { + g_large_pkt_size_update_ms = ms; + g_large_pkt_size = g_sf_conf.large_ptks_init_size; + return; + } + + if (ms - g_large_pkt_size_update_ms >= LARGE_PKT_SIZE_UPDATE_INTERVAL_MS && g_large_pkt_omean.count >= LARGE_PKT_SIZE_UPDATE_COUNT_MIN) + { + g_large_pkt_size_update_ms = ms; + g_large_pkt_size = (uint32_t)(0.84f * OnlineMean_GetStd(&g_large_pkt_omean) + OnlineMean_GetMean(&g_large_pkt_omean));//计算公式 0.84 = (g_large_pkt_size - mean) / std, 0.84为正态分布表中80%的概率对应的z值 + + if (g_large_pkt_size < LARGE_PKT_SIZE_MIN) + { + g_large_pkt_size = LARGE_PKT_SIZE_MIN; + } + else if (g_large_pkt_size > LARGE_PKT_SIZE_MAX) + { + g_large_pkt_size = LARGE_PKT_SIZE_MAX; + } + + STELLAR_LOG_DEBUG(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "session_flags thread %ld update large_pkt_size %d", pthread_self(), g_large_pkt_size); + } + + return; +} + +struct session_flags_result *session_flags(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_ctx *ctx, struct session *session, int topic_id, uint32_t bytes, enum flow_type flow_type, uint64_t ms) +{ + struct session_flags_stat *stat = &ctx->stat; + + if (stat == NULL || bytes == 0) + { + return NULL; + } + + session_flags_update_large_pkt_size(sf_plugin_info, bytes, ms); + + uint64_t delta_ms = 0; + + if(stat->session_start_time_ms == 0) + { + stat->session_start_time_ms = ms; + } + stat->stream_live_time_ms = ms - stat->session_start_time_ms; + + if (stat->last_iter_ts_ms == 0) + { + stat->last_iter_ts_ms = ms; + } + + if (flow_type == FLOW_TYPE_C2S) + { + flow_stat_update(session, &stat->c2s, bytes); + } + else + { + flow_stat_update(session, &stat->s2c, bytes); + } + + uint64_t all_pkts = stat->c2s.pkts + stat->s2c.pkts; + session_flags_calculate_dir(stat, all_pkts); + session_flags_calculate_random_looking(sf_plugin_info, stat, session, topic_id, all_pkts); + + const struct packet *pkt = session_get0_current_packet(session); + size_t payload_len = packet_get_payload_len(pkt); + if (g_sf_conf.tunneling_enabled && payload_len > 0 && (topic_id == sf_plugin_info->tcp_topic_id))// detect tunneling on tcp only + { + tunneling_scan_sequence(sf_plugin_info, session, ctx, payload_len, flow_type, all_pkts); + } + + if (stat->stream_live_time_ms >= START_JUDGE_TIME_MS) + { + if (all_pkts > g_sf_conf.main_dir_front_n_pkts) + { + session_flags_calculate_main_dir(stat); + } + } + + if (stat->c2s.pkts == 0 || stat->s2c.pkts == 0) + { + goto END; + } + + if (stat->main_dir != MAIN_DIR_UNKONWN) + { + session_flags_calculate_bound(stat, all_pkts); + session_flags_calculate_unidirection(stat, all_pkts); + } + + delta_ms = ms - stat->last_iter_ts_ms; + if (delta_ms >= SESSION_ITER_INTERVAL_MS) + { + session_flags_calculate_rate(stat, delta_ms); + + session_flags_calculate_bidirectional(stat, all_pkts); + session_flags_calculate_CBR(stat, all_pkts); + session_flags_calculate_download(stat, all_pkts); + session_flags_calculate_bulky(stat, all_pkts); + session_flags_calculate_pseudo_unidirection(stat, all_pkts); + session_flags_calculate_streaming(stat, all_pkts); + stat->iter.iter_cnt++; + stat->last_iter_ts_ms = ms; + + session_flags_reset_delta(stat); + } + + session_flags_calculate_interactive_pulse(stat, ms, all_pkts); + +END: + stat->last_pkt_ts_ms = ms; + return &stat->result; +} + +struct session_flags_result *session_flags_get_flags(struct session_flags_stat *stat) +{ + if (stat == NULL) + return NULL; + + return &stat->result; +} + +struct session_flags_message *session_flags_generate_firewall_message(uint64_t flags, const uint32_t identify[session_flags_all_mask]) +{ + int flag_num = 0; + uint32_t temp_identify[session_flags_all_mask] = {0}; + struct session_flags_message *flags_msg = (struct session_flags_message *)calloc(1, sizeof(struct session_flags_message)); + + flags_msg->magic= MESSAGE_MAGIC; + flags_msg->flags = flags; + + for (int i = 0; i < session_flags_all_mask; i++) + { + if (flags & (SESSION_FLAGS_START << i)) + { + temp_identify[flag_num] = identify[i]; + flag_num++; + } + } + + flags_msg->packet_sequence_array = (uint32_t *)calloc(flag_num, sizeof(uint32_t)); + for (int i = 0; i < flag_num; i++) + { + flags_msg->packet_sequence_array[i] = temp_identify[i]; + } + flags_msg->array_num = flag_num; + + return flags_msg; +} diff --git a/decoders/session_flags/session_flags_internal.h b/decoders/session_flags/session_flags_internal.h new file mode 100644 index 0000000..eea0b20 --- /dev/null +++ b/decoders/session_flags/session_flags_internal.h @@ -0,0 +1,153 @@ +#pragma once +#include +#include "onlinemean.h" +#include "tunneling.h" + +#include "hs/hs_runtime.h" +#include "stellar/session.h" +#include "stellar/session_flags.h" +#include "toml/toml.h" + +#define SESSION_FLAGS_LOG_MODULE "SESSION_FLAGS" + +enum random_looking_flags +{ + session_flags_frequency_mask = 0, + session_flags_block_frequency_mask, + session_flags_cumulative_sums_mask, + session_flags_runs_mask, + session_flags_longest_run_mask, + session_flags_rank_mask, + session_flags_non_overlapping_template_matching_mask, + session_flags_overlapping_template_matching_mask, + session_flags_universal_mask, + session_flags_random_excursions_mask, + session_flags_random_excursions_variant_mask, + session_flags_poker_detect_mask, + session_flags_runs_distribution_mask, + session_flags_self_correlation_mask, + session_flags_binary_derivative_mask, +}; +#define SESSION_FLAGS_FREQUENCY (0x0000000000000001) +#define SESSION_FLAGS_BLOCK_FREQUENCY (SESSION_FLAGS_FREQUENCY << session_flags_block_frequency_mask) +#define SESSION_FLAGS_CUMULATIVE_SUMS (SESSION_FLAGS_FREQUENCY << session_flags_cumulative_sums_mask) +#define SESSION_FLAGS_RUNS (SESSION_FLAGS_FREQUENCY << session_flags_runs_mask) +#define SESSION_FLAGS_LONGEST_RUN (SESSION_FLAGS_FREQUENCY << session_flags_longest_run_mask) +#define SESSION_FLAGS_RANK (SESSION_FLAGS_FREQUENCY << session_flags_rank_mask) +#define SESSION_FLAGS_NON_OVERLAPPING_TEMPLATE_MATCHING (SESSION_FLAGS_FREQUENCY << session_flags_non_overlapping_template_matching_mask) +#define SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING (SESSION_FLAGS_FREQUENCY << session_flags_overlapping_template_matching_mask) +#define SESSION_FLAGS_UNIVERSAL (SESSION_FLAGS_FREQUENCY << session_flags_universal_mask) +#define SESSION_FLAGS_RANDOM_EXCURSIONS (SESSION_FLAGS_FREQUENCY << session_flags_random_excursions_mask) +#define SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT (SESSION_FLAGS_FREQUENCY << session_flags_random_excursions_variant_mask) +#define SESSION_FLAGS_POKER_DETECT (SESSION_FLAGS_FREQUENCY << session_flags_poker_detect_mask) +#define SESSION_FLAGS_RUNS_DISTRIBUTION (SESSION_FLAGS_FREQUENCY << session_flags_runs_distribution_mask) +#define SESSION_FLAGS_SELF_CORRELATION (SESSION_FLAGS_FREQUENCY << session_flags_self_correlation_mask) +#define SESSION_FLAGS_BINARY_DERIVATIVE (SESSION_FLAGS_FREQUENCY << session_flags_binary_derivative_mask) + +#define MAIN_DIR_UNKONWN -1 + +#define START_JUDGE_TIME_MS 5000 + +struct session_flags_result { + uint64_t flags; + uint64_t random_looking_flags; + uint32_t identify[session_flags_all_mask]; + bool is_tls; +}; + +struct session_flags_init_conf{ + uint32_t interactive_starttime_ms; + uint32_t interactive_pulse_num; + uint32_t main_dir_front_n_pkts; + uint64_t interactive_latency_ms; + uint32_t large_ptks_init_size; + uint32_t random_judge_flags_cnt; + uint32_t session_max_process_time_ms; + uint32_t fet_enabled; + uint32_t tunneling_enabled; + int32_t random_looking_udp_ignore_pkts; + uint32_t tunneling_tls_ignore_pkts; + uint32_t tunneling_max_scan_pkts; + char tunneling_pcre_list[2048]; + char random_looking_judge_list[2048]; +}; + +struct session_flags_plugin_info{ + int plugin_id; + int sess_ctx_exdata_idx; + struct stellar *st; + struct logger *log_handle; + int session_flags_topic_id; + int tcp_topic_id; + int udp_topic_id; + hs_database_t *tunneling_hs_db; +}; + +struct session_flags_iter_values +{ + float bulky; + float CBR; + float download; + float interactive; + float pseudo_unidirectional; + float streaming; + OnlineMean_t omean; +}; + +struct session_flags_iter +{ + uint32_t iter_cnt; + float bidirectional; + struct session_flags_iter_values c2s; + struct session_flags_iter_values s2c; +}; + +struct flow_stat +{ + uint64_t bytes; + uint64_t pkts; + uint64_t payload_pkts; + uint64_t large_pkts; + + uint32_t delta_pkts; + uint32_t delta_large_pkts; + uint32_t delta_payload_pkts; + uint32_t delta_bytes; + + float rate; +}; + +struct random_looking_stat_info +{ + uint8_t has_judged_sts; + uint8_t has_judged_fet; + uint8_t payload_pkt_num; +}; + +struct session_flags_stat +{ + struct flow_stat c2s, s2c; + uint64_t last_pkt_ts_ms; + uint64_t interactive_pulse_num; + uint64_t session_start_time_ms; + uint64_t stream_live_time_ms; + uint64_t last_iter_ts_ms; + int main_dir; + struct random_looking_stat_info random_looking_stat; + struct tunneling_stat_info tunneling_stat; + struct session_flags_iter iter; + struct session_flags_result result; +}; + +struct session_flags_ctx +{ + struct session_flags_stat stat; + hs_stream_t *tunneling_hs_stream; + uint64_t history_flags; +}; + +void session_flags_stat_init(struct session_flags_stat *stat, enum session_direction session_dir); +struct session_flags_result *session_flags(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_ctx *ctx, struct session *session, int etopic_id, uint32_t bytes, enum flow_type flow_type, uint64_t ms); +struct session_flags_result *session_flags_get_flags(struct session_flags_stat *session_flags); +struct session_flags_message *session_flags_generate_firewall_message(uint64_t flags, const uint32_t identify[session_flags_all_mask]); +float session_flags_calculate_CV(OnlineMean_t * omean); \ No newline at end of file diff --git a/decoders/session_flags/session_flags_plugin.cpp b/decoders/session_flags/session_flags_plugin.cpp new file mode 100644 index 0000000..db9522c --- /dev/null +++ b/decoders/session_flags/session_flags_plugin.cpp @@ -0,0 +1,404 @@ +#include +#include +#include +#include "mesa_sts.h" +#include "cJSON.h" +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" +#include "stellar/log.h" + +#include "session_flags_internal.h" + +#define _MAX_STR_LEN 64 + +#define UNUSED(x) (void)(x) + +const char *CFG_FILE_PATH="./etc/session_flags/session_flags.toml"; + +uint32_t sts_random_switch = 0; + +struct session_flags_init_conf g_sf_conf; + +static const char* random_looking_judge_table[] = { + "frequency", + "block_frequency", + "cumulative_sums", + "runs", + "longest_run", + "rank", + "non_overlapping_template_matching", + "overlapping_template_matching", + "universal", + "random_excursions", + "random_excursions_variant", + "poker_detect", + "runs_distribution", + "self_correlation", + "binary_derivative" +}; + +static void session_flags_topic_free_cb(void *msg, void *msg_free_arg) +{ + UNUSED(msg_free_arg); + struct session_flags_message *flags = (struct session_flags_message *)msg; + + if (flags) + { + if (flags->packet_sequence_array) + { + free(flags->packet_sequence_array); + } + free(flags); + } + + return; +} + +static void session_flags_exdata_free_cb(int idx, void *ex_ptr, void *arg) +{ + UNUSED(idx); + UNUSED(arg); + + if (ex_ptr == NULL) + { + return; + } + struct session_flags_ctx *ctx = (struct session_flags_ctx *)ex_ptr; + tunneling_hs_stream_free(ctx); + + free(ex_ptr); +} + +void session_flags_entry(struct session *session, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + UNUSED(per_session_ctx); + if (msg == NULL) + { + return; + } + + const struct packet *pkt = (const struct packet *)msg; + struct session_flags_plugin_info *sf_plugin_info = (struct session_flags_plugin_info *)plugin_env; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)session_exdata_get(session, sf_plugin_info->sess_ctx_exdata_idx); + + if (ctx == NULL) + { + ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + session_exdata_set(session, sf_plugin_info->sess_ctx_exdata_idx, ctx); + + session_flags_stat_init(&ctx->stat, session_get_direction(session)); + if (g_sf_conf.tunneling_enabled) + { + tunneling_hs_stream_init(sf_plugin_info, ctx); + } + } + + struct session_flags_stat *stat = &ctx->stat; + session_flags_result *flags_result = NULL; + size_t pktlen = 0; + + pktlen = packet_get_raw_len(pkt); + + uint64_t curr_time_ms = 0; + const struct timeval *tv; + + tv = packet_get_timeval(pkt); + if (tv != NULL) + { + curr_time_ms = tv->tv_sec * 1000 + tv->tv_usec / 1000; + } + + flags_result = session_flags(sf_plugin_info, ctx, session, topic_id, pktlen, session_get_flow_type(session), curr_time_ms); + + if ((stat->stream_live_time_ms > g_sf_conf.session_max_process_time_ms)) + { + stellar_session_plugin_dettach_current_session(session); + } + + uint32_t pkts_num = stat->c2s.pkts + stat->s2c.pkts; + + if (flags_result != NULL) + { + if (flags_result->flags != ctx->history_flags) + { + struct session_flags_message *flags_msg = session_flags_generate_firewall_message(flags_result->flags, flags_result->identify); + if (session_mq_publish_message(session, sf_plugin_info->session_flags_topic_id, flags_msg) < 0) + { + session_flags_topic_free_cb(flags_msg, NULL); + + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "[%s] publish session flags message failed, flags:0x%x, pkts_num:%d", session_get0_readable_addr(session), flags_result->flags, pkts_num); + return; + } + + ctx->history_flags = flags_result->flags; + + STELLAR_LOG_DEBUG(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, + "[%s] flags:0x%x, pkts_num:%d\n \ + c2s_iter: bulky: %f, CBR: %f, download: %f, interactive: %f, pseudo_unidirectional: %f, streaming: %f, CBR_CV: %f\n \ + s2c_iter: bulky: %f, CBR: %f, download: %f, interactive: %f, pseudo_unidirectional: %f, streaming: %f, CBR_CV: %f\n \ + iter_cnt: %d, bidirectional: %f\n", session_get0_readable_addr(session), ctx->history_flags, pkts_num, + stat->iter.c2s.bulky, stat->iter.c2s.CBR, stat->iter.c2s.download, stat->iter.c2s.interactive, stat->iter.c2s.pseudo_unidirectional, stat->iter.c2s.streaming, session_flags_calculate_CV(&stat->iter.c2s.omean), + stat->iter.s2c.bulky, stat->iter.s2c.CBR, stat->iter.s2c.download, stat->iter.s2c.interactive, stat->iter.s2c.pseudo_unidirectional, stat->iter.s2c.streaming, session_flags_calculate_CV(&stat->iter.s2c.omean), + stat->iter.iter_cnt, stat->iter.bidirectional); + } + } + + return; +} + +static void session_flags_load_config(struct session_flags_plugin_info *sf_plugin_info, const char *cfg_file, struct session_flags_init_conf *g_sf_conf) +{ + char errbuf[256] = {0}; + + FILE *fp = fopen(cfg_file, "r"); + if (NULL == fp) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "Can't open config file:%s", cfg_file); + return; + } + + toml_table_t *toml_root = toml_parse_file(fp, errbuf, sizeof(errbuf)); + fclose(fp); + + toml_table_t *cfg_tbl = toml_table_in(toml_root, "SESSION_FLAGS"); + if (NULL == cfg_tbl) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "config file:%s has no key: [SESSION_FLAGS]", cfg_file); + toml_free(toml_root); + return; + } + + toml_datum_t toml_val = toml_int_in(cfg_tbl, "INTERACTIVE_STARTTIME_MS"); + if (toml_val.ok) + { + g_sf_conf->interactive_starttime_ms = toml_val.u.i; + } + else + { + g_sf_conf->interactive_starttime_ms = 15000; + } + + toml_val = toml_int_in(cfg_tbl, "INTERACTIVE_PULSE_NUM"); + if (toml_val.ok) + { + g_sf_conf->interactive_pulse_num = toml_val.u.i; + } + else + { + g_sf_conf->interactive_pulse_num = 4; + } + + toml_val = toml_int_in(cfg_tbl, "INTERACTIVE_LATENCY_MS"); + if (toml_val.ok) + { + g_sf_conf->interactive_latency_ms = toml_val.u.i; + } + else + { + g_sf_conf->interactive_latency_ms = 1000; + } + + toml_val = toml_int_in(cfg_tbl, "MAIN_DIR_FRONT_N_PKTS"); + if (toml_val.ok) + { + g_sf_conf->main_dir_front_n_pkts = toml_val.u.i; + } + else + { + g_sf_conf->main_dir_front_n_pkts = 100; + } + + toml_val = toml_int_in(cfg_tbl, "LARGE_PKTS_INIT_SIZE"); + if (toml_val.ok) + { + g_sf_conf->large_ptks_init_size = toml_val.u.i; + } + else + { + g_sf_conf->large_ptks_init_size = 1000; + } + + toml_val = toml_int_in(cfg_tbl, "SESSION_MAX_PROCESS_TIME_MS"); + if (toml_val.ok) + { + g_sf_conf->session_max_process_time_ms = toml_val.u.i; + } + else + { + g_sf_conf->session_max_process_time_ms = 30000; + } + + toml_val = toml_int_in(cfg_tbl, "FET_ENABLED"); + if (toml_val.ok) + { + g_sf_conf->fet_enabled = toml_val.u.b; + } + else + { + g_sf_conf->fet_enabled = 1; + } + + toml_val = toml_int_in(cfg_tbl, "RANDOM_LOOKING_UDP_IGNORE_PKTS"); + if (toml_val.ok) + { + g_sf_conf->random_looking_udp_ignore_pkts = toml_val.u.i; + } + else + { + g_sf_conf->random_looking_udp_ignore_pkts = 3; + } + + toml_val = toml_int_in(cfg_tbl, "TUNNELING_TLS_IGNORE_PKTS"); + if (toml_val.ok) + { + g_sf_conf->tunneling_tls_ignore_pkts = toml_val.u.i; + } + else + { + g_sf_conf->tunneling_tls_ignore_pkts = 4; + } + + toml_val = toml_int_in(cfg_tbl, "TUNNELING_MAX_SCAN_PKTS"); + if (toml_val.ok) + { + g_sf_conf->tunneling_max_scan_pkts = toml_val.u.i; + } + else + { + g_sf_conf->tunneling_max_scan_pkts = 15; + } + + toml_val = toml_string_in(cfg_tbl, "TUNNELING_PCRE_LIST"); + if (toml_val.ok) + { + strncpy(g_sf_conf->tunneling_pcre_list, toml_val.u.s, sizeof(g_sf_conf->tunneling_pcre_list) - 1); + } + else + { + strncpy(g_sf_conf->tunneling_pcre_list, "{\"tunneling_pcre_list\":[]}", sizeof(g_sf_conf->tunneling_pcre_list) - 1); + } + + toml_val = toml_string_in(cfg_tbl, "RANDOM_LOOKING_JUDGE_LIST"); + if (toml_val.ok) + { + strncpy(g_sf_conf->random_looking_judge_list, toml_val.u.s, sizeof(g_sf_conf->random_looking_judge_list) - 1); + } + else + { + strncpy(g_sf_conf->random_looking_judge_list, "{\"random_looking_judge_list\":[]}", sizeof(g_sf_conf->random_looking_judge_list) - 1); + } +} + +extern "C" void *session_flags_plugin_init(struct stellar *st) +{ + char random_looking_list_str[2048] = {0}; + struct session_flags_plugin_info *sf_plugin_info = (struct session_flags_plugin_info *)calloc(1, sizeof(struct session_flags_plugin_info)); + cJSON *json = NULL, *item = NULL; + int array_num; + + sf_plugin_info->st = st; + sf_plugin_info->sess_ctx_exdata_idx = stellar_exdata_new_index(st, "SESSION_FLAGS_SESS_CTX", session_flags_exdata_free_cb, NULL); + + sf_plugin_info->log_handle = stellar_get_logger(st); + if(sf_plugin_info->log_handle==NULL) + { + printf("stellar_get_logger object failed ...\n"); + goto ERROR; + } + + memset(&g_sf_conf, 0, sizeof(g_sf_conf)); + session_flags_load_config(sf_plugin_info, CFG_FILE_PATH, &g_sf_conf); + tunneling_hyperscan_engine_init(sf_plugin_info, &g_sf_conf); + + json = cJSON_Parse(g_sf_conf.random_looking_judge_list); + if (json == NULL) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_Parse failed, random_looking_list_str:%s", random_looking_list_str); + goto ERROR; + } + item = cJSON_GetObjectItem(json, "random_looking_judge_list"); + if (item == NULL) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_GetObjectItem failed, random_looking_list_str:%s", random_looking_list_str); + goto ERROR; + } + array_num = cJSON_GetArraySize(item); + if (array_num > STS_RANDOM_JUDGE_NUM || array_num < 0) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "array size error, array_num:%d", array_num); + goto ERROR; + } + for (int i = 0; i < array_num; i++) + { + for (int j = 0; j < STS_RANDOM_JUDGE_NUM; j++) + { + if (strcmp(cJSON_GetArrayItem(item, i)->valuestring, random_looking_judge_table[j]) == 0) + { + STS_SET_FLAG(sts_random_switch, j); + g_sf_conf.random_judge_flags_cnt++; + break; + } + } + } + cJSON_Delete(json); + + sf_plugin_info->plugin_id = stellar_session_plugin_register(st, NULL, NULL, sf_plugin_info); + if (sf_plugin_info->plugin_id < 0) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "stellar_session_plugin_register failed"); + goto ERROR; + + } + + sf_plugin_info->session_flags_topic_id = stellar_mq_create_topic(st, SESSION_FLAGS_MESSAGE_TOPIC, session_flags_topic_free_cb, NULL); + if (sf_plugin_info->session_flags_topic_id < 0) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "stellar_session_mq_create_topic failed"); + goto ERROR; + } + + sf_plugin_info->tcp_topic_id = stellar_mq_get_topic_id(st, TOPIC_TCP_INPUT); + sf_plugin_info->udp_topic_id = stellar_mq_get_topic_id(st, TOPIC_UDP_INPUT); + if (sf_plugin_info->tcp_topic_id < 0 || sf_plugin_info->udp_topic_id < 0) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "stellar_session_mq_get_topic_id failed"); + goto ERROR; + } + + stellar_session_mq_subscribe(st, sf_plugin_info->tcp_topic_id, session_flags_entry, sf_plugin_info->plugin_id); + stellar_session_mq_subscribe(st, sf_plugin_info->udp_topic_id, session_flags_entry, sf_plugin_info->plugin_id); + + return sf_plugin_info; + +ERROR: + if (sf_plugin_info != NULL) + { + free(sf_plugin_info); + } + + if (json != NULL) + { + cJSON_Delete(json); + } + + perror("session_flags init failed"); + exit(-1); +} + +extern "C" void session_flags_plugin_exit(void *plugin_ctx) +{ + if (plugin_ctx == NULL) + { + return; + } + + struct session_flags_plugin_info *sf_plugin_info = (struct session_flags_plugin_info *)plugin_ctx; + + tunneling_hyperscan_engine_exit(sf_plugin_info->tunneling_hs_db); + + free(plugin_ctx); + + return; +} \ No newline at end of file diff --git a/decoders/session_flags/tunneling.cpp b/decoders/session_flags/tunneling.cpp new file mode 100644 index 0000000..987ffc5 --- /dev/null +++ b/decoders/session_flags/tunneling.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include "cJSON.h" +#include "session_flags_internal.h" +#include "tunneling.h" +#include "stellar/log.h" + +#define UNUSED(x) (void)(x) + +thread_local hs_scratch_t *hs_scratch = NULL; +extern struct session_flags_init_conf g_sf_conf; + +static char tunneling_length_to_character(enum flow_type flow_type, size_t len) +{ + char ret; + + switch(len) + { + case 1 ... 200: + ret = 'A'; + break; + case 201 ... 600: + ret = 'B'; + break; + case 601 ... 1000: + ret = 'C'; + break; + case 1001 ... 1460: + ret = 'D'; + break; + default: + ret = 'Z'; + break; + } + + if (flow_type == FLOW_TYPE_C2S) + { + return ret; + } + else + { + return tolower(ret); + } +} + +static int tunneling_match_event_handler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context) { + UNUSED(id); + UNUSED(from); + UNUSED(to); + UNUSED(flags); + + struct session_flags_ctx *ctx = (struct session_flags_ctx *)context; + ctx->stat.result.flags |= SESSION_FLAGS_TUNNELING; + return 0; +} + +int tunneling_scan_sequence(struct session_flags_plugin_info *sf_plugin_info, struct session *session, struct session_flags_ctx *ctx, size_t payload_len, enum flow_type flow_type, uint64_t pkts_cnt) +{ + if (ctx->stat.result.flags & SESSION_FLAGS_TUNNELING) + { + return 0; + } + + ctx->stat.tunneling_stat.payload_pkt_num++; + if (ctx->stat.result.is_tls && ctx->stat.tunneling_stat.payload_pkt_num <= g_sf_conf.tunneling_tls_ignore_pkts) + { + return 0; + } + + if((ctx->stat.result.is_tls==0) && (ctx->stat.tunneling_stat.payload_pkt_num > g_sf_conf.tunneling_max_scan_pkts)) + { + return 0; + } + + if((ctx->stat.result.is_tls) && (ctx->stat.tunneling_stat.payload_pkt_num > g_sf_conf.tunneling_max_scan_pkts+g_sf_conf.tunneling_tls_ignore_pkts)) + { + return 0; + } + + if (hs_scratch == NULL) + { + hs_error_t err = hs_alloc_scratch(sf_plugin_info->tunneling_hs_db, &hs_scratch); + if (err != HS_SUCCESS) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_alloc_scratch failed, err:%d", err); + return -1; + } + } + + char tunneling_seq_char = tunneling_length_to_character(flow_type, payload_len); + STELLAR_LOG_DEBUG(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "session: %s, is tls:%s, total_num: %d, payload_pkt_num: %d, tunneling_seq_char:%c, payload_len:%d", + session_get0_readable_addr(session), ctx->stat.result.is_tls == true ? "yes":"no", pkts_cnt, ctx->stat.tunneling_stat.payload_pkt_num, tunneling_seq_char, payload_len); + + hs_error_t err = hs_scan_stream(ctx->tunneling_hs_stream, &tunneling_seq_char, 1, 0, hs_scratch, tunneling_match_event_handler, ctx); + if (err != HS_SUCCESS) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_scan_stream failed, err:%d", err); + return -1; + } + if (ctx->stat.result.flags & SESSION_FLAGS_TUNNELING) + { + ctx->stat.result.identify[session_flags_tunneling_mask] = pkts_cnt; + } + + return 0; +} + +void tunneling_hs_stream_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_ctx *ctx) +{ + hs_error_t err = hs_open_stream(sf_plugin_info->tunneling_hs_db, 0, &ctx->tunneling_hs_stream); + if (err != HS_SUCCESS) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_open_stream failed, err:%d", err); + return; + } +} + +void tunneling_hs_stream_free(struct session_flags_ctx *ctx) +{ + if (ctx->tunneling_hs_stream == NULL) + { + return; + } + + hs_close_stream(ctx->tunneling_hs_stream, hs_scratch, NULL, NULL); +} + +int tunneling_hyperscan_engine_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_init_conf *g_sf_conf) +{ + cJSON *json = NULL, *item = NULL; + int array_num; + char **pcre = NULL; + hs_compile_error_t *compile_err; + hs_error_t err; + unsigned int *flags = NULL; + unsigned int *ids = NULL; + int ret = 0; + + g_sf_conf->tunneling_enabled = 0; + + json = cJSON_Parse(g_sf_conf->tunneling_pcre_list); + if (json == NULL) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_Parse failed, tunneling_pcre_list:%s", g_sf_conf->tunneling_pcre_list); + goto END; + } + item = cJSON_GetObjectItem(json, "tunneling_pcre_list"); + if (item == NULL) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_GetObjectItem failed, tunneling_pcre_list:%s", g_sf_conf->tunneling_pcre_list); + goto END; + } + array_num = cJSON_GetArraySize(item); + if (array_num < 0) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "array size error, array_num:%d", array_num); + goto END; + } + + if (array_num == 0) + { + goto END; + } + + g_sf_conf->tunneling_enabled = 1; + pcre = (char **)calloc(array_num, sizeof(char *)); + for (int i = 0; i < array_num; i++) + { + pcre[i] = cJSON_GetArrayItem(item, i)->valuestring; + } + + flags = (unsigned int *)calloc(array_num, sizeof(unsigned int)); + ids = (unsigned int *)calloc(array_num, sizeof(unsigned int)); + for (int i = 0; i < array_num; i++) + { + flags[i] = HS_FLAG_DOTALL; + ids[i] = i; + } + + err = hs_compile_multi(pcre, flags, ids, array_num, HS_MODE_STREAM, NULL, &sf_plugin_info->tunneling_hs_db, &compile_err); + if (err != HS_SUCCESS) + { + STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_compile_multi failed, err:%d, pattern id: %d, err_msg: %s, pattern: %s", err, compile_err->expression, compile_err->message, pcre[compile_err->expression]); + cJSON_Delete(json); + free(pcre); + ret = -1; + goto END; + } + +END: + if (json != NULL) + { + cJSON_Delete(json); + } + if (pcre != NULL) + { + free(pcre); + } + if (flags != NULL) + { + free(flags); + } + if (ids != NULL) + { + free(ids); + } + return ret; +} + +void tunneling_hyperscan_engine_exit(hs_database_t *tunneling_hs_db) +{ + if (tunneling_hs_db != NULL) + { + hs_free_database(tunneling_hs_db); + } +} diff --git a/decoders/session_flags/tunneling.h b/decoders/session_flags/tunneling.h new file mode 100644 index 0000000..50fc3fe --- /dev/null +++ b/decoders/session_flags/tunneling.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include +#include +#include "stellar/session.h" + +struct tunneling_stat_info +{ + uint8_t payload_pkt_num; +}; + +int tunneling_scan_sequence(struct session_flags_plugin_info *sf_plugin_info, struct session *session, struct session_flags_ctx *ctx, size_t payload_len, flow_type flow_type, uint64_t pkts_cnt); +void tunneling_hs_stream_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_ctx *ctx); +void tunneling_hs_stream_free(struct session_flags_ctx *ctx); +int tunneling_hyperscan_engine_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_init_conf *g_sf_conf); +void tunneling_hyperscan_engine_exit(hs_database_t *tunneling_hs_db); \ No newline at end of file diff --git a/decoders/socks/CMakeLists.txt b/decoders/socks/CMakeLists.txt new file mode 100644 index 0000000..dabede1 --- /dev/null +++ b/decoders/socks/CMakeLists.txt @@ -0,0 +1,13 @@ +add_definitions(-fPIC) + +set(SOCKS_SRC socks_decoder.cpp) + +add_library(socks STATIC ${SOCKS_SRC}) +add_library(socks_dyn SHARED ${SOCKS_SRC}) +set_target_properties(socks PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map") +target_include_directories(socks PUBLIC ${CMAKE_SOURCE_DIR}/deps/) +target_link_libraries(socks toml) +set_target_properties(socks PROPERTIES PREFIX "") + +set_target_properties(socks_dyn PROPERTIES PREFIX "") +target_link_libraries(socks_dyn toml) \ No newline at end of file diff --git a/decoders/socks/socks_decoder.cpp b/decoders/socks/socks_decoder.cpp new file mode 100644 index 0000000..233c077 --- /dev/null +++ b/decoders/socks/socks_decoder.cpp @@ -0,0 +1,527 @@ +#include +#include +#include + +extern "C" { +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" +} + +#include "socks_decoder_internal.h" +#include "stellar/log.h" + +#define UNUSED(x) (void)(x) + + +static void socks_decoder_session_exdata_free(int idx, void *ex_ptr, void *arg) +{ + UNUSED(idx); + UNUSED(arg); + + if (ex_ptr == NULL) + { + return; + } + + free(ex_ptr); + + return; +} + +//packet format refer to https://zh.wikipedia.org/wiki/SOCKS +static int socks_rough_rec(const char *payload, size_t payload_len) +{ + //for socks4 + if (payload_len < SOCKS5_REQUEST_METHOD_MIN_LEN) + { + return -1; + } + + if (payload[0] == SOCKS_FIELD_VER_4 && payload[payload_len-1] == 0) + { + if (payload_len >= 9) + { + return 0; + } + } + + if (payload[0] == SOCKS_FIELD_VER_5) + { + if (2 + (unsigned int)payload[1] == payload_len) + { + + return 0; + } + } + return -1; +} + +static int socks5_method_request(const char *payload, size_t payload_len) +{ + if (payload_len < SOCKS5_REQUEST_METHOD_MIN_LEN) + { + return -1; + } + + if (payload[0] != SOCKS_FIELD_VER_5) + { + return -1; + } + + if ((size_t)(2 + payload[1]) != payload_len) + { + return -1; + } + + return 0; +} + +static int socks4_request(struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + if (payload_len < 9) + return -1; + if (payload[0] != SOCKS_FIELD_VER_4 || payload[payload_len-1] != 0) + return -1; + + struct socks_addr *addr = &(stream->info.dst_addr); + + memcpy(&(addr->port), payload + 2, 2); + memcpy(&(addr->ipv4), payload + 4, 4); + + if (addr->ipv4 & 0x00FFFFFF) + { + addr->type = SOCKS_ADDR_IPV4; + return 0; + } + else if (addr->ipv4 & 0xFF000000)//socks4a hostname + { + size_t pos = 8; + while (pos < payload_len - 2 && payload[pos] != 0) + { + pos++; + } + + if (payload[pos] == 0) + { + if (payload_len - 1 - pos < 2) + return -1; + + addr->fqdn.iov_len = payload_len - 1 - pos - 1; + addr->fqdn.iov_base = (unsigned char *)calloc(1, addr->fqdn.iov_len + 1); + + memcpy(addr->fqdn.iov_base, payload+pos+1, addr->fqdn.iov_len); + + addr->type = SOCKS_ADDR_FQDN; + + return 0; + } + else + { + return -1; + } + } + + return -1; +} + +static int socks5_request(struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + unsigned int port_offset = 0; + struct socks_addr *addr = &(stream->info.dst_addr); + + if (payload_len < SOCKS5_REQUEST_MIN_LEN) + { + return -1; + } + + if (payload[0] != SOCKS_FIELD_VER_5) + { + return -1; + } + + if (payload[1] != SOCKS_CMD_CONNECT && payload[1] != SOCKS_CMD_BIND) + { + return -1; + } + + if (payload[2] != SOCKS5_RSV_DEFAULT) + { + return -1; + } + + switch (payload[3]) + { + case SOCKS_ATYPE_IP4: + { + if (payload_len != 10) + { + return -1; + } + + addr->type = SOCKS_ADDR_IPV4; + memcpy(&(addr->ipv4), payload+4, 4); + + port_offset = 8; + + break; + } + //should be processed + case SOCKS_ATYPE_IP6: + { + if(payload_len != 22) + { + return -1; + } + addr->type = SOCKS_ADDR_IPV6; + memcpy(addr->ipv6, payload+4, 16); + port_offset = 20; + + break; + } + case SOCKS_ATYPE_FQDN: + { + if (payload[4] < 0 || payload_len != (size_t)(7 + payload[4])) + { + return -1; + } + addr->type = SOCKS_ADDR_FQDN; + addr->fqdn.iov_len = payload[4]; + addr->fqdn.iov_base = (char *)calloc(1, addr->fqdn.iov_len + 1); + memcpy(addr->fqdn.iov_base, payload+5, payload[4]); + + port_offset = 5 + payload[4]; + } + break; + default: + break; + } + + memcpy(&(addr->port), payload+port_offset, 2); + + return 0; +} + +static int socks5_pass_request(struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + unsigned char *ubuf = (unsigned char*)payload; + unsigned char *cur; + struct socks_info *info = &stream->info; + + if (ubuf[0]!=1) + { + return -1; + } + if (payload_len < 2 || payload_len < (size_t)(3+ubuf[1]) || payload_len != (size_t)(3+ubuf[1]+ubuf[2+ubuf[1]])) + { + return -1; + } + + info->user_name.iov_len = ubuf[1]; + info->user_name.iov_base = (char *)calloc(1, info->user_name.iov_len + 1); + memcpy(info->user_name.iov_base, ubuf+2, info->user_name.iov_len); + + info->password.iov_len = ubuf[2+ubuf[1]]; + info->password.iov_base = (char *)calloc(1, info->password.iov_len + 1); + cur = ubuf + 2 + info->user_name.iov_len + 1; + memcpy(info->password.iov_base, cur, info->password.iov_len); + + return 0; +} + +static void c2s_handler(struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + switch (stream->client_state) + { + case SS_BEGIN: + if (socks5_method_request(payload, payload_len) == 0) + { + stream->client_state = SS_SUB; + stream->info.version = SOCKS_VERSION_5; + } + else if (socks4_request(stream, payload, payload_len) == 0) + { + stream->client_state = SS_END; + stream->info.version = SOCKS_VERSION_4; + } + else + { + stream->client_state = SS_FAILED; + } + break; + case SS_SUB: + if (socks5_request(stream, payload, payload_len) == 0) + { + stream->client_state = SS_END; + } + else if (socks5_pass_request(stream, payload, payload_len) != 0) + { + stream->client_state = SS_FAILED; + } + break; + default: + break; + } +} + +static int socks5_method_replay(const char *payload, size_t payload_len) +{ + if (payload_len != 2) + { + return -1; + } + if (payload[0] != SOCKS_FIELD_VER_5) + { + return -1; + } + if (payload[1] != 0 && payload[1]!=2) + { + return -1; + } + + ////printf("socks5 method replay!\n"); + return 0; +} + +static int socks4_replay(const char *payload, size_t payload_len) +{ + if (payload_len != 8) + return -1; + if (payload[0] != 0 || payload[1] < 90 || payload[1] > 93) + return -1; + + return 0; +} + +static int socks5_replay(const char *payload, size_t payload_len) +{ + if (payload_len < 6) + { + return -1; + } + if (payload[0] != SOCKS_FIELD_VER_5) + { + return -1; + } + if (payload[1] != 0) + { + return -1; + } + if (payload[2] != 0) + { + return -1; + } + + switch(payload[3]) + { + case SOCKS_ATYPE_IP4: + if (payload_len < 10) + { + return -1; + } + break; + case SOCKS_ATYPE_IP6: + if (payload_len != 22) + { + return -1; + } + break; + case SOCKS_ATYPE_FQDN: + if (payload[4] < 0 || payload_len < (size_t)(7 + payload[4])) + { + return -1; + } + break; + default: + return -1; + } + + return 0; +} + +static int socks5_pass_reply(const char *payload, size_t payload_len) +{ + if (payload_len != 2) + return -1; + if (payload[0] != 1 || payload[1] != 0) + return -1; + return 0; +} + +static void s2c_handler(struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + switch (stream->server_state) + { + case SS_BEGIN: + if (stream->info.version == SOCKS_VERSION_5 && socks5_method_replay(payload, payload_len) == 0) + { + stream->server_state = SS_SUB; + } + else if (stream->info.version == SOCKS_VERSION_4 && socks4_replay(payload, payload_len) == 0) + { + stream->server_state = SS_END; + } + else + { + stream->server_state = SS_FAILED; + //printf("socks error, s2c beign\n"); + } + break; + case SS_SUB: + if (socks5_replay(payload, payload_len) == 0) + { + stream->server_state = SS_END; + } + else if (socks5_pass_reply(payload, payload_len) != 0) + { + stream->server_state = SS_FAILED; + + //printf("socks error, s2c sub\n"); + } + break; + default: + //error! + break; + } +} + +int socks_process(struct socks_decoder_info *socks_decoder_info, struct session *sess, struct socks_tunnel_stream *stream, const char *payload, size_t payload_len) +{ + if (payload_len == 0) + { + return 0; + } + + switch(stream->state) + { + case STATE_INIT: + if (socks_rough_rec(payload, payload_len) < 0) + { + stream->state = STATE_FAILED; + return -1; + } + stream->state = STATE_OPENING; + [[fallthrough]];//continue execute STATE_OPENING + case STATE_OPENING: + switch (session_get_flow_type(sess)) + { + case FLOW_TYPE_C2S: + c2s_handler(stream, payload, payload_len); + break; + case FLOW_TYPE_S2C: + s2c_handler(stream, payload, payload_len); + break; + default: + break; + } + + if (stream->client_state == SS_END && stream->server_state == SS_END) + { + if (session_mq_publish_message(sess, socks_decoder_info->socks_decoder_topic_id, &stream->info) < 0) + { + STELLAR_LOG_FATAL(socks_decoder_info->log_handle, SOCKS_LOG_MOUDLE, "session_mq_publish_message OPENING failed"); + } + stellar_session_plugin_dettach_current_session(sess); + } + else if (stream->client_state == SS_FAILED || stream->server_state == SS_FAILED) + { + //not a socks proxy + stream->state = STATE_FAILED; + return -1; + } + break; + default: + return -1; + } + + return 0; +} + +void socks_decoder_on_message(struct session *sess, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + UNUSED(per_session_ctx); + UNUSED(topic_id); + UNUSED(msg); + + struct socks_decoder_info *socks_decoder_info = (struct socks_decoder_info *)plugin_env; + struct socks_tunnel_stream *socks_tunel_stream = (struct socks_tunnel_stream *)session_exdata_get(sess, socks_decoder_info->sess_exdata_idx); + const char *payload = NULL; + size_t payload_len = 0; + const struct packet *pkt = NULL; + + if (socks_tunel_stream == NULL) + { + socks_tunel_stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + session_exdata_set(sess, socks_decoder_info->sess_exdata_idx, socks_tunel_stream); + } + + pkt = session_get0_current_packet(sess); + payload = packet_get_payload(pkt); + payload_len = packet_get_payload_len(pkt); + + if (socks_process(socks_decoder_info, sess, socks_tunel_stream, payload, payload_len) < 0) + { + stellar_session_plugin_dettach_current_session(sess); + } +} + +extern "C" void *socks_decoder_init(struct stellar *st) +{ + struct socks_decoder_info *socks_decoder_info = (struct socks_decoder_info *)calloc(1, sizeof(struct socks_decoder_info)); + + socks_decoder_info->sess_exdata_idx= stellar_exdata_new_index(st, "SOCKS_DECODER_SESS_CTX", socks_decoder_session_exdata_free, NULL); + + socks_decoder_info->st = st; + socks_decoder_info->log_handle = stellar_get_logger(st); + + socks_decoder_info->plugin_id = stellar_session_plugin_register(st, NULL, NULL, socks_decoder_info); + if (socks_decoder_info->plugin_id < 0) + { + STELLAR_LOG_FATAL(socks_decoder_info->log_handle, SOCKS_LOG_MOUDLE, "stellar_session_plugin_register failed"); + goto ERROR; + + } + + socks_decoder_info->socks_decoder_topic_id = stellar_mq_create_topic(st, SOCKS_MESSAGE_TOPIC, NULL, NULL); + if (socks_decoder_info->socks_decoder_topic_id < 0) + { + STELLAR_LOG_FATAL(socks_decoder_info->log_handle, SOCKS_LOG_MOUDLE, "stellar_session_mq_create_topic failed"); + goto ERROR; + } + + socks_decoder_info->tcp_topic_id = stellar_mq_get_topic_id(st, TOPIC_TCP_STREAM); + if (socks_decoder_info->tcp_topic_id < 0) + { + STELLAR_LOG_FATAL(socks_decoder_info->log_handle, SOCKS_LOG_MOUDLE, "stellar_session_mq_get_topic_id failed"); + goto ERROR; + } + + if (stellar_session_mq_subscribe(st, socks_decoder_info->tcp_topic_id, socks_decoder_on_message, socks_decoder_info->plugin_id) < 0) + { + STELLAR_LOG_FATAL(socks_decoder_info->log_handle, SOCKS_LOG_MOUDLE, "stellar_session_mq_subscribe tcp_topic_id failed"); + goto ERROR; + } + + return socks_decoder_info; + +ERROR: + if (socks_decoder_info != NULL) + { + free(socks_decoder_info); + } + perror("socks_decoder init failed"); + exit(-1); +} + +extern "C" void socks_decoder_exit(void *plugin_env) +{ + struct socks_decoder_info *socks_decoder_info = (struct socks_decoder_info *)plugin_env; + + if (socks_decoder_info != NULL) + { + free(socks_decoder_info); + } + + return; +} \ No newline at end of file diff --git a/decoders/socks/socks_decoder_internal.h b/decoders/socks/socks_decoder_internal.h new file mode 100644 index 0000000..8749c62 --- /dev/null +++ b/decoders/socks/socks_decoder_internal.h @@ -0,0 +1,56 @@ +#include "stellar/socks_decoder.h" + +#define SOCKS_FIELD_VER_4 4 +#define SOCKS_FIELD_VER_5 5 + +#define SOCKS5_REQUEST_METHOD_MIN_LEN 3 +#define SOCKS5_REQUEST_MIN_LEN 6 +#define SOCKS_VERSION_TYPE_SOCKS4 4 +#define SOCKS_VERSION_TYPE_SOCKS5 5 + +#define SOCKS_CMD_CONNECT 0x01 +#define SOCKS_CMD_BIND 0x02 +#define SOCKS_CMD_UDP 0x03 + +#define SOCKS5_RSV_DEFAULT 0 +#define SOCKS_ATYPE_IP4 1 +#define SOCKS_ATYPE_IP6 4 +#define SOCKS_ATYPE_FQDN 3 + +#define SOCKS5_AUTH_NONE 0x00 +#define SOCKS5_AUTH_PASS 0x02 + +#define SOCKS_LOG_MOUDLE "SOCKS_DECODER" + +struct socks_decoder_info +{ + int plugin_id; + int sess_exdata_idx; + struct stellar *st; + struct logger *log_handle; + int socks_decoder_topic_id; + int tcp_topic_id; +}; + +enum socks_establish_state +{ + SS_BEGIN = 0, + SS_SUB, + SS_END, + SS_FAILED +}; + +enum socks_internal_state +{ + STATE_INIT, + STATE_OPENING, + STATE_FAILED +}; + +struct socks_tunnel_stream +{ + enum socks_internal_state state; + enum socks_establish_state client_state; + enum socks_establish_state server_state; + struct socks_info info; +}; \ No newline at end of file diff --git a/decoders/stratum/CMakeLists.txt b/decoders/stratum/CMakeLists.txt new file mode 100644 index 0000000..757555e --- /dev/null +++ b/decoders/stratum/CMakeLists.txt @@ -0,0 +1,14 @@ +add_definitions(-fPIC) +include_directories(${CMAKE_SOURCE_DIR}/deps) +include_directories(${CMAKE_BINARY_DIR}/vendors/cjson/src/cjson/include) + +set(STRATUM_SRC stratum_decoder.cpp) + +add_library(stratum STATIC ${STRATUM_SRC}) +add_library(stratum_dyn SHARED ${STRATUM_SRC}) +set_target_properties(stratum PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version.map") + +set_target_properties(stratum PROPERTIES PREFIX "") + +target_link_libraries(stratum_dyn) +set_target_properties(stratum_dyn PROPERTIES PREFIX "") \ No newline at end of file diff --git a/decoders/stratum/stratum_decoder.cpp b/decoders/stratum/stratum_decoder.cpp new file mode 100644 index 0000000..3267817 --- /dev/null +++ b/decoders/stratum/stratum_decoder.cpp @@ -0,0 +1,311 @@ +#include +#include +#include + +#include "cJSON.h" +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" +#include "stellar/stratum_decoder.h" +#include "stellar/log.h" + +#define unused(x) ((void)(x)) + +#define STRATUM_LOG_MOUDLE "STRATUM_DECODER" + +//字段内容宏 +#define METHOD_STR "method" +#define WORKER_STR "worker" +#define PARAMS_STR "params" +#define AGENT_STR "agent" + +enum stratum_field_type +{ + CRYPTOCURRENCY_FLAG = 1, + MINING_POOL_FLAG, + MINING_PROGRAM_FLAG, + MINING_SUBSCRIBE_FLAG, +}; + +struct stratum_decoder_info +{ + int plugin_id; + struct stellar *st; + struct logger *log_handle; + int tcp_topic_id; + int stratum_decoder_topic_id; +}; + +void free_stratum_filed(struct stratum_field *stratum_field) +{ + if(stratum_field!=NULL){ + if(stratum_field->mining_program.iov_base != NULL){ + free(stratum_field->mining_program.iov_base); + stratum_field->mining_program.iov_len = 0; + } + if(stratum_field->mining_pools.iov_base != NULL){ + free(stratum_field->mining_pools.iov_base); + stratum_field->mining_pools.iov_len = 0; + } + if(stratum_field->mining_subscribe.iov_base != NULL){ + free(stratum_field->mining_subscribe.iov_base); + stratum_field->mining_subscribe.iov_len = 0; + } + free(stratum_field); + } + return; +} + +void stratum_decoder_session_msg_free_cb(void *msg, void *msg_free_arg) +{ + unused(msg_free_arg); + + struct stratum_field *stratum_field = (struct stratum_field *)msg; + + free_stratum_filed(stratum_field); + + return; +} + +int stratum_field_assign(char *content, struct stratum_field* stratum_field,int field_range) +{ + switch (field_range) + { + case MINING_POOL_FLAG: + stratum_field->mining_pools.iov_len=strlen(content); + stratum_field->mining_pools.iov_base=(char*)malloc(stratum_field->mining_pools.iov_len+1); + memcpy(stratum_field->mining_pools.iov_base, content, stratum_field->mining_pools.iov_len); + ((char*)stratum_field->mining_pools.iov_base)[stratum_field->mining_pools.iov_len]='\0'; + break; + case MINING_PROGRAM_FLAG: + stratum_field->mining_program.iov_len=strlen(content); + stratum_field->mining_program.iov_base=(char*)malloc(stratum_field->mining_program.iov_len+1); + memcpy(stratum_field->mining_program.iov_base, content, stratum_field->mining_program.iov_len); + ((char*)stratum_field->mining_program.iov_base)[stratum_field->mining_program.iov_len]='\0'; + break; + case MINING_SUBSCRIBE_FLAG: + stratum_field->mining_subscribe.iov_len=strlen(content); + stratum_field->mining_subscribe.iov_base=(char*)malloc(stratum_field->mining_subscribe.iov_len+1); + memcpy(stratum_field->mining_subscribe.iov_base, content,stratum_field->mining_subscribe.iov_len); + ((char*)stratum_field->mining_subscribe.iov_base)[stratum_field->mining_subscribe.iov_len]='\0'; + break; + default: + return -1; + } + + return 0; +} + +struct stratum_field *stratum_json_decode(struct stratum_decoder_info *stratum_decoder_info, char *raw_json_str) +{ + + if(raw_json_str==NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode error!:raw_json_str is null! "); + return NULL; + } + + cJSON *root = cJSON_Parse(raw_json_str); + if (root == NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode error!:root_json is null,error: %s ",cJSON_GetErrorPtr()); + return NULL; + } + + cJSON *method_item = cJSON_GetObjectItem(root, METHOD_STR); + if(method_item==NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode error!:not_found '%s' in raw_json_str ", METHOD_STR); + cJSON_Delete(root); + return NULL; + } + + struct stratum_field *stratum_field = (struct stratum_field *)calloc(1, sizeof(struct stratum_field)); + int field_range = 0; + if(cJSON_IsString(method_item)){ + int assign_ret = 0; + STELLAR_LOG_DEBUG(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode,find '%s':%s\n", METHOD_STR, method_item->valuestring); + + if((strncasecmp("mining.subscribe", method_item->valuestring,strlen("mining.subscribe")) == 0) + ||(strncasecmp("login", method_item->valuestring,strlen("login")) == 0)){ + field_range = MINING_SUBSCRIBE_FLAG; + assign_ret = stratum_field_assign(raw_json_str, stratum_field, field_range); + + cJSON *paras_item = cJSON_GetObjectItem(root, PARAMS_STR); + if(paras_item == NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!not_found '%s' in raw_json_str ", PARAMS_STR); + goto err_ret; + } + + if(cJSON_IsArray(paras_item)){ + int asize = cJSON_GetArraySize(paras_item); + stratum_field->type = OTHER; + cJSON *array_item = cJSON_GetArrayItem(paras_item, 0); + if(cJSON_IsString(array_item)){ + field_range = MINING_PROGRAM_FLAG; + assign_ret = stratum_field_assign(array_item->valuestring, stratum_field, field_range); + } + if(asize>2){ + array_item = cJSON_GetArrayItem(paras_item, 2); + if(cJSON_IsString(array_item)){ + field_range = MINING_POOL_FLAG; + assign_ret = stratum_field_assign(array_item->valuestring, stratum_field, field_range); + } + } + }else if(cJSON_IsObject(paras_item) || cJSON_IsRaw(paras_item)){ + cJSON *agent_item = cJSON_GetObjectItem(paras_item, AGENT_STR); + if(agent_item == NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!not_found '%s' in raw_json_str ", AGENT_STR); + goto err_ret; + } + if(cJSON_IsString(agent_item)){ + field_range = MINING_PROGRAM_FLAG; + stratum_field->type = OTHER; + assign_ret = stratum_field_assign(agent_item->valuestring, stratum_field, field_range); + } + }else{ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!found '%s',json_value_type:%d\n ", PARAMS_STR, paras_item->type); + goto err_ret; + } + }else if(strncasecmp("eth_submitLogin", method_item->valuestring, strlen("eth_submitLogin")) == 0){ + field_range = MINING_SUBSCRIBE_FLAG; + assign_ret = stratum_field_assign(raw_json_str, stratum_field, field_range); + + cJSON *worker_item = cJSON_GetObjectItem(root, WORKER_STR); + if(worker_item == NULL){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!not_found '%s' in raw_json_str ", WORKER_STR); + goto err_ret; + } + if(cJSON_IsString(worker_item)){ + field_range = MINING_PROGRAM_FLAG; + stratum_field->type = ETH; + assign_ret = stratum_field_assign(worker_item->valuestring, stratum_field, field_range); + }else{ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!found '%s',json_value_type:%d\n ", WORKER_STR, worker_item->type); + goto err_ret; + } + }else{ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!found '%s',json_value_type:%d\n ", METHOD_STR, method_item->type); + goto err_ret; + } + + if(assign_ret<0){ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "field_assign_error:raw_json_str:%s\n ", raw_json_str); + goto err_ret; + } + cJSON_Delete(root); + return stratum_field; + }else{ + STELLAR_LOG_INFO(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "json_decode:error!found '%s',json_value_type:%d\n ", METHOD_STR, method_item->type); + goto err_ret; + } + +err_ret: + cJSON_Delete(root); + free_stratum_filed(stratum_field); + return NULL; +} + +struct stratum_field *stratum_data_process(struct stratum_decoder_info *stratum_decoder_info, const char *tcpdata, size_t datalen) +{ + if(tcpdata == NULL || datalen == 0) + { + return NULL; + } + + char *tcp_json=(char*)malloc(datalen+1); + memcpy(tcp_json, tcpdata, datalen); + tcp_json[datalen]='\0'; + + struct stratum_field *stratum_field=stratum_json_decode(stratum_decoder_info, tcp_json); + if(stratum_field==NULL) + { + STELLAR_LOG_DEBUG(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "payload_decode failed!stratum_field is null"); + } + + free(tcp_json); + tcp_json=NULL; + + return stratum_field; + +} + +void stratum_decoder_tcp_on_msg_cb(struct session *sess, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + unused(topic_id); + unused(per_session_ctx); + unused(msg); + + struct stratum_decoder_info *stratum_decoder_info = (struct stratum_decoder_info *)plugin_env; + + const struct packet *pkt = session_get0_current_packet(sess); + const char *payload = packet_get_payload(pkt); + size_t payload_len = packet_get_payload_len(pkt); + + struct stratum_field *stratum_field = stratum_data_process(stratum_decoder_info, payload, payload_len); + if (stratum_field != NULL) + { + if (session_mq_publish_message(sess, stratum_decoder_info->stratum_decoder_topic_id, stratum_field) < 0) + { + STELLAR_LOG_FATAL(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "stratum_decoder_tcp_on_msg_cb:session_mq_publish_message failed"); + free_stratum_filed(stratum_field); + } + stellar_session_plugin_dettach_current_session(sess); + } + + return; +} + +extern "C" void *stratum_decoder_init(struct stellar *st) +{ + struct stratum_decoder_info *stratum_decoder_info = (struct stratum_decoder_info *)malloc(sizeof(struct stratum_decoder_info)); + + stratum_decoder_info->st = st; + stratum_decoder_info->log_handle = stellar_get_logger(st); + + stratum_decoder_info->plugin_id = stellar_session_plugin_register(st, NULL, NULL, stratum_decoder_info); + if (stratum_decoder_info->plugin_id < 0) + { + STELLAR_LOG_FATAL(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "stellar_session_plugin_register failed"); + goto ERROR; + } + + stratum_decoder_info->stratum_decoder_topic_id = stellar_mq_create_topic(st, STRATUM_MESSAGE_TOPIC, stratum_decoder_session_msg_free_cb, NULL); + if (stratum_decoder_info->stratum_decoder_topic_id < 0) + { + STELLAR_LOG_FATAL(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "stellar_session_mq_create_topic failed"); + goto ERROR; + } + + stratum_decoder_info->tcp_topic_id = stellar_mq_get_topic_id(st, TOPIC_TCP_STREAM); + if (stratum_decoder_info->tcp_topic_id < 0) + { + STELLAR_LOG_FATAL(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "stellar_session_mq_get_topic_id failed"); + goto ERROR; + } + + if (stellar_session_mq_subscribe(st, stratum_decoder_info->tcp_topic_id, stratum_decoder_tcp_on_msg_cb, stratum_decoder_info->plugin_id) < 0) + { + STELLAR_LOG_FATAL(stratum_decoder_info->log_handle, STRATUM_LOG_MOUDLE, "stellar_session_mq_subscribe failed"); + goto ERROR; + } + + return stratum_decoder_info; + +ERROR: + if (stratum_decoder_info) + { + free(stratum_decoder_info); + } + return NULL; +} + +extern "C" void stratum_decoder_exit(void *plugin_env) +{ + struct stratum_decoder_info *stratum_decoder_info = (struct stratum_decoder_info *)plugin_env; + + if (stratum_decoder_info != NULL) + { + free(stratum_decoder_info); + } + + return; +} \ No newline at end of file diff --git a/include/stellar/session_flags.h b/include/stellar/session_flags.h new file mode 100644 index 0000000..2aeace8 --- /dev/null +++ b/include/stellar/session_flags.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#define MESSAGE_MAGIC 0x12345678 + +#define SESSION_FLAGS_MESSAGE_TOPIC "TOPIC_SESSION_FLAGS" + +enum +{ + session_flags_bulky_mask = 1, + session_flags_cbr_mask, + session_flags_local_client_mask, + session_flags_local_server_mask, + session_flags_download_mask, + session_flags_interactive_mask, + session_flags_inbound_mask, + session_flags_outbound_mask, + session_flags_pseudo_unidirectional_mask, + session_flags_streaming_mask, + session_flags_unidirectional_mask, + session_flags_random_looking_mask, + session_flags_c2s_mask, + session_flags_s2c_mask, + session_flags_bidirectional_mask, + session_flags_tunneling_mask, + session_flags_all_mask +}; + +#define SESSION_FLAGS_START (0x0000000000000001) +#define SESSION_FLAGS_BULKY (SESSION_FLAGS_START << session_flags_bulky_mask) +#define SESSION_FLAGS_CBR (SESSION_FLAGS_START << session_flags_cbr_mask) +#define SESSION_FLAGS_LOCAL_CLIENT (SESSION_FLAGS_START << session_flags_local_client_mask) +#define SESSION_FLAGS_LOCAL_SERVER (SESSION_FLAGS_START << session_flags_local_server_mask) +#define SESSION_FLAGS_DOWNLOAD (SESSION_FLAGS_START << session_flags_download_mask) +#define SESSION_FLAGS_INTERACTIVE (SESSION_FLAGS_START << session_flags_interactive_mask) +#define SESSION_FLAGS_INBOUND (SESSION_FLAGS_START << session_flags_inbound_mask) +#define SESSION_FLAGS_OUTBOUND (SESSION_FLAGS_START << session_flags_outbound_mask) +#define SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL (SESSION_FLAGS_START << session_flags_pseudo_unidirectional_mask) +#define SESSION_FLAGS_STREAMING (SESSION_FLAGS_START << session_flags_streaming_mask) +#define SESSION_FLAGS_UNIDIRECTIONAL (SESSION_FLAGS_START << session_flags_unidirectional_mask) +#define SESSION_FLAGS_RANDOM_LOOKING (SESSION_FLAGS_START << session_flags_random_looking_mask) +#define SESSION_FLAGS_C2S (SESSION_FLAGS_START << session_flags_c2s_mask) +#define SESSION_FLAGS_S2C (SESSION_FLAGS_START << session_flags_s2c_mask) +#define SESSION_FLAGS_BIDIRECTIONAL (SESSION_FLAGS_START << session_flags_bidirectional_mask) +#define SESSION_FLAGS_TUNNELING (SESSION_FLAGS_START << session_flags_tunneling_mask) + +struct session_flags_message +{ + int magic; + uint64_t flags; + uint32_t array_num; + uint32_t *packet_sequence_array; +}; \ No newline at end of file diff --git a/include/stellar/socks_decoder.h b/include/stellar/socks_decoder.h new file mode 100644 index 0000000..c3034b8 --- /dev/null +++ b/include/stellar/socks_decoder.h @@ -0,0 +1,44 @@ +#include + +#include +#ifndef IPV6_ADDR_LEN +#define IPV6_ADDR_LEN (sizeof(struct in6_addr)) +#endif + + +#define SOCKS_MESSAGE_TOPIC "TOPIC_SOCKS" + + +enum socks_addr_type +{ + SOCKS_ADDR_IPV4, + SOCKS_ADDR_IPV6, + SOCKS_ADDR_FQDN +}; + +struct socks_addr +{ + enum socks_addr_type type; + union + { + uint32_t ipv4; /* network order */ + uint8_t ipv6[IPV6_ADDR_LEN] ; + struct iovec fqdn; + }; + uint16_t port; /* network order */ +}; + +enum socks_version +{ + SOCKS_VERSION_4, + SOCKS_VERSION_5 +}; + +struct socks_info +{ + enum socks_version version; + struct socks_addr dst_addr; + struct iovec user_name; + struct iovec password; +};//message data + \ No newline at end of file diff --git a/include/stellar/stratum_decoder.h b/include/stellar/stratum_decoder.h new file mode 100644 index 0000000..a6eed42 --- /dev/null +++ b/include/stellar/stratum_decoder.h @@ -0,0 +1,18 @@ +#include + +#define STRATUM_MESSAGE_TOPIC "TOPIC_STRATUM" + +enum cryptocurrency_type +{ + ETH=1, + OTHER=2 +}; + +struct stratum_field +{ + enum cryptocurrency_type type; + struct iovec mining_pools; + struct iovec mining_program; + struct iovec mining_subscribe; + +};//message data \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7f8f9f0..89f667b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,3 +3,6 @@ add_subdirectory(packet_tool) add_subdirectory(debug_plugin) add_subdirectory(lpi_plugin) add_subdirectory(decoders/http) +add_subdirectory(decoders/socks) +add_subdirectory(decoders/stratum) +add_subdirectory(decoders/session_flags) \ No newline at end of file diff --git a/test/decoders/session_flags/CMakeLists.txt b/test/decoders/session_flags/CMakeLists.txt new file mode 100644 index 0000000..4bf55ba --- /dev/null +++ b/test/decoders/session_flags/CMakeLists.txt @@ -0,0 +1,56 @@ +set(DECODER_NAME session_flags) + +add_library(${DECODER_NAME}_test SHARED session_flags_test_plugin.cpp) +add_dependencies(${DECODER_NAME}_test ${DECODER_NAME}) +set_target_properties(${DECODER_NAME}_test PROPERTIES PREFIX "") + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/testing) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(${CMAKE_BINARY_DIR}/vendors/cjson/src/cjson/include) +include_directories(${PROJECT_SOURCE_DIR}/decoders/session_flags) +include_directories(${PROJECT_SOURCE_DIR}/include/stellar) + +add_executable(gtest_session_flags_pcap session_flags_pcap_test.cpp + dummy.c + ${PROJECT_SOURCE_DIR}/decoders/session_flags/fet.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/onlinemean.c + ${PROJECT_SOURCE_DIR}/decoders/session_flags/session_flags_plugin.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/session_flags.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/tunneling.cpp) +target_link_libraries(gtest_session_flags_pcap gtest pcap hyperscan_static hyperscan_runtime_static logger cjson-static libmesa_sts) + +add_executable(gtest_session_flags_static session_flags_static_test.cpp + dummy.c + ${PROJECT_SOURCE_DIR}/decoders/session_flags/fet.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/onlinemean.c + ${PROJECT_SOURCE_DIR}/decoders/session_flags/session_flags_plugin.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/session_flags.cpp + ${PROJECT_SOURCE_DIR}/decoders/session_flags/tunneling.cpp) +target_link_libraries(gtest_session_flags_static gtest pcap hyperscan_static hyperscan_runtime_static logger cjson-static libmesa_sts) + +add_executable(session_flags_test_main plugin_test_main.cpp) +set_target_properties(session_flags_test_main + PROPERTIES + LINK_OPTIONS + "-rdynamic" + ) +set_target_properties(session_flags_test_main + PROPERTIES + LINK_FLAGS + "-rdynamic" + ) +set(LINK_FLAGS "-rdynamic") + +target_link_libraries(session_flags_test_main PUBLIC gtest cjson-static stellar_lib -Wl,--whole-archive packet_parser -Wl,--no-whole-archive) + +add_subdirectory(test_based_on_stellar) + +#copy pcap file folder to build directory +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/pcap DESTINATION ${CMAKE_BINARY_DIR}/test/decoders/session_flags) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_based_on_stellar/env/session_flags.toml DESTINATION ${CMAKE_BINARY_DIR}/test/decoders/session_flags/etc/session_flags/) + +include(GoogleTest) +gtest_discover_tests(gtest_session_flags_pcap) +gtest_discover_tests(gtest_session_flags_static) diff --git a/test/decoders/session_flags/dummy.c b/test/decoders/session_flags/dummy.c new file mode 100644 index 0000000..9227261 --- /dev/null +++ b/test/decoders/session_flags/dummy.c @@ -0,0 +1,167 @@ +#include +#include + +#include "dummy.h" + +#define UNUSED(x) (void)(x) + +struct session g_sess; + +void session_set_current_payload(struct session *sess, char *payload, int payload_len) +{ + UNUSED(sess); + g_sess.payload_len = payload_len; + g_sess.payload = payload; +} + +int session_exdata_set(struct session *sess, int idx, void *ex_ptr) +{ + UNUSED(sess); + UNUSED(idx); + UNUSED(ex_ptr); + + return 0; +} + +struct logger *stellar_get_logger(struct stellar *st) +{ + UNUSED(st); + + return (struct logger *)1; +} + +void *session_exdata_get(struct session *sess, int idx) +{ + UNUSED(sess); + UNUSED(idx); + + return NULL; +} + +const struct packet *session_get0_current_packet(const struct session *sess) +{ + UNUSED(sess); + + return NULL; +} + +uint16_t packet_get_payload_len(const struct packet *pkt) +{ + UNUSED(pkt); + + return g_sess.payload_len; +} + +const char *packet_get_payload(const struct packet *pkt) +{ + UNUSED(pkt); + + return g_sess.payload; +} + +enum session_direction session_get_direction(const struct session *sess) +{ + UNUSED(sess); + + return SESSION_DIRECTION_OUTBOUND; +} + +enum flow_type session_get_flow_type(const struct session *sess) +{ + UNUSED(sess); + + return FLOW_TYPE_C2S; +} + +const char *session_get0_readable_addr(const struct session *sess) +{ + UNUSED(sess); + + return NULL; +} + +uint16_t packet_get_raw_len(const struct packet *pkt) +{ + UNUSED(pkt); + + return 0; +} + +const struct timeval *packet_get_timeval(const struct packet *pkt) +{ + UNUSED(pkt); + + return NULL; +} + +void stellar_session_plugin_dettach_current_session(struct session *sess) +{ + UNUSED(sess); +} + +int session_mq_publish_message(struct session *sess, int topic_id, void *msg) +{ + UNUSED(sess); + UNUSED(topic_id); + UNUSED(msg); + + return 0; +} + +int stellar_exdata_new_index(struct stellar *st, const char *name, stellar_exdata_free *free_func,void *arg) +{ + UNUSED(st); + UNUSED(name); + UNUSED(free_func); + UNUSED(arg); + + return 0; +} + +int stellar_mq_create_topic(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg) +{ + UNUSED(st); + UNUSED(topic_name); + UNUSED(msg_free_cb); + UNUSED(msg_free_arg); + + return 0; +} + +int stellar_mq_get_topic_id(struct stellar *st, const char *topic_name) +{ + UNUSED(st); + + if (strcmp(topic_name, TOPIC_TCP_INPUT) == 0) + { + return DUMMY_TCP_TOPIC_ID; + } + else if (strcmp(topic_name, TOPIC_UDP_INPUT) == 0) + { + return DUMMY_UDP_TOPIC_ID; + } + else + { + return -1; + } +} + +int stellar_session_mq_subscribe(struct stellar *st, int topic_id, on_session_msg_cb_func *plugin_on_msg_cb, int plugin_id) +{ + UNUSED(st); + UNUSED(topic_id); + UNUSED(plugin_on_msg_cb); + UNUSED(plugin_id); + + return 0; +} + +int stellar_session_plugin_register(struct stellar *st, session_ctx_new_func session_ctx_new, session_ctx_free_func session_ctx_free, void *plugin_env) +{ + UNUSED(st); + UNUSED(session_ctx_new); + UNUSED(session_ctx_free); + UNUSED(plugin_env); + + return 0; +} \ No newline at end of file diff --git a/test/decoders/session_flags/dummy.h b/test/decoders/session_flags/dummy.h new file mode 100644 index 0000000..aec8383 --- /dev/null +++ b/test/decoders/session_flags/dummy.h @@ -0,0 +1,18 @@ +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" + +#define DUMMY_TCP_TOPIC_ID 1 +#define DUMMY_UDP_TOPIC_ID 2 + +struct session //stub just for test +{ + int payload_len; + char *payload; +}; + +void session_set_current_payload(struct session *sess, char *payload, int payload_len); + +void *session_flags_plugin_init(struct stellar *st); +void session_flags_plugin_exit(void *arg); \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/1-dtls.192.168.44.32.pcap b/test/decoders/session_flags/pcap/1-dtls.192.168.44.32.pcap new file mode 100644 index 0000000..4fa6ce4 Binary files /dev/null and b/test/decoders/session_flags/pcap/1-dtls.192.168.44.32.pcap differ diff --git a/test/decoders/session_flags/pcap/192.168.56.19.56554.json b/test/decoders/session_flags/pcap/192.168.56.19.56554.json new file mode 100644 index 0000000..78d1fd1 --- /dev/null +++ b/test/decoders/session_flags/pcap/192.168.56.19.56554.json @@ -0,0 +1,20 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":4}", + "common_flags_2": 2123980808, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":4,\"frequency\":6,\"runs\":6,\"longest_run\":6,\"overlapping_template_matching\":6,\"random_excursions\":6,\"random_excursions_variant\":6,\"poker_detect\":6,\"runs_distribution\":6,\"self_correlation\":6,\"binary_derivative\":6}", + "common_flags_3": 2123980936, + "common_flags_str_3": "[Client is Local,Inbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":21,\"C2S\":1,\"S2C\":4,\"frequency\":6,\"runs\":6,\"longest_run\":6,\"overlapping_template_matching\":6,\"random_excursions\":6,\"random_excursions_variant\":6,\"poker_detect\":6,\"runs_distribution\":6,\"self_correlation\":6,\"binary_derivative\":6}", + "common_flags_4": 2123981960, + "common_flags_str_4": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_4": "{\"Client is Local\":1,\"Inbound\":21,\"Streaming\":100,\"C2S\":1,\"S2C\":4,\"frequency\":6,\"runs\":6,\"longest_run\":6,\"overlapping_template_matching\":6,\"random_excursions\":6,\"random_excursions_variant\":6,\"poker_detect\":6,\"runs_distribution\":6,\"self_correlation\":6,\"binary_derivative\":6}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/192.168.56.19.56555-47.93.59.84.443_869284834001082715.pcapng b/test/decoders/session_flags/pcap/192.168.56.19.56555-47.93.59.84.443_869284834001082715.pcapng new file mode 100644 index 0000000..b675a02 Binary files /dev/null and b/test/decoders/session_flags/pcap/192.168.56.19.56555-47.93.59.84.443_869284834001082715.pcapng differ diff --git a/test/decoders/session_flags/pcap/192.168.56.31.58530.json b/test/decoders/session_flags/pcap/192.168.56.31.58530.json new file mode 100644 index 0000000..67acb45 --- /dev/null +++ b/test/decoders/session_flags/pcap/192.168.56.31.58530.json @@ -0,0 +1,17 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2}", + "common_flags_2": 1185898504, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"block_frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"rank\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"binary_derivative\":4}", + "common_flags_3": 1185898632, + "common_flags_str_3": "[Client is Local,Inbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":34,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"block_frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"rank\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"binary_derivative\":4}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/192.168.56.31.58530.pcapng b/test/decoders/session_flags/pcap/192.168.56.31.58530.pcapng new file mode 100644 index 0000000..6abe0ed Binary files /dev/null and b/test/decoders/session_flags/pcap/192.168.56.31.58530.pcapng differ diff --git a/test/decoders/session_flags/pcap/192.168.64.61.62275.asymmetric.pcapng b/test/decoders/session_flags/pcap/192.168.64.61.62275.asymmetric.pcapng new file mode 100644 index 0000000..afff17d Binary files /dev/null and b/test/decoders/session_flags/pcap/192.168.64.61.62275.asymmetric.pcapng differ diff --git a/test/decoders/session_flags/pcap/192.168.64.61.62275.json b/test/decoders/session_flags/pcap/192.168.64.61.62275.json new file mode 100644 index 0000000..ea68bf3 --- /dev/null +++ b/test/decoders/session_flags/pcap/192.168.64.61.62275.json @@ -0,0 +1,14 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 1453269000, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"frequency\":3,\"block_frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"runs_distribution\":3,\"binary_derivative\":3}", + "common_flags_2": 1453269001, + "common_flags_str_2": "[Asymmetric,Client is Local]", + "common_flags_identify_info_2": "{\"Asymmetric\":10,\"Client is Local\":1,\"C2S\":1,\"frequency\":3,\"block_frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"runs_distribution\":3,\"binary_derivative\":3}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/192.168.64.67.53813.json b/test/decoders/session_flags/pcap/192.168.64.67.53813.json new file mode 100644 index 0000000..6893c7f --- /dev/null +++ b/test/decoders/session_flags/pcap/192.168.64.67.53813.json @@ -0,0 +1,14 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 2126340104, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 2126340232, + "common_flags_str_2": "[Client is Local,Inbound]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"Inbound\":18,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/192.168.64.67.53813.pcapng b/test/decoders/session_flags/pcap/192.168.64.67.53813.pcapng new file mode 100644 index 0000000..ffb6287 Binary files /dev/null and b/test/decoders/session_flags/pcap/192.168.64.67.53813.pcapng differ diff --git a/test/decoders/session_flags/pcap/1_result.json b/test/decoders/session_flags/pcap/1_result.json new file mode 100644 index 0000000..57df72d --- /dev/null +++ b/test/decoders/session_flags/pcap/1_result.json @@ -0,0 +1,11 @@ +[ + { + "common_flags_0": 8208, + "common_flags_str_0": "[Server is Local,C2S]", + "common_flags_identify_info_0": "1,1,", + "common_flags_1": 24592, + "common_flags_str_1": "[Server is Local,C2S,S2C]", + "common_flags_identify_info_1": "1,1,2,", + "name": "session_flags_test" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/bilibili-dtls.pcap b/test/decoders/session_flags/pcap/bilibili-dtls.pcap new file mode 100644 index 0000000..9316c01 Binary files /dev/null and b/test/decoders/session_flags/pcap/bilibili-dtls.pcap differ diff --git a/test/decoders/session_flags/pcap/bilibili.json b/test/decoders/session_flags/pcap/bilibili.json new file mode 100644 index 0000000..640957c --- /dev/null +++ b/test/decoders/session_flags/pcap/bilibili.json @@ -0,0 +1,23 @@ +[ + { + "common_flags_0": 16392, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"S2C\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":2,\"S2C\":1}", + "common_flags_2": 1585602568, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":2,\"S2C\":1,\"block_frequency\":5,\"overlapping_template_matching\":5,\"random_excursions\":5,\"random_excursions_variant\":5,\"poker_detect\":5,\"runs_distribution\":5,\"binary_derivative\":5}", + "common_flags_3": 1585602696, + "common_flags_str_3": "[Client is Local,Inbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":25,\"C2S\":2,\"S2C\":1,\"block_frequency\":5,\"overlapping_template_matching\":5,\"random_excursions\":5,\"random_excursions_variant\":5,\"poker_detect\":5,\"runs_distribution\":5,\"binary_derivative\":5}", + "common_flags_4": 1585603720, + "common_flags_str_4": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_4": "{\"Client is Local\":1,\"Inbound\":25,\"Streaming\":186,\"C2S\":2,\"S2C\":1,\"block_frequency\":5,\"overlapping_template_matching\":5,\"random_excursions\":5,\"random_excursions_variant\":5,\"poker_detect\":5,\"runs_distribution\":5,\"binary_derivative\":5}", + "common_flags_5": 1585636488, + "common_flags_str_5": "[Client is Local,Inbound,Streaming,Bidirectional]", + "common_flags_identify_info_5": "{\"Client is Local\":1,\"Inbound\":25,\"Streaming\":186,\"C2S\":2,\"S2C\":1,\"Bidirectional\":8551,\"block_frequency\":5,\"overlapping_template_matching\":5,\"random_excursions\":5,\"random_excursions_variant\":5,\"poker_detect\":5,\"runs_distribution\":5,\"binary_derivative\":5}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/dns_asymmetric.json b/test/decoders/session_flags/pcap/dns_asymmetric.json new file mode 100644 index 0000000..3b3510b --- /dev/null +++ b/test/decoders/session_flags/pcap/dns_asymmetric.json @@ -0,0 +1,14 @@ +[ + { + "common_flags_0": 8208, + "common_flags_str_0": "[Server is Local]", + "common_flags_identify_info_0": "{\"Server is Local\":1,\"C2S\":1}", + "common_flags_1": 8209, + "common_flags_str_1": "[Asymmetric,Server is Local]", + "common_flags_identify_info_1": "{\"Asymmetric\":10,\"Server is Local\":1,\"C2S\":1}", + "common_flags_2": 24593, + "common_flags_str_2": "[Asymmetric,Server is Local]", + "common_flags_identify_info_2": "{\"Asymmetric\":10,\"Server is Local\":1,\"C2S\":1,\"S2C\":12}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/dns_asymmetric.pcap b/test/decoders/session_flags/pcap/dns_asymmetric.pcap new file mode 100644 index 0000000..116934f Binary files /dev/null and b/test/decoders/session_flags/pcap/dns_asymmetric.pcap differ diff --git a/test/decoders/session_flags/pcap/douyin.json b/test/decoders/session_flags/pcap/douyin.json new file mode 100644 index 0000000..739d1db --- /dev/null +++ b/test/decoders/session_flags/pcap/douyin.json @@ -0,0 +1,20 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2}", + "common_flags_2": 2124242952, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "common_flags_3": 2124244104, + "common_flags_str_3": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":6036,\"Streaming\":6036,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "common_flags_4": 2124244650, + "common_flags_str_4": "[Bulky,Client is Local,Download,Inbound,Pseudo Unidirectional,Streaming]", + "common_flags_identify_info_4": "{\"Bulky\":6042,\"Client is Local\":1,\"Download\":6042,\"Inbound\":6036,\"Pseudo Unidirectional\":6042,\"Streaming\":6036,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/douyin.pcap b/test/decoders/session_flags/pcap/douyin.pcap new file mode 100644 index 0000000..89e08d3 Binary files /dev/null and b/test/decoders/session_flags/pcap/douyin.pcap differ diff --git a/test/decoders/session_flags/pcap/ftp-data.pcap b/test/decoders/session_flags/pcap/ftp-data.pcap new file mode 100644 index 0000000..9517dde Binary files /dev/null and b/test/decoders/session_flags/pcap/ftp-data.pcap differ diff --git a/test/decoders/session_flags/pcap/https_download.json b/test/decoders/session_flags/pcap/https_download.json new file mode 100644 index 0000000..b0f735d --- /dev/null +++ b/test/decoders/session_flags/pcap/https_download.json @@ -0,0 +1,26 @@ +[{ + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local,C2S]", + "common_flags_identify_info_0": "1,1,", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local,C2S,S2C]", + "common_flags_identify_info_1": "1,1,2,", + "common_flags_2": 28680, + "common_flags_str_2": "[Client is Local,Random Looking,C2S,S2C]", + "common_flags_identify_info_2": "1,4,1,2,", + "common_flags_3": 28808, + "common_flags_str_3": "[Client is Local,Inbound,Random Looking,C2S,S2C]", + "common_flags_identify_info_3": "1,1188,4,1,2,", + "common_flags_4": 29832, + "common_flags_str_4": "[Client is Local,Inbound,Streaming,Random Looking,C2S,S2C]", + "common_flags_identify_info_4": "1,1188,1662,4,1,2,", + "common_flags_5": 30344, + "common_flags_str_5": "[Client is Local,Inbound,Pseudo Unidirectional,Streaming,Random Looking,C2S,S2C]", + "common_flags_identify_info_5": "1,1188,3546,1662,4,1,2,", + "common_flags_6": 30346, + "common_flags_str_6": "[Bulky,Client is Local,Inbound,Pseudo Unidirectional,Streaming,Random Looking,C2S,S2C]", + "common_flags_identify_info_6": "4095,1,1188,3546,1662,4,1,2,", + "common_flags_7": 30378, + "common_flags_str_7": "[Bulky,Client is Local,Download,Inbound,Pseudo Unidirectional,Streaming,Random Looking,C2S,S2C]", + "common_flags_identify_info_7": "4095,1,4201,1188,3546,1662,4,1,2," +}] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/https_download.pcap b/test/decoders/session_flags/pcap/https_download.pcap new file mode 100644 index 0000000..f2f5835 Binary files /dev/null and b/test/decoders/session_flags/pcap/https_download.pcap differ diff --git a/test/decoders/session_flags/pcap/mix-quic-ssl-quic-mail.pcap b/test/decoders/session_flags/pcap/mix-quic-ssl-quic-mail.pcap new file mode 100644 index 0000000..05f2d03 Binary files /dev/null and b/test/decoders/session_flags/pcap/mix-quic-ssl-quic-mail.pcap differ diff --git a/test/decoders/session_flags/pcap/mix.json b/test/decoders/session_flags/pcap/mix.json new file mode 100644 index 0000000..e3144b6 --- /dev/null +++ b/test/decoders/session_flags/pcap/mix.json @@ -0,0 +1,65 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2}", + "common_flags_2": 109076488, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4}", + "common_flags_3": 109078186, + "common_flags_str_3": "[Bulky,Client is Local,Download,Inbound,Pseudo Unidirectional,Streaming]", + "common_flags_identify_info_3": "{\"Bulky\":2250,\"Client is Local\":1,\"Download\":2250,\"Inbound\":2250,\"Pseudo Unidirectional\":2250,\"Streaming\":2250,\"C2S\":1,\"S2C\":2,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4}", + "name": "base_0" + }, + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 1451237384, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"overlapping_template_matching\":10,\"random_excursions\":10,\"random_excursions_variant\":10,\"runs_distribution\":10,\"binary_derivative\":10}", + "common_flags_2": 1451237385, + "common_flags_str_2": "[Asymmetric,Client is Local]", + "common_flags_identify_info_2": "{\"Asymmetric\":4168,\"Client is Local\":1,\"C2S\":1,\"overlapping_template_matching\":10,\"random_excursions\":10,\"random_excursions_variant\":10,\"runs_distribution\":10,\"binary_derivative\":10}", + "name": "base_1" + }, + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 2126323720, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 2126340104, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":6,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_3": 2126340232, + "common_flags_str_3": "[Client is Local,Inbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":29,\"C2S\":1,\"S2C\":6,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_2" + }, + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 1186291720, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"binary_derivative\":2}", + "common_flags_2": 1186291848, + "common_flags_str_2": "[Client is Local,Inbound]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"Inbound\":21,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"binary_derivative\":2}", + "common_flags_3": 1186292872, + "common_flags_str_3": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":21,\"Streaming\":100,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"binary_derivative\":2}", + "common_flags_4": 1186292874, + "common_flags_str_4": "[Bulky,Client is Local,Inbound,Streaming]", + "common_flags_identify_info_4": "{\"Bulky\":430,\"Client is Local\":1,\"Inbound\":21,\"Streaming\":100,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"binary_derivative\":2}", + "common_flags_5": 1186292878, + "common_flags_str_5": "[Bulky,CBR Streaming,Client is Local,Inbound,Streaming]", + "common_flags_identify_info_5": "{\"Bulky\":430,\"CBR Streaming\":6984,\"Client is Local\":1,\"Inbound\":21,\"Streaming\":100,\"C2S\":1,\"S2C\":2,\"frequency\":2,\"cumulative_sums\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"binary_derivative\":2}", + "name": "base_3" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/quic_asymmetric.json b/test/decoders/session_flags/pcap/quic_asymmetric.json new file mode 100644 index 0000000..68e3e37 --- /dev/null +++ b/test/decoders/session_flags/pcap/quic_asymmetric.json @@ -0,0 +1,17 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 2126323720, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 2126340104, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":14,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_3": 2126340232, + "common_flags_str_3": "[Client is Local,Inbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":84,\"C2S\":1,\"S2C\":14,\"frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/quic_asymmetric.pcapng b/test/decoders/session_flags/pcap/quic_asymmetric.pcapng new file mode 100644 index 0000000..5596a03 Binary files /dev/null and b/test/decoders/session_flags/pcap/quic_asymmetric.pcapng differ diff --git a/test/decoders/session_flags/pcap/quic_asymmetric_1.json b/test/decoders/session_flags/pcap/quic_asymmetric_1.json new file mode 100644 index 0000000..dab7c23 --- /dev/null +++ b/test/decoders/session_flags/pcap/quic_asymmetric_1.json @@ -0,0 +1,14 @@ +[ + { + "common_flags_0": 16392, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"S2C\":1}", + "common_flags_1": 1452294152, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"S2C\":1,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"binary_derivative\":2}", + "common_flags_2": 1452294153, + "common_flags_str_2": "[Asymmetric,Client is Local]", + "common_flags_identify_info_2": "{\"Asymmetric\":37,\"Client is Local\":1,\"S2C\":1,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/quic_asymmetric_1.pcap b/test/decoders/session_flags/pcap/quic_asymmetric_1.pcap new file mode 100644 index 0000000..bb55d52 Binary files /dev/null and b/test/decoders/session_flags/pcap/quic_asymmetric_1.pcap differ diff --git a/test/decoders/session_flags/pcap/quic_online_streaming.json b/test/decoders/session_flags/pcap/quic_online_streaming.json new file mode 100644 index 0000000..443d331 --- /dev/null +++ b/test/decoders/session_flags/pcap/quic_online_streaming.json @@ -0,0 +1,26 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 2124226568, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "common_flags_2": 2124242952, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":4,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "common_flags_3": 2124244104, + "common_flags_str_3": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Inbound\":291,\"Streaming\":291,\"C2S\":1,\"S2C\":4,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "common_flags_4": 2124244106, + "common_flags_str_4": "[Bulky,Client is Local,Inbound,Streaming]", + "common_flags_identify_info_4": "{\"Bulky\":630,\"Client is Local\":1,\"Inbound\":291,\"Streaming\":291,\"C2S\":1,\"S2C\":4,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "common_flags_5": 2124276874, + "common_flags_str_5": "[Bulky,Client is Local,Inbound,Streaming,Bidirectional]", + "common_flags_identify_info_5": "{\"Bulky\":630,\"Client is Local\":1,\"Inbound\":291,\"Streaming\":291,\"C2S\":1,\"S2C\":4,\"Bidirectional\":7315,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "common_flags_6": 2124276938, + "common_flags_str_6": "[Bulky,Client is Local,Interactive,Inbound,Streaming,Bidirectional]", + "common_flags_identify_info_6": "{\"Bulky\":630,\"Client is Local\":1,\"Interactive\":25786,\"Inbound\":291,\"Streaming\":291,\"C2S\":1,\"S2C\":4,\"Bidirectional\":7315,\"frequency\":3,\"cumulative_sums\":3,\"runs\":3,\"longest_run\":3,\"overlapping_template_matching\":3,\"random_excursions\":3,\"random_excursions_variant\":3,\"poker_detect\":3,\"runs_distribution\":3,\"self_correlation\":3,\"binary_derivative\":3}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/quic_online_streaming.pcap b/test/decoders/session_flags/pcap/quic_online_streaming.pcap new file mode 100644 index 0000000..9db5c49 Binary files /dev/null and b/test/decoders/session_flags/pcap/quic_online_streaming.pcap differ diff --git a/test/decoders/session_flags/pcap/ssh-interactive.json b/test/decoders/session_flags/pcap/ssh-interactive.json new file mode 100644 index 0000000..e6a3e40 --- /dev/null +++ b/test/decoders/session_flags/pcap/ssh-interactive.json @@ -0,0 +1,29 @@ +[ + { + "common_flags_0": 8208, + "common_flags_str_0": "[Server is Local]", + "common_flags_identify_info_0": "{\"Server is Local\":1,\"C2S\":1}", + "common_flags_1": 24592, + "common_flags_str_1": "[Server is Local]", + "common_flags_identify_info_1": "{\"Server is Local\":1,\"C2S\":1,\"S2C\":2}", + "common_flags_2": 111173648, + "common_flags_str_2": "[Server is Local]", + "common_flags_identify_info_2": "{\"Server is Local\":1,\"C2S\":1,\"S2C\":2,\"rank\":7,\"overlapping_template_matching\":7,\"random_excursions\":7,\"random_excursions_variant\":7}", + "common_flags_3": 111173904, + "common_flags_str_3": "[Server is Local,Outbound]", + "common_flags_identify_info_3": "{\"Server is Local\":1,\"Outbound\":40,\"C2S\":1,\"S2C\":2,\"rank\":7,\"overlapping_template_matching\":7,\"random_excursions\":7,\"random_excursions_variant\":7}", + "common_flags_4": 111173968, + "common_flags_str_4": "[Server is Local,Interactive,Outbound]", + "common_flags_identify_info_4": "{\"Server is Local\":1,\"Interactive\":52,\"Outbound\":40,\"C2S\":1,\"S2C\":2,\"rank\":7,\"overlapping_template_matching\":7,\"random_excursions\":7,\"random_excursions_variant\":7}", + "name": "base_0" + }, + { + "common_flags_0": 16400, + "common_flags_str_0": "[Server is Local]", + "common_flags_identify_info_0": "{\"Server is Local\":1,\"S2C\":1}", + "common_flags_1": 16401, + "common_flags_str_1": "[Asymmetric,Server is Local]", + "common_flags_identify_info_1": "{\"Asymmetric\":2,\"Server is Local\":1,\"S2C\":1}", + "name": "base_1" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/ssh-interactive.pcap b/test/decoders/session_flags/pcap/ssh-interactive.pcap new file mode 100644 index 0000000..6efe2ab Binary files /dev/null and b/test/decoders/session_flags/pcap/ssh-interactive.pcap differ diff --git a/test/decoders/session_flags/pcap/telegram_mtproto_ipv4_key_1.pcap b/test/decoders/session_flags/pcap/telegram_mtproto_ipv4_key_1.pcap new file mode 100644 index 0000000..7b966dd Binary files /dev/null and b/test/decoders/session_flags/pcap/telegram_mtproto_ipv4_key_1.pcap differ diff --git a/test/decoders/session_flags/pcap/telegram_mtproto_ipv6_key_1.pcap b/test/decoders/session_flags/pcap/telegram_mtproto_ipv6_key_1.pcap new file mode 100644 index 0000000..e0b3144 Binary files /dev/null and b/test/decoders/session_flags/pcap/telegram_mtproto_ipv6_key_1.pcap differ diff --git a/test/decoders/session_flags/pcap/tencent_meeting_video.json b/test/decoders/session_flags/pcap/tencent_meeting_video.json new file mode 100644 index 0000000..bb29da4 --- /dev/null +++ b/test/decoders/session_flags/pcap/tencent_meeting_video.json @@ -0,0 +1,23 @@ +[ + { + "common_flags_0": 16392, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"S2C\":1}", + "common_flags_1": 2126462984, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"S2C\":1,\"frequency\":2,\"block_frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 2126471176, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":5,\"S2C\":1,\"frequency\":2,\"block_frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_3": 2126471432, + "common_flags_str_3": "[Client is Local,Outbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Outbound\":414,\"C2S\":5,\"S2C\":1,\"frequency\":2,\"block_frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_4": 2126504200, + "common_flags_str_4": "[Client is Local,Outbound,Bidirectional]", + "common_flags_identify_info_4": "{\"Client is Local\":1,\"Outbound\":414,\"C2S\":5,\"S2C\":1,\"Bidirectional\":2448,\"frequency\":2,\"block_frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_5": 2126504204, + "common_flags_str_5": "[CBR Streaming,Client is Local,Outbound,Bidirectional]", + "common_flags_identify_info_5": "{\"CBR Streaming\":4095,\"Client is Local\":1,\"Outbound\":414,\"C2S\":5,\"S2C\":1,\"Bidirectional\":2448,\"frequency\":2,\"block_frequency\":2,\"cumulative_sums\":2,\"runs\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/tencent_meeting_video.pcapng b/test/decoders/session_flags/pcap/tencent_meeting_video.pcapng new file mode 100644 index 0000000..6013cfb Binary files /dev/null and b/test/decoders/session_flags/pcap/tencent_meeting_video.pcapng differ diff --git a/test/decoders/session_flags/pcap/tencent_meeting_voice.json b/test/decoders/session_flags/pcap/tencent_meeting_voice.json new file mode 100644 index 0000000..a81e3c5 --- /dev/null +++ b/test/decoders/session_flags/pcap/tencent_meeting_voice.json @@ -0,0 +1,20 @@ +[ + { + "common_flags_0": 16392, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"S2C\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":2,\"S2C\":1}", + "common_flags_2": 2123980808, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":2,\"S2C\":1,\"frequency\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "common_flags_3": 2123981064, + "common_flags_str_3": "[Client is Local,Outbound]", + "common_flags_identify_info_3": "{\"Client is Local\":1,\"Outbound\":21,\"C2S\":2,\"S2C\":1,\"frequency\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "common_flags_4": 2124013832, + "common_flags_str_4": "[Client is Local,Outbound,Bidirectional]", + "common_flags_identify_info_4": "{\"Client is Local\":1,\"Outbound\":21,\"C2S\":2,\"S2C\":1,\"Bidirectional\":606,\"frequency\":4,\"runs\":4,\"longest_run\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"poker_detect\":4,\"runs_distribution\":4,\"self_correlation\":4,\"binary_derivative\":4}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/tencent_meeting_voice.pcapng b/test/decoders/session_flags/pcap/tencent_meeting_voice.pcapng new file mode 100644 index 0000000..2935fe5 Binary files /dev/null and b/test/decoders/session_flags/pcap/tencent_meeting_voice.pcapng differ diff --git a/test/decoders/session_flags/pcap/tls1.2.pcapng b/test/decoders/session_flags/pcap/tls1.2.pcapng new file mode 100644 index 0000000..ad1a1e0 Binary files /dev/null and b/test/decoders/session_flags/pcap/tls1.2.pcapng differ diff --git a/test/decoders/session_flags/pcap/tls1.2_no_reuse.pcap b/test/decoders/session_flags/pcap/tls1.2_no_reuse.pcap new file mode 100644 index 0000000..e911f2b Binary files /dev/null and b/test/decoders/session_flags/pcap/tls1.2_no_reuse.pcap differ diff --git a/test/decoders/session_flags/pcap/tls_over_tls_1.2_no_reuse.pcap b/test/decoders/session_flags/pcap/tls_over_tls_1.2_no_reuse.pcap new file mode 100644 index 0000000..9deb86f Binary files /dev/null and b/test/decoders/session_flags/pcap/tls_over_tls_1.2_no_reuse.pcap differ diff --git a/test/decoders/session_flags/pcap/unidirectional.json b/test/decoders/session_flags/pcap/unidirectional.json new file mode 100644 index 0000000..a681f54 --- /dev/null +++ b/test/decoders/session_flags/pcap/unidirectional.json @@ -0,0 +1,14 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 24584, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2}", + "common_flags_2": 1185898504, + "common_flags_str_2": "[Client is Local]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"frequency\":4,\"block_frequency\":4,\"cumulative_sums\":4,\"runs\":4,\"rank\":4,\"overlapping_template_matching\":4,\"random_excursions\":4,\"random_excursions_variant\":4,\"binary_derivative\":4}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/unidirectional.pcap b/test/decoders/session_flags/pcap/unidirectional.pcap new file mode 100644 index 0000000..9e7b65a Binary files /dev/null and b/test/decoders/session_flags/pcap/unidirectional.pcap differ diff --git a/test/decoders/session_flags/pcap/wechat_voice_call.json b/test/decoders/session_flags/pcap/wechat_voice_call.json new file mode 100644 index 0000000..a2077d6 --- /dev/null +++ b/test/decoders/session_flags/pcap/wechat_voice_call.json @@ -0,0 +1,20 @@ +[ + { + "common_flags_0": 8208, + "common_flags_str_0": "[Server is Local]", + "common_flags_identify_info_0": "{\"Server is Local\":1,\"C2S\":1}", + "common_flags_1": 2123390992, + "common_flags_str_1": "[Server is Local]", + "common_flags_identify_info_1": "{\"Server is Local\":1,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 2123391120, + "common_flags_str_2": "[Server is Local,Inbound]", + "common_flags_identify_info_2": "{\"Server is Local\":1,\"Inbound\":83,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_3": 2123391124, + "common_flags_str_3": "[CBR Streaming,Server is Local,Inbound]", + "common_flags_identify_info_3": "{\"CBR Streaming\":3634,\"Server is Local\":1,\"Inbound\":83,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_4": 2123423892, + "common_flags_str_4": "[CBR Streaming,Server is Local,Inbound,Bidirectional]", + "common_flags_identify_info_4": "{\"CBR Streaming\":3634,\"Server is Local\":1,\"Inbound\":83,\"C2S\":1,\"S2C\":2,\"Bidirectional\":3808,\"longest_run\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"poker_detect\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/pcap/wechat_voice_call.pcap b/test/decoders/session_flags/pcap/wechat_voice_call.pcap new file mode 100644 index 0000000..4690892 Binary files /dev/null and b/test/decoders/session_flags/pcap/wechat_voice_call.pcap differ diff --git a/test/decoders/session_flags/pcap/youtube-quic.pcap b/test/decoders/session_flags/pcap/youtube-quic.pcap new file mode 100644 index 0000000..b6ae0cd Binary files /dev/null and b/test/decoders/session_flags/pcap/youtube-quic.pcap differ diff --git a/test/decoders/session_flags/pcap/youtube.json b/test/decoders/session_flags/pcap/youtube.json new file mode 100644 index 0000000..6c055db --- /dev/null +++ b/test/decoders/session_flags/pcap/youtube.json @@ -0,0 +1,20 @@ +[ + { + "common_flags_0": 8200, + "common_flags_str_0": "[Client is Local]", + "common_flags_identify_info_0": "{\"Client is Local\":1,\"C2S\":1}", + "common_flags_1": 1991270408, + "common_flags_str_1": "[Client is Local]", + "common_flags_identify_info_1": "{\"Client is Local\":1,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_2": 1991271560, + "common_flags_str_2": "[Client is Local,Inbound,Streaming]", + "common_flags_identify_info_2": "{\"Client is Local\":1,\"Inbound\":633,\"Streaming\":633,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_3": 1991271562, + "common_flags_str_3": "[Bulky,Client is Local,Inbound,Streaming]", + "common_flags_identify_info_3": "{\"Bulky\":635,\"Client is Local\":1,\"Inbound\":633,\"Streaming\":633,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "common_flags_4": 1991271566, + "common_flags_str_4": "[Bulky,CBR Streaming,Client is Local,Inbound,Streaming]", + "common_flags_identify_info_4": "{\"Bulky\":635,\"CBR Streaming\":7070,\"Client is Local\":1,\"Inbound\":633,\"Streaming\":633,\"C2S\":1,\"S2C\":2,\"longest_run\":2,\"rank\":2,\"overlapping_template_matching\":2,\"random_excursions\":2,\"random_excursions_variant\":2,\"runs_distribution\":2,\"self_correlation\":2,\"binary_derivative\":2}", + "name": "base_0" + } +] \ No newline at end of file diff --git a/test/decoders/session_flags/plugin_test_main.cpp b/test/decoders/session_flags/plugin_test_main.cpp new file mode 100644 index 0000000..8f3d996 --- /dev/null +++ b/test/decoders/session_flags/plugin_test_main.cpp @@ -0,0 +1,135 @@ +#include "cJSON.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "stellar/stellar.h" +#ifdef __cplusplus +} +#endif + +// #define IGNORE_PRINTF +#ifdef IGNORE_PRINTF +#define printf(fmt, ...) (0) +#endif +static cJSON *g_test_result_root = NULL; +static cJSON *g_load_result_root = NULL; +static const char *result_json_path = NULL; + +extern "C" int commit_test_result_json(cJSON *node, const char *name) +{ + (void)name; + if (g_test_result_root) + { + // cJSON_AddItemToObject(g_test_result_root, name, node); + // cJSON_AddStringToObject(node, "name", name); + cJSON_AddItemToArray(g_test_result_root, node); + return 0; + } + return -1; +} + +static cJSON *load_result_from_jsonfile(const char *json_path) +{ + if (json_path == NULL) + return NULL; + + long file_len = 0; + char *file_content = NULL; + FILE *fp = NULL; + + fp = fopen(json_path, "r+"); + if (NULL == fp) + { + return NULL; + } + fseek(fp, 0, SEEK_END); + file_len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (file_len == 0) + { + fclose(fp); + return NULL; + } + file_content = (char *)malloc(file_len + 1); + fread(file_content, file_len, 1, fp); + file_content[file_len] = '\0'; + cJSON *load = cJSON_Parse(file_content); + free(file_content); + fclose(fp); + + return load; +} + +TEST(PROTOCOL, compare_result_json) +{ + EXPECT_EQ(cJSON_GetArraySize(g_test_result_root), cJSON_GetArraySize(g_load_result_root)); + int ret = cJSON_Compare(g_test_result_root, g_load_result_root, 0); + EXPECT_EQ(1, ret); + + if (ret != 1) + { + char *load_json_str = cJSON_Print(g_load_result_root); + printf("LOAD Raw:\n%s\n", load_json_str); + free(load_json_str); + char *result_json_str = cJSON_Print(g_test_result_root); + printf("TEST Raw:\n%s\n", result_json_str); + free(result_json_str); + + cJSON *t_load = g_load_result_root->child, *t_test = g_test_result_root->child; + while (t_load != NULL) + { + ret = cJSON_Compare(t_load, t_test, 0); + if (ret != 1) + { + load_json_str = cJSON_Print(t_load); + printf("LOAD Diff:\n%s\n", load_json_str); + free(load_json_str); + result_json_str = cJSON_Print(t_test); + printf("TEST Diff:\n%s\n", result_json_str); + free(result_json_str); + goto fail; + } + t_load = t_load->next; + t_test = t_test->next; + } + } + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +fail: + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + result_json_path = NULL; + } + else + { + result_json_path = argv[1]; + g_test_result_root = cJSON_CreateArray(); + g_load_result_root = load_result_from_jsonfile(result_json_path); + assert(g_load_result_root != NULL && g_test_result_root != NULL); + } + ::testing::InitGoogleTest(&argc, argv); + struct stellar *st = stellar_new("./conf/stellar.toml", "./plugin/spec.toml", "./conf/log.toml"); + stellar_run(st); + if (result_json_path != NULL) + { + ret = RUN_ALL_TESTS(); + } + stellar_free(st); + return ret; +} diff --git a/test/decoders/session_flags/session_flags_pcap_test.cpp b/test/decoders/session_flags/session_flags_pcap_test.cpp new file mode 100644 index 0000000..14af115 --- /dev/null +++ b/test/decoders/session_flags/session_flags_pcap_test.cpp @@ -0,0 +1,630 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "session_flags_internal.h" +#include "gtest/gtest.h" +extern "C" { +#include "dummy.h" +} + +#define MAC_FRAME_HEADER_LEN 14 +#define IP_HEADER_LEN 20 +#define TCP_HEADER_LEN 20 +#define UDP_HEADER_LEN 8 +#define LINUX_COOKED_CAPTURE 20 + +struct pcap_loop_arg +{ + pcap_t *pcap_handle; + struct session_flags_ctx *ctx; +}; + +struct session_flags_plugin_info *sf_plugin_info = NULL; + +extern int MESA_dir_link_to_human(int link_route_dir); +extern char *session_flags_generate_firewall_message(uint64_t flags, uint32_t identify[session_flags_all_mask]); + +static inline size_t ts2ms(const timeval *ts) +{ + return ts->tv_sec * 1000 + ts->tv_usec / 1000; +} + +static void pcap_handle_cb(pcap_loop_arg *userarg, const struct pcap_pkthdr *pkthdr, const u_char *packet) +{ + struct pcap_loop_arg *arg = (struct pcap_loop_arg *)userarg; + struct session sess; + int payload_len = 0; + char *payload = NULL; + unsigned short sport, dport; + unsigned short eth_proto_type; + unsigned char *ip_header; + int topic_id = 0; + + memset(&sess, 0, sizeof(sess)); + + int data_link_type = pcap_datalink(arg->pcap_handle); + switch (data_link_type) { + case DLT_EN10MB: + eth_proto_type = ntohs(*(unsigned short *)(packet + 12)); + ip_header = (unsigned char *)(packet + sizeof(struct ethhdr)); + break; + case 276://DLT_LINUX_SLL2 + eth_proto_type = ntohs(*(unsigned short *)packet); + ip_header = (unsigned char *)(packet + LINUX_COOKED_CAPTURE); + break; + default: + return; + } + + if (eth_proto_type == ETH_P_IP) { + int l4_proto = *(unsigned char *)(ip_header + 9); + if (l4_proto == IPPROTO_TCP) { + topic_id = DUMMY_TCP_TOPIC_ID; + int ip_total_len = ntohs(*(unsigned short *)(ip_header + 2)); + int ip_header_len = (*(unsigned char *)ip_header & 0x0f) * 4; + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(iphdr) + 12) & 0xf0) >> 4); + payload_len = ip_total_len - ip_header_len - tcp_header_len; + payload = (char *)ip_header + ip_header_len + tcp_header_len; + } else if (l4_proto == IPPROTO_UDP) { + topic_id = DUMMY_UDP_TOPIC_ID; + payload_len = pkthdr->caplen - (ip_header - packet) - sizeof(iphdr) - sizeof(struct udphdr); + payload = (char *)ip_header + sizeof(iphdr) + sizeof(struct udphdr); + } else { + return; + } + + sport = ntohs(*(unsigned short *)(ip_header + sizeof(iphdr) + 0)); + dport = ntohs(*(unsigned short *)(ip_header + sizeof(iphdr) + 2)); + + } else if (eth_proto_type == ETH_P_IPV6) { + int l4_proto = *(unsigned char *)(ip_header + 6); + if (l4_proto == IPPROTO_TCP) { + topic_id = DUMMY_TCP_TOPIC_ID; + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(struct ip6_hdr) + 12) & 0xf0) >> 4); + payload_len = pkthdr->caplen - (ip_header - packet) - sizeof(struct ip6_hdr) - tcp_header_len; + payload = (char *)ip_header + sizeof(struct ip6_hdr) + tcp_header_len; + } else if (l4_proto == IPPROTO_UDP) { + topic_id = DUMMY_UDP_TOPIC_ID; + payload_len = pkthdr->caplen - (ip_header - packet) - sizeof(struct ip6_hdr) - sizeof(struct udphdr); + payload = (char *)ip_header + sizeof(struct ip6_hdr) + sizeof(struct udphdr); + } else { + return; + } + + sport = ntohs(*(unsigned short *)(ip_header + sizeof(struct ip6_hdr) + 0)); + dport = ntohs(*(unsigned short *)(ip_header + sizeof(struct ip6_hdr) + 2)); + } else { + return; + } + + session_set_current_payload(&sess, payload, payload_len); + + if (sport > dport) + { + session_flags(sf_plugin_info, arg->ctx, &sess, topic_id, pkthdr->caplen, FLOW_TYPE_C2S, ts2ms(&pkthdr->ts)); + } + else + { + session_flags(sf_plugin_info, arg->ctx, &sess, topic_id, pkthdr->caplen, FLOW_TYPE_S2C, ts2ms(&pkthdr->ts)); + } + +} + +TEST(session_flags, bulky_and_download) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_BULKY, SESSION_FLAGS_BULKY); + EXPECT_EQ(flags_info->identify[session_flags_bulky_mask], 2333); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_DOWNLOAD, SESSION_FLAGS_DOWNLOAD); + EXPECT_EQ(flags_info->identify[session_flags_download_mask], 2333); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, CBR) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/youtube-quic.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + EXPECT_EQ(flags_info->identify[session_flags_cbr_mask], 3351); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, not_CBR_ftp) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, not_CBR_dtls) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/bilibili-dtls.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, server_is_local) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + // session_flags_ip(sf, inet_addr("192.168.1.1"), inet_addr("127.0.0.1"), inet_addr("192.168.1.1")); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_INBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_LOCAL_SERVER, SESSION_FLAGS_LOCAL_SERVER); + EXPECT_EQ(flags_info->identify[session_flags_local_server_mask], 1); + + EXPECT_NE(flags_info->flags & SESSION_FLAGS_LOCAL_CLIENT, SESSION_FLAGS_LOCAL_CLIENT); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, client_is_local) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_LOCAL_SERVER, SESSION_FLAGS_LOCAL_SERVER); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_LOCAL_CLIENT, SESSION_FLAGS_LOCAL_CLIENT); + EXPECT_EQ(flags_info->identify[session_flags_local_client_mask], 1); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, inbound) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_LOCAL_CLIENT, SESSION_FLAGS_LOCAL_CLIENT); + EXPECT_EQ(flags_info->identify[session_flags_local_client_mask], 1); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_INBOUND, SESSION_FLAGS_INBOUND); + EXPECT_EQ(flags_info->identify[session_flags_inbound_mask], 1834); + + EXPECT_NE(flags_info->flags & SESSION_FLAGS_OUTBOUND, SESSION_FLAGS_OUTBOUND); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_LOCAL_SERVER, SESSION_FLAGS_LOCAL_SERVER); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, outbound) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_INBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_LOCAL_SERVER, SESSION_FLAGS_LOCAL_SERVER); + EXPECT_EQ(flags_info->identify[session_flags_local_server_mask], 1); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_OUTBOUND, SESSION_FLAGS_OUTBOUND); + EXPECT_EQ(flags_info->identify[session_flags_outbound_mask], 1834); + + EXPECT_NE(flags_info->flags & SESSION_FLAGS_LOCAL_CLIENT, SESSION_FLAGS_LOCAL_CLIENT); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_INBOUND, SESSION_FLAGS_INBOUND); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, not_streaming) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/1-dtls.192.168.44.32.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_STREAMING, SESSION_FLAGS_STREAMING); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL, SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_UNIDIRECTIONAL, SESSION_FLAGS_UNIDIRECTIONAL); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, streaming_pseudo_unidirectional_unidirectional) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ftp-data.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_STREAMING, SESSION_FLAGS_STREAMING); + EXPECT_EQ(flags_info->identify[session_flags_streaming_mask], 2333); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL, SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_pseudo_unidirectional_mask], 2333); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_UNIDIRECTIONAL, SESSION_FLAGS_UNIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_unidirectional_mask], 1834); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, interactive) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/ssh-interactive.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_INTERACTIVE, SESSION_FLAGS_INTERACTIVE); + EXPECT_EQ(flags_info->identify[session_flags_interactive_mask], 52); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, not_interactive) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/youtube-quic.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_INTERACTIVE, SESSION_FLAGS_INTERACTIVE); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, random_looking_flags_telegram_mtproto_ipv4_key_1) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/telegram_mtproto_ipv4_key_1.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_RANDOM_LOOKING, SESSION_FLAGS_RANDOM_LOOKING); +#if 0 + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_FREQUENCY, SESSION_FLAGS_FREQUENCY); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_BLOCK_FREQUENCY, SESSION_FLAGS_BLOCK_FREQUENCY); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_CUMULATIVE_SUMS, SESSION_FLAGS_CUMULATIVE_SUMS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RUNS, SESSION_FLAGS_RUNS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_LONGEST_RUN, SESSION_FLAGS_LONGEST_RUN); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANK, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_NON_OVERLAPPING_TEMPLATE_MATCHING, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING, SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_UNIVERSAL, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANDOM_EXCURSIONS, SESSION_FLAGS_RANDOM_EXCURSIONS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT, SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_POKER_DETECT, SESSION_FLAGS_POKER_DETECT); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RUNS_DISTRIBUTION, SESSION_FLAGS_RUNS_DISTRIBUTION); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_SELF_CORRELATION, SESSION_FLAGS_SELF_CORRELATION); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_BINARY_DERIVATIVE, SESSION_FLAGS_BINARY_DERIVATIVE); +#endif + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, random_looking_flags_telegram_mtproto_ipv6_key_1) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t * handle = pcap_open_offline("pcap/telegram_mtproto_ipv6_key_1.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_RANDOM_LOOKING, SESSION_FLAGS_RANDOM_LOOKING); + +#if 0 + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_FREQUENCY, SESSION_FLAGS_FREQUENCY); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_BLOCK_FREQUENCY, SESSION_FLAGS_BLOCK_FREQUENCY); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_CUMULATIVE_SUMS, SESSION_FLAGS_CUMULATIVE_SUMS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RUNS, SESSION_FLAGS_RUNS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_LONGEST_RUN, SESSION_FLAGS_LONGEST_RUN); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANK, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_NON_OVERLAPPING_TEMPLATE_MATCHING, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING, SESSION_FLAGS_OVERLAPPING_TEMPLATE_MATCHING); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_UNIVERSAL, 0); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANDOM_EXCURSIONS, SESSION_FLAGS_RANDOM_EXCURSIONS); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT, SESSION_FLAGS_RANDOM_EXCURSIONS_VARIANT); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_POKER_DETECT, SESSION_FLAGS_POKER_DETECT); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_RUNS_DISTRIBUTION, SESSION_FLAGS_RUNS_DISTRIBUTION); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_SELF_CORRELATION, SESSION_FLAGS_SELF_CORRELATION); + EXPECT_EQ(flags_info->random_looking_flags & SESSION_FLAGS_BINARY_DERIVATIVE, SESSION_FLAGS_BINARY_DERIVATIVE); +#endif + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, bidirectional) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t *handle = pcap_open_offline("pcap/wechat_voice_call.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_INBOUND); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_BIDIRECTIONAL, SESSION_FLAGS_BIDIRECTIONAL); + + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, tunneling_tls_fet) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t *handle = pcap_open_offline("pcap/tls1.2_no_reuse.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + tunneling_hs_stream_init(sf_plugin_info, ctx); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_TUNNELING, SESSION_FLAGS_TUNNELING); + + tunneling_hs_stream_free(ctx); + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, tunneling_tls_over_tls) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t *handle = pcap_open_offline("pcap/tls_over_tls_1.2_no_reuse.pcap", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + tunneling_hs_stream_init(sf_plugin_info, ctx); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_TUNNELING, SESSION_FLAGS_TUNNELING); + + tunneling_hs_stream_free(ctx); + pcap_close(handle); + free(ctx); +} + +TEST(session_flags, tunneling_tls) +{ + char error[100]; + struct pcap_loop_arg arg; + struct session_flags_ctx *ctx = (struct session_flags_ctx *)calloc(1, sizeof(struct session_flags_ctx)); + pcap_t *handle = pcap_open_offline("pcap/tls1.2.pcapng", error); + ASSERT_NE(handle, nullptr); + + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + tunneling_hs_stream_init(sf_plugin_info, ctx); + + memset(&arg, 0, sizeof(arg)); + arg.ctx = ctx; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + + EXPECT_NE(flags_info->flags & SESSION_FLAGS_TUNNELING, SESSION_FLAGS_TUNNELING); + + tunneling_hs_stream_free(ctx); + pcap_close(handle); + free(ctx); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + sf_plugin_info = (struct session_flags_plugin_info *)session_flags_plugin_init(NULL); + sf_plugin_info->log_handle = NULL; + + int result = RUN_ALL_TESTS(); + + session_flags_plugin_exit(sf_plugin_info); + + return result; +} \ No newline at end of file diff --git a/test/decoders/session_flags/session_flags_static_test.cpp b/test/decoders/session_flags/session_flags_static_test.cpp new file mode 100644 index 0000000..d415807 --- /dev/null +++ b/test/decoders/session_flags/session_flags_static_test.cpp @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include +#include "session_flags_internal.h" +#include "gtest/gtest.h" + +extern "C" { +#include "dummy.h" +} + +struct session_flags_plugin_info *sf_plugin_info = NULL; + +TEST(session_flags_static, bulky) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + int cur_time_ms = 1; + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 96; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 1001, FLOW_TYPE_C2S, cur_time_ms); + cur_time_ms++; + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + for (int j = 0; j < 4; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 100, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_BULKY, SESSION_FLAGS_BULKY); + EXPECT_EQ(flags_info->identify[session_flags_bulky_mask], 6001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Bulky\":196,\"Client is Local\":1,\"Outbound\":196,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, download_gt_95) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + int cur_time_ms = 1; + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 96; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 1001, FLOW_TYPE_C2S, cur_time_ms); + cur_time_ms++; + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + for (int j = 0; j < 4; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 100, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + } + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_DOWNLOAD, SESSION_FLAGS_DOWNLOAD); + EXPECT_EQ(flags_info->identify[session_flags_download_mask], 6001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Bulky\":195,\"Client is Local\":1,\"Outbound\":195,\"Streaming\":195,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, download_lt_95) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + int cur_time_ms = 1; + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 94; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 1001, FLOW_TYPE_C2S, cur_time_ms); + cur_time_ms++; + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + for (int j = 0; j < 6; j++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 100, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + } + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_DOWNLOAD, SESSION_FLAGS_DOWNLOAD); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Bulky\":195,\"Client is Local\":1,\"Outbound\":195,\"Streaming\":195,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, CBR_lt_1s) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + int std_bytes = 1000; + int cur_time_ms = 1; + for (int i = 0; i < 100; i++) + { + long delta = random() % 200; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, std_bytes + delta, FLOW_TYPE_C2S, cur_time_ms++); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms++); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Bulky\":200,\"Client is Local\":1,\"Download\":200,\"Outbound\":200,\"Pseudo Unidirectional\":200,\"Streaming\":200,\"Unidirectional\":200,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, CBR) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + for (uint64_t cur_time_ms = 1; cur_time_ms < 11000; cur_time_ms += 10) + { + long delta = random() % 200; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 1000 + delta, FLOW_TYPE_C2S, cur_time_ms); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + EXPECT_EQ(flags_info->identify[session_flags_cbr_mask], 1001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Bulky\":201,\"CBR Streaming\":2021,\"Client is Local\":1,\"Download\":201,\"Outbound\":201,\"Pseudo Unidirectional\":201,\"Streaming\":201,\"Unidirectional\":201,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, not_CBR) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + for (uint64_t cur_time_ms = 1, i = 0; cur_time_ms < 10000; cur_time_ms += 500) + { + int delta = (i++ % 10) * 100; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100 + delta, FLOW_TYPE_C2S, cur_time_ms); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Client is Local\":1,\"Outbound\":21,\"Pseudo Unidirectional\":21,\"Unidirectional\":21,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, interactive) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + uint64_t cur_time_ms = 1; + while(cur_time_ms < 60000) + { + long delta = random() % 100; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 1000 + delta, FLOW_TYPE_C2S, cur_time_ms++); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms++); + } + while(cur_time_ms < 200000) + { + cur_time_ms += 10000; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 80, FLOW_TYPE_C2S, cur_time_ms); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 66, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_INTERACTIVE, SESSION_FLAGS_INTERACTIVE); + EXPECT_EQ(flags_info->identify[session_flags_interactive_mask], 60009); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Bulky\":1001,\"CBR Streaming\":10021,\"Client is Local\":1,\"Download\":1001,\"Interactive\":60009,\"Outbound\":1001,\"Pseudo Unidirectional\":1001,\"Streaming\":1001,\"Unidirectional\":1001,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, streaming_gt_90) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + session_set_current_payload(&sess, NULL, 100); + for (uint64_t cur_time_ms = 1; cur_time_ms < 10000; cur_time_ms++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 861, FLOW_TYPE_C2S, cur_time_ms); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 139, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_STREAMING, SESSION_FLAGS_STREAMING); + EXPECT_EQ(flags_info->identify[session_flags_streaming_mask], 12001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Client is Local\":1,\"Outbound\":668,\"Streaming\":669,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, streaming_lt_90) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + session_set_current_payload(&sess, NULL, 100); + for (uint64_t cur_time_ms = 1; cur_time_ms < 10000; cur_time_ms++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 859, FLOW_TYPE_C2S, cur_time_ms); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 141, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_STREAMING, 0); + EXPECT_EQ(flags_info->identify[session_flags_streaming_mask], 0); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Client is Local\":1,\"Outbound\":668,\"Streaming\":669,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, presu_unidirectional_gt_95) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + uint64_t cur_time_ms = 1; + session_set_current_payload(&sess, NULL, 100); + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 96; j++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_C2S, cur_time_ms); + cur_time_ms++; + } + for (int j = 0; j < 4; j++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL, SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_pseudo_unidirectional_mask], 6001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Client is Local\":1,\"Outbound\":1002,\"Pseudo Unidirectional\":1002,\"Streaming\":1002,\"C2S\":1,\"S2C\":99}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, presu_unidirectional_lt_95) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + uint64_t cur_time_ms = 1; + session_set_current_payload(&sess, NULL, 100); + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 94; j++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_C2S, cur_time_ms); + cur_time_ms++; + } + for (int j = 0; j < 6; j++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_S2C, cur_time_ms); + cur_time_ms++; + } + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL, 0); + EXPECT_EQ(flags_info->identify[session_flags_pseudo_unidirectional_mask], 0); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Client is Local\":1,\"Outbound\":1002,\"Pseudo Unidirectional\":1002,\"Streaming\":1002,\"C2S\":1,\"S2C\":99}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, Unidirectional) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + for (uint64_t cur_time_ms = 1; cur_time_ms < 10000; cur_time_ms++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_C2S, cur_time_ms); + + session_set_current_payload(&sess, NULL, 0); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 80, FLOW_TYPE_S2C, cur_time_ms); + } + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_UNIDIRECTIONAL, SESSION_FLAGS_UNIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_unidirectional_mask], 10001); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL, SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_pseudo_unidirectional_mask], 12001); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ("{\"Client is Local\":1,\"Outbound\":668,\"Pseudo Unidirectional\":669,\"Unidirectional\":669,\"C2S\":1,\"S2C\":2}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, not_unidirectional) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + srandom(time(NULL)); + uint64_t cur_time_ms = 1; + session_set_current_payload(&sess, NULL, 100); + for (int i = 1; i < 10000; i++) + { + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100 + random() % 1000, FLOW_TYPE_C2S, cur_time_ms++); + } + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 80, FLOW_TYPE_S2C, cur_time_ms++); + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_UNIDIRECTIONAL, SESSION_FLAGS_UNIDIRECTIONAL); + + struct session_flags_message *msg = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Client is Local\":1, \"Outbound\":10000, \"C2S\":1,\"S2C\":10000}", identify_str); + EXPECT_EQ(msg->packet_sequence_array[0], 1); + EXPECT_EQ(msg->packet_sequence_array[1], 10000); + EXPECT_EQ(msg->packet_sequence_array[2], 1); + EXPECT_EQ(msg->packet_sequence_array[3], 10000); + free(msg->packet_sequence_array); + free(msg); + free(ctx); +} + +TEST(session_flags_static, dns) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + uint64_t cur_time_ms = 1000; + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 72, FLOW_TYPE_C2S, cur_time_ms); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 72, FLOW_TYPE_C2S, cur_time_ms); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 72, FLOW_TYPE_C2S, cur_time_ms+10000); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 72, FLOW_TYPE_C2S, cur_time_ms+10000); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 146, FLOW_TYPE_S2C, cur_time_ms+15000); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_UDP_TOPIC_ID, 72, FLOW_TYPE_C2S, cur_time_ms+15000); + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_NE(flags_info->flags & SESSION_FLAGS_CBR, SESSION_FLAGS_CBR); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_LOCAL_CLIENT, SESSION_FLAGS_LOCAL_CLIENT); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_C2S, SESSION_FLAGS_C2S); + EXPECT_EQ(flags_info->identify[session_flags_c2s_mask], 1); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_S2C, SESSION_FLAGS_S2C); + EXPECT_EQ(flags_info->identify[session_flags_s2c_mask], 5); + + //char *identify_str = session_flags_generate_firewall_message(flags_info->flags, flags_info->identify); + //EXPECT_STREQ( "{\"Client is Local\":1,\"Outbound\":6,\"C2S\":1,\"S2C\":5}", identify_str); + //free(identify_str); + free(ctx); +} + +TEST(session_flags_static, bidirectional) +{ + struct session_flags_ctx *ctx = (struct session_flags_ctx*)calloc(1, sizeof(struct session_flags_ctx)); + struct session sess; + + memset(&sess, 0, sizeof(sess)); + session_flags_stat_init(&ctx->stat, SESSION_DIRECTION_OUTBOUND); + + int cur_time_ms = 1; + session_set_current_payload(&sess, NULL, 100); + for (int i = 0; i < 5000; i++) + { + session_set_current_payload(&sess, NULL, 100); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 100, FLOW_TYPE_C2S, cur_time_ms++); + + session_set_current_payload(&sess, NULL, 99); + session_flags(sf_plugin_info, ctx, &sess, DUMMY_TCP_TOPIC_ID, 99, FLOW_TYPE_S2C, cur_time_ms++); + } + + struct session_flags_result *flags_info = session_flags_get_flags(&ctx->stat); + EXPECT_EQ(flags_info->flags & SESSION_FLAGS_BIDIRECTIONAL, SESSION_FLAGS_BIDIRECTIONAL); + EXPECT_EQ(flags_info->identify[session_flags_bidirectional_mask], 6001); + free(ctx); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + //testing::GTEST_FLAG(filter) = ""; + sf_plugin_info = (struct session_flags_plugin_info *)session_flags_plugin_init(NULL); + sf_plugin_info->log_handle = NULL; + int result = RUN_ALL_TESTS(); + session_flags_plugin_exit(sf_plugin_info); + + return result; +} \ No newline at end of file diff --git a/test/decoders/session_flags/session_flags_test_plugin.cpp b/test/decoders/session_flags/session_flags_test_plugin.cpp new file mode 100644 index 0000000..27d2377 --- /dev/null +++ b/test/decoders/session_flags/session_flags_test_plugin.cpp @@ -0,0 +1,210 @@ +#include +#include +#include + +#include "cJSON.h" + +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" + +#include "stellar/session_flags.h" + +#ifdef __cplusplus +extern "C" +{ +int commit_test_result_json(cJSON *node, const char *name); +} +#endif + +#define unused(x) ((void)(x)) + +int g_test_session_flags_plugin_id; +int g_session_flags_topic_id; + +int g_receive_msg_count = 0; + +static void session_flags_2_str(uint64_t flags, char *str, int str_len) +{ + if (str == NULL || str_len == 0) + return; + + int offset = 0; + str[0] = '['; + offset += 1; + + if (flags & SESSION_FLAGS_BULKY && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Bulky,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_CBR && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "CBR Streaming,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_LOCAL_CLIENT && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Client is Local,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_LOCAL_SERVER && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Server is Local,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_DOWNLOAD && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Download,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_INTERACTIVE && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Interactive,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_INBOUND && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Inbound,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_OUTBOUND && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Outbound,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_PSEUDO_UNIDIRECTIONAL && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Pseudo Unidirectional,"); + offset = strlen(str); + } + + + if (flags & SESSION_FLAGS_STREAMING && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Streaming,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_UNIDIRECTIONAL && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Unidirectional,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_RANDOM_LOOKING && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Random Looking,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_C2S && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "C2S,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_S2C && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "S2C,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_BIDIRECTIONAL && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Bidirectional,"); + offset = strlen(str); + } + + if (flags & SESSION_FLAGS_TUNNELING && str_len > offset) + { + snprintf(&str[offset], str_len-offset, "Tunneling,"); + offset = strlen(str); + } + + + str[offset-1] = ']'; +} + +static void append_json(cJSON *root, struct session_flags_message *sf_message) +{ + char key[128] = {0}; + snprintf(key, 128, "common_flags_%d", g_receive_msg_count); + cJSON_AddNumberToObject(root, (const char *)key, sf_message->flags); + + char str[1024] = {0}; + session_flags_2_str(sf_message->flags, str, 1024); + snprintf(key, 128, "common_flags_str_%d", g_receive_msg_count); + cJSON_AddStringToObject(root, (const char *)key, str); + + char identify_str[1024] = {0}; + int offset = 0; + for (unsigned int i = 0; i < sf_message->array_num; i++) + { + offset += snprintf(identify_str + offset, 1024-offset, "%u,", sf_message->packet_sequence_array[i]); + } + snprintf(key, 128, "common_flags_identify_info_%d", g_receive_msg_count); + cJSON_AddStringToObject(root, (const char *)key, identify_str); + + g_receive_msg_count++; +} + +void test_session_flags_entry(struct session *session, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + unused(plugin_env); + unused(session); + unused(topic_id); + + if (msg == NULL) + { + return; + } + + struct session_flags_message *sf_message = (struct session_flags_message *)msg; + cJSON *json_root = (cJSON *)per_session_ctx; + + append_json(json_root, sf_message); + +} + +void *ctx_new(struct session *session, void *plugin_env) +{ + unused(plugin_env); + unused(session); + + cJSON *root = cJSON_CreateObject(); + return (void *)root; +} + +void ctx_free(struct session *sess, void *session_ctx, void *plugin_env) +{ + unused(sess); + unused(plugin_env); + + commit_test_result_json((cJSON *)session_ctx, "session_flags_test"); +} + +extern "C" void *SESSION_FLAGS_TEST_PLUG_INIT(struct stellar *st) +{ + g_test_session_flags_plugin_id = stellar_session_plugin_register(st, ctx_new, ctx_free, NULL); + g_session_flags_topic_id = stellar_mq_get_topic_id(st, SESSION_FLAGS_MESSAGE_TOPIC); + + stellar_session_mq_subscribe(st, g_session_flags_topic_id, test_session_flags_entry, g_test_session_flags_plugin_id); + + return NULL; +} + +extern "C" void SESSION_FLAGS_TEST_PLUG_DESTROY(void *ctx) +{ + unused(ctx); + return; +} \ No newline at end of file diff --git a/test/decoders/session_flags/test_based_on_stellar/CMakeLists.txt b/test/decoders/session_flags/test_based_on_stellar/CMakeLists.txt new file mode 100644 index 0000000..9f4f5ba --- /dev/null +++ b/test/decoders/session_flags/test_based_on_stellar/CMakeLists.txt @@ -0,0 +1,37 @@ +set(DECODER_NAME session_flags) + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/test/decoders/session_flags) +set(SAPP_DEVEL_DIR ${TEST_RUN_DIR}/lib) +set(TEST_MAIN session_flags_test_main) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/test) +include_directories(/usr/local/include/cjson) +include_directories(/opt/tsg/framework/include/stellar) +include_directories(/opt/MESA/include/MESA) +include_directories(/opt/tsg/stellar/include/) + +#various ways to add -rdynamic for centos7, centos8, and different cmake version +add_definitions(-rdynamic) +link_directories(${SAPP_DEVEL_DIR}) + +# assemble test env +add_test(NAME SESSION_FLAGS_MKDIR_METRIC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/metrics; mkdir -p ${TEST_RUN_DIR}/plugin; mkdir -p ${TEST_RUN_DIR}/log; mkdir -p ${TEST_RUN_DIR}/pcap") +add_test(NAME SESSION_FLAGS_COPY_SPEC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/plugin/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/spec.toml ${TEST_RUN_DIR}/plugin/spec.toml") +add_test(NAME SESSION_FLAGS_COPY_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/stellar.toml ${TEST_RUN_DIR}/conf/stellar.toml") +add_test(NAME SESSION_FLAGS_COPY_LOG_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/log.toml ${TEST_RUN_DIR}/conf/log.toml") + +# update plugin to be tested +add_test(NAME SESSION_FLAGS_CP_DECODER_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/decoders/session_flags/session_flags_dyn.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}.so") +add_test(NAME SESSION_FLAGS_CP_DECODER_GTEST_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/decoders/session_flags/${DECODER_NAME}_test.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}_test.so") + +set_tests_properties(SESSION_FLAGS_MKDIR_METRIC SESSION_FLAGS_COPY_SPEC + SESSION_FLAGS_COPY_CONF SESSION_FLAGS_COPY_LOG_CONF + SESSION_FLAGS_CP_DECODER_SO SESSION_FLAGS_CP_DECODER_GTEST_SO + PROPERTIES FIXTURES_SETUP TestFixture) + +set(TEST_PCAP_DIR ${PROJECT_SOURCE_DIR}/test/decoders/session_flags/pcap) + +# run tests +add_test(NAME SESSION_FLAGS_PLUGIN_TEST COMMAND sh -c "ln -sf ${TEST_PCAP_DIR}/https_download.pcap ${TEST_RUN_DIR}/pcap/test.pcap; ./${TEST_MAIN} ${TEST_PCAP_DIR}/https_download.json" WORKING_DIRECTORY ${TEST_RUN_DIR}) + diff --git a/test/decoders/session_flags/test_based_on_stellar/env/log.toml b/test/decoders/session_flags/test_based_on_stellar/env/log.toml new file mode 100644 index 0000000..a51abd8 --- /dev/null +++ b/test/decoders/session_flags/test_based_on_stellar/env/log.toml @@ -0,0 +1,4 @@ +[log] +output = "stderr" # stderr, file +file = "log/stellar.log" +level = "ERROR" # TRACE, DEBUG, INFO, WARN, ERROR, FATAL diff --git a/test/decoders/session_flags/test_based_on_stellar/env/session_flags.toml b/test/decoders/session_flags/test_based_on_stellar/env/session_flags.toml new file mode 100644 index 0000000..af62a2b --- /dev/null +++ b/test/decoders/session_flags/test_based_on_stellar/env/session_flags.toml @@ -0,0 +1,9 @@ +[SESSION_FLAGS] +FET_ENABLED=1 +INTERACTIVE_STARTTIME_MS = 10000 +INTERACTIVE_PULSE_NUM = 4 +INTERACTIVE_LATENCY_MS = 5000 +MAIN_DIR_FRONT_N_PKTS = 100 +LARGE_PKTS_INIT_SIZE = 1000 +RANDOM_LOOKING_JUDGE_LIST="{\"random_looking_judge_list\":[ \"frequency\", \"block_frequency\", \"cumulative_sums\", \"runs\", \"longest_run\", \"rank\", \"non_overlapping_template_matching\", \"overlapping_template_matching\", \"universal\", \"random_excursions\", \"random_excursions_variant\", \"poker_detect\", \"runs_distribution\", \"self_correlation\", \"binary_derivative\" ]}" +TUNNELING_PCRE_LIST="{\"tunneling_pcre_list\":[\"(B|C)(d){3,5}(a|b|c|d)(A|B)b(A|B|C|D)\", \"(B|C)(d){3,5}(a|b|c|d)Aa(A|B|C|D)\", \"(B|C)(d){2}(b|c)(A|B)b(A|B|C|D)\", \"(B|C)(d){2}(b|c)Aa(A|B|C|D)\"]}" diff --git a/test/decoders/session_flags/test_based_on_stellar/env/spec.toml b/test/decoders/session_flags/test_based_on_stellar/env/spec.toml new file mode 100644 index 0000000..ead4371 --- /dev/null +++ b/test/decoders/session_flags/test_based_on_stellar/env/spec.toml @@ -0,0 +1,9 @@ +[[plugin]] +path = "./plugin/session_flags.so" +init = "session_flags_plugin_init" +exit = "session_flags_plugin_exit" + +[[plugin]] +path = "./plugin/session_flags_test.so" +init = "SESSION_FLAGS_TEST_PLUG_INIT" +exit = "SESSION_FLAGS_TEST_PLUG_DESTROY" diff --git a/test/decoders/session_flags/test_based_on_stellar/env/stellar.toml b/test/decoders/session_flags/test_based_on_stellar/env/stellar.toml new file mode 100644 index 0000000..308c884 --- /dev/null +++ b/test/decoders/session_flags/test_based_on_stellar/env/stellar.toml @@ -0,0 +1,64 @@ +[instance] + id = 1 # range: [0, 4095] (20 bit) + +[packet_io] + mode = "pcapfile" # pcapfile, pcaplist, marsio + app_symbol = "stellar" + dev_symbol = "nf_0_fw" + pcap_path = "./pcap/test.pcap" + nr_worker_thread = 1 # range: [1, 256] + cpu_mask = [5, 6, 7, 8, 9, 10, 11, 12] + idle_yield_interval_ms = 90 # range: [0, 60000] (ms) + +[ip_reassembly] + enable = 1 + bucket_entries = 32 # range: [1, 4294967295] (must be power of 2) + bucket_num = 1024 # range: [1, 4294967295] + + ip_frag_timeout_ms = 1000 # range: [1, 60000] (ms) + ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms) + ip_frag_expire_polling_limit = 1024 # range: [1, 1024] + +[session_manager] + tcp_session_max = 500 + udp_session_max = 500 + + evict_old_on_tcp_table_limit = 1 # range: [0, 1] + evict_old_on_udp_table_limit = 1 # range: [0, 1] + + expire_period_ms = 0 # range: [0, 60000] (ms) + expire_batch_max = 1024 # range: [1, 1024] + + [session_manager.tcp_timeout_ms] + init = 500 # range: [1, 60000] (ms) + handshake = 500 # range: [1, 60000] (ms) + data = 500 # range: [1, 15999999000] (ms) + half_closed = 500 # range: [1, 604800000] (ms) + time_wait = 500 # range: [1, 600000] (ms) + discard_default = 1000 # range: [1, 15999999000] (ms) + unverified_rst = 500 # range: [1, 600000] (ms) + + [session_manager.udp_timeout_ms] + data = 500 # range: [1, 15999999000] (ms) + discard_default = 500 # range: [1, 15999999000] (ms) + + [session_manager.duplicated_packet_bloom_filter] + enable = 0 + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.evicted_session_bloom_filter] + enable = 0 # range: [0, 1] + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.tcp_reassembly] + enable = 1 # range: [0, 1] + timeout_ms = 100 # range: [1, 60000] (ms) + buffered_segments_max = 256 # range: [2, 4096] per flow + +[stat] + merge_interval_ms = 500 # range: [0, 60000] (ms) + output_interval_ms = 1000 # range: [0, 60000] (ms) diff --git a/test/decoders/socks/CMakeLists.txt b/test/decoders/socks/CMakeLists.txt new file mode 100644 index 0000000..f40930a --- /dev/null +++ b/test/decoders/socks/CMakeLists.txt @@ -0,0 +1,38 @@ +set(DECODER_NAME socks) + +add_library(${DECODER_NAME}_test SHARED socks_decoder_test_plugin.cpp) +add_dependencies(${DECODER_NAME}_test ${DECODER_NAME}) +set_target_properties(${DECODER_NAME}_test PROPERTIES PREFIX "") + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/testing) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(${CMAKE_BINARY_DIR}/vendors/cjson/src/cjson/include) +include_directories(${PROJECT_SOURCE_DIR}/decoders/socks) +include_directories(${PROJECT_SOURCE_DIR}/include/stellar) + +add_executable(gtest_pcap_socks socks_decoder_pcap_gtest.cpp dummy.c ${PROJECT_SOURCE_DIR}/decoders/socks/socks_decoder.cpp) +target_link_libraries(gtest_pcap_socks gtest logger pcap) + +add_executable(socks_test_main plugin_test_main.cpp) +set_target_properties(socks_test_main + PROPERTIES + LINK_OPTIONS + "-rdynamic" + ) +set_target_properties(socks_test_main + PROPERTIES + LINK_FLAGS + "-rdynamic" + ) +set(LINK_FLAGS "-rdynamic") +target_link_libraries(socks_test_main gtest cjson-static stellar_lib) + +add_subdirectory(test_based_on_stellar) + +#copy pcap file folder to build directory +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/pcap DESTINATION ${CMAKE_BINARY_DIR}/test/decoders/socks) + +include(GoogleTest) +gtest_discover_tests(gtest_pcap_socks) diff --git a/test/decoders/socks/dummy.c b/test/decoders/socks/dummy.c new file mode 100644 index 0000000..bd15d44 --- /dev/null +++ b/test/decoders/socks/dummy.c @@ -0,0 +1,151 @@ +#include "dummy.h" + +#define UNUSED(x) (void)(x) + +int direction; + +void session_set_current_state(struct session *sess, enum session_state sess_state) +{ + sess->sess_state = sess_state; + + return; +} +enum session_state session_get_current_state(const struct session *sess) +{ + return sess->sess_state; +} + +void dummy_set_direction(int dir) +{ + direction = dir; +} + +struct logger *stellar_get_logger(struct stellar *st) +{ + UNUSED(st); + + return NULL; +} + +enum flow_type session_get_flow_type(const struct session *sess) +{ + UNUSED(sess); + + return direction; +} + +const struct packet *session_get0_current_packet(const struct session *sess) +{ + UNUSED(sess); + + return NULL; +} + +const char *packet_get_payload(const struct packet *pkt) +{ + UNUSED(pkt); + + return NULL; +} + +uint16_t packet_get_payload_len(const struct packet *pkt) +{ + UNUSED(pkt); + + return 0; +} + +int session_mq_ignore_message(struct session *sess, int topic_id, int plugin_id) +{ + UNUSED(sess); + UNUSED(topic_id); + UNUSED(plugin_id); + + return 0; +} + +int session_exdata_set(struct session *sess, int idx, void *ex_ptr) +{ + UNUSED(sess); + UNUSED(idx); + UNUSED(ex_ptr); + + return 0; +} + +void *session_exdata_get(struct session *sess, int idx) +{ + UNUSED(sess); + UNUSED(idx); + + return NULL; +} + +void stellar_session_plugin_dettach_current_session(struct session *sess) +{ + UNUSED(sess); +} + +int session_mq_publish_message(struct session *sess, int topic_id, void *msg) +{ + UNUSED(sess); + UNUSED(topic_id); + UNUSED(msg); + + return 0; +} + +const char *session_get0_readable_addr(const struct session *sess) +{ + UNUSED(sess); + + return NULL; +} + +int stellar_exdata_new_index(struct stellar *st, const char *name, stellar_exdata_free *free_func,void *arg) +{ + UNUSED(st); + UNUSED(name); + UNUSED(free_func); + UNUSED(arg); + + return 0; +} + +int stellar_mq_create_topic(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg) +{ + UNUSED(st); + UNUSED(topic_name); + UNUSED(msg_free_cb); + UNUSED(msg_free_arg); + + return 0; +} + +int stellar_mq_get_topic_id(struct stellar *st, const char *topic_name) +{ + UNUSED(st); + UNUSED(topic_name); + + return 0; +} + +int stellar_session_mq_subscribe(struct stellar *st, int topic_id, on_session_msg_cb_func *plugin_on_msg_cb, int plugin_id) +{ + UNUSED(st); + UNUSED(topic_id); + UNUSED(plugin_on_msg_cb); + UNUSED(plugin_id); + + return 0; +} + +int stellar_session_plugin_register(struct stellar *st, session_ctx_new_func session_ctx_new, session_ctx_free_func session_ctx_free, void *plugin_env) +{ + UNUSED(st); + UNUSED(session_ctx_new); + UNUSED(session_ctx_free); + UNUSED(plugin_env); + + return 0; +} \ No newline at end of file diff --git a/test/decoders/socks/dummy.h b/test/decoders/socks/dummy.h new file mode 100644 index 0000000..48f801e --- /dev/null +++ b/test/decoders/socks/dummy.h @@ -0,0 +1,14 @@ +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" + +struct session //stub just for test +{ + enum session_state sess_state; + int payload_len; + char *payload; +}; + +void session_set_current_state(struct session *sess, enum session_state sess_state); +void dummy_set_direction(int dir); \ No newline at end of file diff --git a/test/decoders/socks/pcap/result.json b/test/decoders/socks/pcap/result.json new file mode 100644 index 0000000..084d449 --- /dev/null +++ b/test/decoders/socks/pcap/result.json @@ -0,0 +1,7 @@ +[{ + "socks_info": { + "version": "SOCKS4", + "dst_addr": "127.0.0.1", + "dst_port": 8888 + } +}] \ No newline at end of file diff --git a/test/decoders/socks/pcap/socks4.pcap b/test/decoders/socks/pcap/socks4.pcap new file mode 100644 index 0000000..9091236 Binary files /dev/null and b/test/decoders/socks/pcap/socks4.pcap differ diff --git a/test/decoders/socks/pcap/socks4_nest_socks4a.pcap b/test/decoders/socks/pcap/socks4_nest_socks4a.pcap new file mode 100644 index 0000000..b5bcc9f Binary files /dev/null and b/test/decoders/socks/pcap/socks4_nest_socks4a.pcap differ diff --git a/test/decoders/socks/pcap/socks4a_domain.pcap b/test/decoders/socks/pcap/socks4a_domain.pcap new file mode 100644 index 0000000..14fbf10 Binary files /dev/null and b/test/decoders/socks/pcap/socks4a_domain.pcap differ diff --git a/test/decoders/socks/pcap/socks5_auth_failed.pcap b/test/decoders/socks/pcap/socks5_auth_failed.pcap new file mode 100644 index 0000000..1c75c66 Binary files /dev/null and b/test/decoders/socks/pcap/socks5_auth_failed.pcap differ diff --git a/test/decoders/socks/pcap/socks5_auth_success.pcap b/test/decoders/socks/pcap/socks5_auth_success.pcap new file mode 100644 index 0000000..4c4b9fd Binary files /dev/null and b/test/decoders/socks/pcap/socks5_auth_success.pcap differ diff --git a/test/decoders/socks/pcap/socks5_no_auth.pcap b/test/decoders/socks/pcap/socks5_no_auth.pcap new file mode 100644 index 0000000..a00100f Binary files /dev/null and b/test/decoders/socks/pcap/socks5_no_auth.pcap differ diff --git a/test/decoders/socks/plugin_test_main.cpp b/test/decoders/socks/plugin_test_main.cpp new file mode 100644 index 0000000..8f3d996 --- /dev/null +++ b/test/decoders/socks/plugin_test_main.cpp @@ -0,0 +1,135 @@ +#include "cJSON.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "stellar/stellar.h" +#ifdef __cplusplus +} +#endif + +// #define IGNORE_PRINTF +#ifdef IGNORE_PRINTF +#define printf(fmt, ...) (0) +#endif +static cJSON *g_test_result_root = NULL; +static cJSON *g_load_result_root = NULL; +static const char *result_json_path = NULL; + +extern "C" int commit_test_result_json(cJSON *node, const char *name) +{ + (void)name; + if (g_test_result_root) + { + // cJSON_AddItemToObject(g_test_result_root, name, node); + // cJSON_AddStringToObject(node, "name", name); + cJSON_AddItemToArray(g_test_result_root, node); + return 0; + } + return -1; +} + +static cJSON *load_result_from_jsonfile(const char *json_path) +{ + if (json_path == NULL) + return NULL; + + long file_len = 0; + char *file_content = NULL; + FILE *fp = NULL; + + fp = fopen(json_path, "r+"); + if (NULL == fp) + { + return NULL; + } + fseek(fp, 0, SEEK_END); + file_len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (file_len == 0) + { + fclose(fp); + return NULL; + } + file_content = (char *)malloc(file_len + 1); + fread(file_content, file_len, 1, fp); + file_content[file_len] = '\0'; + cJSON *load = cJSON_Parse(file_content); + free(file_content); + fclose(fp); + + return load; +} + +TEST(PROTOCOL, compare_result_json) +{ + EXPECT_EQ(cJSON_GetArraySize(g_test_result_root), cJSON_GetArraySize(g_load_result_root)); + int ret = cJSON_Compare(g_test_result_root, g_load_result_root, 0); + EXPECT_EQ(1, ret); + + if (ret != 1) + { + char *load_json_str = cJSON_Print(g_load_result_root); + printf("LOAD Raw:\n%s\n", load_json_str); + free(load_json_str); + char *result_json_str = cJSON_Print(g_test_result_root); + printf("TEST Raw:\n%s\n", result_json_str); + free(result_json_str); + + cJSON *t_load = g_load_result_root->child, *t_test = g_test_result_root->child; + while (t_load != NULL) + { + ret = cJSON_Compare(t_load, t_test, 0); + if (ret != 1) + { + load_json_str = cJSON_Print(t_load); + printf("LOAD Diff:\n%s\n", load_json_str); + free(load_json_str); + result_json_str = cJSON_Print(t_test); + printf("TEST Diff:\n%s\n", result_json_str); + free(result_json_str); + goto fail; + } + t_load = t_load->next; + t_test = t_test->next; + } + } + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +fail: + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + result_json_path = NULL; + } + else + { + result_json_path = argv[1]; + g_test_result_root = cJSON_CreateArray(); + g_load_result_root = load_result_from_jsonfile(result_json_path); + assert(g_load_result_root != NULL && g_test_result_root != NULL); + } + ::testing::InitGoogleTest(&argc, argv); + struct stellar *st = stellar_new("./conf/stellar.toml", "./plugin/spec.toml", "./conf/log.toml"); + stellar_run(st); + if (result_json_path != NULL) + { + ret = RUN_ALL_TESTS(); + } + stellar_free(st); + return ret; +} diff --git a/test/decoders/socks/socks_decoder_pcap_gtest.cpp b/test/decoders/socks/socks_decoder_pcap_gtest.cpp new file mode 100644 index 0000000..b1cde22 --- /dev/null +++ b/test/decoders/socks/socks_decoder_pcap_gtest.cpp @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" + +#include "socks_decoder_internal.h" +extern "C" { +#include "stellar/session.h" +#include "dummy.h" +} + +#define LINUX_COOKED_CAPTURE 20 + +extern int socks_process(struct socks_decoder_info *socks_decoder_info, struct session *sess, struct socks_tunnel_stream *stream, const char *payload, size_t payload_len); +struct pcap_loop_arg +{ + pcap_t *pcap_handle; + struct socks_tunnel_stream *stream; +}; + +struct socks_decoder_info *socks_decoder_info = NULL; + +static void pcap_handle_cb(pcap_loop_arg *userarg, const struct pcap_pkthdr *pkthdr, const u_char *packet) +{ + struct pcap_loop_arg *arg = (struct pcap_loop_arg *)userarg; + struct session sess; + int payload_len = 0; + char *payload = NULL; + unsigned short sport, dport; + unsigned short eth_proto_type; + unsigned char *ip_header; + + memset(&sess, 0, sizeof(sess)); + + int data_link_type = pcap_datalink(arg->pcap_handle); + switch (data_link_type) { + case DLT_EN10MB: + eth_proto_type = ntohs(*(unsigned short *)(packet + 12)); + ip_header = (unsigned char *)(packet + sizeof(struct ethhdr)); + break; + case 276://DLT_LINUX_SLL2 + eth_proto_type = ntohs(*(unsigned short *)packet); + ip_header = (unsigned char *)(packet + LINUX_COOKED_CAPTURE); + break; + default: + return; + } + + if (eth_proto_type == ETH_P_IP) { + int l4_proto = *(unsigned char *)(ip_header + 9); + if (l4_proto == IPPROTO_TCP) { + int ip_total_len = ntohs(*(unsigned short *)(ip_header + 2)); + int ip_header_len = (*(unsigned char *)ip_header & 0x0f) * 4; + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(iphdr) + 12) & 0xf0) >> 4); + payload_len = ip_total_len - ip_header_len - tcp_header_len; + payload = (char *)ip_header + ip_header_len + tcp_header_len; + } else { + return; + } + + sport = ntohs(*(unsigned short *)(ip_header + sizeof(iphdr) + 0)); + dport = ntohs(*(unsigned short *)(ip_header + sizeof(iphdr) + 2)); + + } else if (eth_proto_type == ETH_P_IPV6) { + int l4_proto = *(unsigned char *)(ip_header + 6); + if (l4_proto == IPPROTO_TCP) { + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(struct ip6_hdr) + 12) & 0xf0) >> 4); + payload_len = pkthdr->caplen - (ip_header - packet) - sizeof(struct ip6_hdr) - tcp_header_len; + payload = (char *)ip_header + sizeof(struct ip6_hdr) + tcp_header_len; + } else { + return; + } + + sport = ntohs(*(unsigned short *)(ip_header + sizeof(struct ip6_hdr) + 0)); + dport = ntohs(*(unsigned short *)(ip_header + sizeof(struct ip6_hdr) + 2)); + } else { + return; + } + + session_set_current_state(&sess, SESSION_STATE_ACTIVE); + + if (sport > dport) + { + dummy_set_direction(FLOW_TYPE_C2S); + } else { + dummy_set_direction(FLOW_TYPE_S2C); + } + socks_process(socks_decoder_info, &sess, arg->stream, payload, payload_len); + +} + +TEST(socks_decoder, socks4) +{ + char error[100]; + struct pcap_loop_arg arg; + struct socks_tunnel_stream *stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + pcap_t * handle = pcap_open_offline("pcap/socks4.pcap", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.stream = stream; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + EXPECT_EQ(stream->info.version, SOCKS_VERSION_4); + EXPECT_EQ(stream->info.dst_addr.type, SOCKS_ADDR_IPV4); + EXPECT_EQ(stream->info.dst_addr.ipv4, inet_addr("93.184.216.119")); + EXPECT_EQ(stream->info.dst_addr.port, htons(80)); + EXPECT_EQ(stream->info.user_name.iov_len, 0); + EXPECT_EQ(stream->info.password.iov_len, 0); + EXPECT_EQ(stream->client_state, SS_END); + EXPECT_EQ(stream->server_state, SS_END); + + pcap_close(handle); + free(stream); +} + +TEST(socks_decoder, socks4a_domain) +{ + char error[100]; + struct pcap_loop_arg arg; + struct socks_tunnel_stream *stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + pcap_t * handle = pcap_open_offline("pcap/socks4a_domain.pcap", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.stream = stream; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + EXPECT_EQ(stream->info.version, SOCKS_VERSION_4); + EXPECT_EQ(stream->info.dst_addr.type, SOCKS_ADDR_FQDN); + EXPECT_EQ(stream->info.dst_addr.fqdn.iov_len, strlen("www.example.com")); + EXPECT_STREQ("www.example.com", (char *)stream->info.dst_addr.fqdn.iov_base); + EXPECT_EQ(stream->info.dst_addr.port, htons(80)); + EXPECT_EQ(stream->info.user_name.iov_len, 0); + EXPECT_EQ(stream->info.password.iov_len, 0); + EXPECT_EQ(stream->client_state, SS_END); + EXPECT_EQ(stream->server_state, SS_END); + + pcap_close(handle); + free(stream->info.dst_addr.fqdn.iov_base); + free(stream); +} + +TEST(socks_decoder, socks5_no_auth) +{ + char error[100]; + struct pcap_loop_arg arg; + struct socks_tunnel_stream *stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + pcap_t * handle = pcap_open_offline("pcap/socks5_no_auth.pcap", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.stream = stream; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + EXPECT_EQ(stream->info.version, SOCKS_VERSION_5); + EXPECT_EQ(stream->info.dst_addr.type, SOCKS_ADDR_IPV4); + EXPECT_EQ(stream->info.dst_addr.ipv4, inet_addr("93.184.216.119")); + EXPECT_EQ(stream->info.dst_addr.port, htons(80)); + EXPECT_EQ(stream->info.user_name.iov_len, 0); + EXPECT_EQ(stream->info.password.iov_len, 0); + EXPECT_EQ(stream->client_state, SS_END); + EXPECT_EQ(stream->server_state, SS_END); + + pcap_close(handle); + free(stream); +} + +TEST(socks_decoder, socks5_auth_success) +{ + char error[100]; + struct pcap_loop_arg arg; + struct socks_tunnel_stream *stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + pcap_t * handle = pcap_open_offline("pcap/socks5_auth_success.pcap", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.stream = stream; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + EXPECT_EQ(stream->info.version, SOCKS_VERSION_5); + EXPECT_EQ(stream->info.dst_addr.type, SOCKS_ADDR_IPV4); + EXPECT_EQ(stream->info.dst_addr.ipv4, inet_addr("93.184.216.119")); + EXPECT_EQ(stream->info.dst_addr.port, htons(80)); + EXPECT_EQ(stream->info.user_name.iov_len, strlen("testuser")); + EXPECT_STREQ("testuser", (char *)stream->info.user_name.iov_base); + EXPECT_EQ(stream->info.password.iov_len, strlen("testuser")); + EXPECT_STREQ("testuser", (char *)stream->info.password.iov_base); + EXPECT_EQ(stream->client_state, SS_END); + EXPECT_EQ(stream->server_state, SS_END); + + pcap_close(handle); + free(stream->info.user_name.iov_base); + free(stream->info.password.iov_base); + free(stream); +} + +TEST(socks_decoder, socks5_auth_fail) +{ + char error[100]; + struct pcap_loop_arg arg; + struct socks_tunnel_stream *stream = (struct socks_tunnel_stream *)calloc(1, sizeof(struct socks_tunnel_stream)); + pcap_t * handle = pcap_open_offline("pcap/socks5_auth_failed.pcap", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.stream = stream; + arg.pcap_handle = handle; + + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + EXPECT_EQ(stream->client_state, SS_SUB); + EXPECT_EQ(stream->server_state, SS_FAILED); + + pcap_close(handle); + free(stream->info.user_name.iov_base); + free(stream->info.password.iov_base); + free(stream); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + socks_decoder_info = (struct socks_decoder_info *)calloc(1, sizeof(struct socks_decoder_info)); + + int result = RUN_ALL_TESTS(); + + free(socks_decoder_info); + + return result; +} \ No newline at end of file diff --git a/test/decoders/socks/socks_decoder_test_plugin.cpp b/test/decoders/socks/socks_decoder_test_plugin.cpp new file mode 100644 index 0000000..7edcf8d --- /dev/null +++ b/test/decoders/socks/socks_decoder_test_plugin.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +extern "C" { +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" +} + +#include "cJSON.h" +#include "socks_decoder.h" + +extern "C" int commit_test_result_json(cJSON *node, const char *name); +#define unused(x) ((void)(x)) + + +int g_test_socks_decoder_plugin_id = 0; +int g_socks_message_topic_id = 0; + +void *ctx_new(struct session *session, void *plugin_env) +{ + unused(plugin_env); + unused(session); + + cJSON *root = cJSON_CreateObject(); + return (void *)root; +} + +void ctx_free(struct session *sess, void *session_ctx, void *plugin_env) +{ + unused(sess); + unused(plugin_env); + + commit_test_result_json((cJSON *)session_ctx, "socks_decoder_test"); +} + +static void append_json(cJSON *root, struct socks_info *info) +{ + cJSON *json_stream = cJSON_CreateObject(); + + cJSON_AddStringToObject(json_stream, "version", info->version == SOCKS_VERSION_4 ? "SOCKS4" : "SOCKS5"); + + char ip_str[INET6_ADDRSTRLEN] = {0}; + if (info->dst_addr.type == SOCKS_ADDR_IPV4) { + inet_ntop(AF_INET, &info->dst_addr.ipv4, ip_str, INET_ADDRSTRLEN); + } else if (info->dst_addr.type == SOCKS_ADDR_IPV6) { + inet_ntop(AF_INET6, info->dst_addr.ipv6, ip_str, INET6_ADDRSTRLEN); + } else { + memcpy(ip_str, info->dst_addr.fqdn.iov_base, info->dst_addr.fqdn.iov_len); + } + cJSON_AddStringToObject(json_stream, "dst_addr", ip_str); + cJSON_AddNumberToObject(json_stream, "dst_port", ntohs(info->dst_addr.port)); + cJSON_AddStringToObject(json_stream, "user_name", (char *)info->user_name.iov_base); + cJSON_AddStringToObject(json_stream, "password", (char *)info->password.iov_base); + + cJSON_AddItemToObject(root, "socks_info", json_stream); +} + +void test_socks_decoder_on_message(struct session *session, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + unused(plugin_env); + unused(session); + unused(topic_id); + + struct socks_info *info = (struct socks_info *)msg; + cJSON *json_root = (cJSON *)per_session_ctx; + + append_json(json_root, info); +} + +extern "C" void *SOCKS_DECODER_TEST_PLUG_INIT(struct stellar *st) +{ + g_test_socks_decoder_plugin_id = stellar_session_plugin_register(st, ctx_new, ctx_free, NULL); + g_socks_message_topic_id = stellar_mq_get_topic_id(st, SOCKS_MESSAGE_TOPIC); + + stellar_session_mq_subscribe(st, g_socks_message_topic_id, test_socks_decoder_on_message, g_test_socks_decoder_plugin_id); + + + return NULL; +} + +extern "C" void SOCKS_DECODER_TEST_PLUG_DESTROY(void *plugin_env) +{ + unused(plugin_env); +} \ No newline at end of file diff --git a/test/decoders/socks/test_based_on_stellar/CMakeLists.txt b/test/decoders/socks/test_based_on_stellar/CMakeLists.txt new file mode 100644 index 0000000..2a3bc25 --- /dev/null +++ b/test/decoders/socks/test_based_on_stellar/CMakeLists.txt @@ -0,0 +1,37 @@ +set(DECODER_NAME socks) + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/test/decoders/socks) +set(SAPP_DEVEL_DIR ${TEST_RUN_DIR}/lib) +set(TEST_MAIN socks_test_main) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/test) +include_directories(/usr/local/include/cjson) +include_directories(/opt/tsg/framework/include/stellar) +include_directories(/opt/MESA/include/MESA) +include_directories(/opt/tsg/stellar/include/) + +#various ways to add -rdynamic for centos7, centos8, and different cmake version +add_definitions(-rdynamic) +link_directories(${SAPP_DEVEL_DIR}) + +# assemble test env +add_test(NAME SOCKS_MKDIR_METRIC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/metrics; mkdir -p ${TEST_RUN_DIR}/plugin; mkdir -p ${TEST_RUN_DIR}/log; mkdir -p ${TEST_RUN_DIR}/pcap") +add_test(NAME SOCKS_COPY_SPEC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/plugin/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/spec.toml ${TEST_RUN_DIR}/plugin/spec.toml") +add_test(NAME SOCKS_COPY_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/stellar.toml ${TEST_RUN_DIR}/conf/stellar.toml") +add_test(NAME SOCKS_COPY_LOG_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/log.toml ${TEST_RUN_DIR}/conf/log.toml") + +# update plugin to be tested +add_test(NAME SOCKS_CP_DECODER_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/decoders/socks/socks_dyn.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}.so") +add_test(NAME SOCKS_CP_DECODER_GTEST_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/decoders/socks/${DECODER_NAME}_test.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}_test.so") + +set_tests_properties(SOCKS_MKDIR_METRIC SOCKS_COPY_SPEC + SOCKS_COPY_CONF SOCKS_COPY_LOG_CONF + SOCKS_CP_DECODER_SO SOCKS_CP_DECODER_GTEST_SO + PROPERTIES FIXTURES_SETUP TestFixture) + +set(TEST_PCAP_DIR ${PROJECT_SOURCE_DIR}/test/decoders/socks/pcap) + +# run tests +add_test(NAME SOCKS_DECODER_PLUGIN_TEST COMMAND sh -c "ln -sf ${TEST_PCAP_DIR}/socks4_nest_socks4a.pcap ${TEST_RUN_DIR}/pcap/test.pcap; ./${TEST_MAIN} ${TEST_PCAP_DIR}/result.json" WORKING_DIRECTORY ${TEST_RUN_DIR}) + diff --git a/test/decoders/socks/test_based_on_stellar/env/log.toml b/test/decoders/socks/test_based_on_stellar/env/log.toml new file mode 100644 index 0000000..a51abd8 --- /dev/null +++ b/test/decoders/socks/test_based_on_stellar/env/log.toml @@ -0,0 +1,4 @@ +[log] +output = "stderr" # stderr, file +file = "log/stellar.log" +level = "ERROR" # TRACE, DEBUG, INFO, WARN, ERROR, FATAL diff --git a/test/decoders/socks/test_based_on_stellar/env/spec.toml b/test/decoders/socks/test_based_on_stellar/env/spec.toml new file mode 100644 index 0000000..71e58b4 --- /dev/null +++ b/test/decoders/socks/test_based_on_stellar/env/spec.toml @@ -0,0 +1,9 @@ +[[plugin]] +path = "./plugin/socks.so" +init = "socks_decoder_init" +exit = "socks_decoder_exit" + +[[plugin]] +path = "./plugin/socks_test.so" +init = "SOCKS_DECODER_TEST_PLUG_INIT" +exit = "SOCKS_DECODER_TEST_PLUG_DESTROY" diff --git a/test/decoders/socks/test_based_on_stellar/env/stellar.toml b/test/decoders/socks/test_based_on_stellar/env/stellar.toml new file mode 100644 index 0000000..308c884 --- /dev/null +++ b/test/decoders/socks/test_based_on_stellar/env/stellar.toml @@ -0,0 +1,64 @@ +[instance] + id = 1 # range: [0, 4095] (20 bit) + +[packet_io] + mode = "pcapfile" # pcapfile, pcaplist, marsio + app_symbol = "stellar" + dev_symbol = "nf_0_fw" + pcap_path = "./pcap/test.pcap" + nr_worker_thread = 1 # range: [1, 256] + cpu_mask = [5, 6, 7, 8, 9, 10, 11, 12] + idle_yield_interval_ms = 90 # range: [0, 60000] (ms) + +[ip_reassembly] + enable = 1 + bucket_entries = 32 # range: [1, 4294967295] (must be power of 2) + bucket_num = 1024 # range: [1, 4294967295] + + ip_frag_timeout_ms = 1000 # range: [1, 60000] (ms) + ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms) + ip_frag_expire_polling_limit = 1024 # range: [1, 1024] + +[session_manager] + tcp_session_max = 500 + udp_session_max = 500 + + evict_old_on_tcp_table_limit = 1 # range: [0, 1] + evict_old_on_udp_table_limit = 1 # range: [0, 1] + + expire_period_ms = 0 # range: [0, 60000] (ms) + expire_batch_max = 1024 # range: [1, 1024] + + [session_manager.tcp_timeout_ms] + init = 500 # range: [1, 60000] (ms) + handshake = 500 # range: [1, 60000] (ms) + data = 500 # range: [1, 15999999000] (ms) + half_closed = 500 # range: [1, 604800000] (ms) + time_wait = 500 # range: [1, 600000] (ms) + discard_default = 1000 # range: [1, 15999999000] (ms) + unverified_rst = 500 # range: [1, 600000] (ms) + + [session_manager.udp_timeout_ms] + data = 500 # range: [1, 15999999000] (ms) + discard_default = 500 # range: [1, 15999999000] (ms) + + [session_manager.duplicated_packet_bloom_filter] + enable = 0 + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.evicted_session_bloom_filter] + enable = 0 # range: [0, 1] + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.tcp_reassembly] + enable = 1 # range: [0, 1] + timeout_ms = 100 # range: [1, 60000] (ms) + buffered_segments_max = 256 # range: [2, 4096] per flow + +[stat] + merge_interval_ms = 500 # range: [0, 60000] (ms) + output_interval_ms = 1000 # range: [0, 60000] (ms) diff --git a/test/decoders/stratum/CMakeLists.txt b/test/decoders/stratum/CMakeLists.txt new file mode 100644 index 0000000..683efee --- /dev/null +++ b/test/decoders/stratum/CMakeLists.txt @@ -0,0 +1,41 @@ +set(DECODER_NAME stratum) + +add_library(${DECODER_NAME}_test SHARED stratum_test_plugin.cpp) +add_dependencies(${DECODER_NAME}_test ${DECODER_NAME}) +set_target_properties(${DECODER_NAME}_test PROPERTIES PREFIX "") + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/testing) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(${CMAKE_SOURCE_DIR}/deps/toml) +include_directories(${CMAKE_BINARY_DIR}/vendors/cjson/src/cjson/include) +include_directories(${PROJECT_SOURCE_DIR}/decoders/stratum) +include_directories(${PROJECT_SOURCE_DIR}/include/stellar) + +add_executable(gtest_pcap_stratum stratum_decoder_pcap_gtest.cpp dummy.c ${PROJECT_SOURCE_DIR}/decoders/stratum/stratum_decoder.cpp) +target_link_libraries(gtest_pcap_stratum gtest pcap cjson-static logger) + +add_executable(stratum_test_main plugin_test_main.cpp) +set_target_properties(stratum_test_main + PROPERTIES + LINK_OPTIONS + "-rdynamic" + ) +set_target_properties(stratum_test_main + PROPERTIES + LINK_FLAGS + "-rdynamic" + ) +set(LINK_FLAGS "-rdynamic") +#target_link_options(stratum_test_main PRIVATE -Wl,--whole-archive logger -Wl,--no-whole-archive) +set(CMAKE_VERBOSE_MAKEFILE ON) +target_link_libraries(stratum_test_main gtest cjson-static logger stellar_lib) + +add_subdirectory(test_based_on_stellar) + +#copy pcap file folder to build directory +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/pcap DESTINATION ${CMAKE_BINARY_DIR}/test/decoders/stratum) + +include(GoogleTest) +gtest_discover_tests(gtest_pcap_stratum) diff --git a/test/decoders/stratum/dummy.c b/test/decoders/stratum/dummy.c new file mode 100644 index 0000000..0290c59 --- /dev/null +++ b/test/decoders/stratum/dummy.c @@ -0,0 +1,86 @@ +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" + +#define UNUSED(x) (void)(x) + +void stellar_session_plugin_dettach_current_session(struct session *sess) +{ + UNUSED(sess); +} + +const struct packet *session_get0_current_packet(const struct session *sess) +{ + UNUSED(sess); + + return NULL; +} + +const char *packet_get_payload(const struct packet *pkt) +{ + UNUSED(pkt); + + return NULL; +} + +uint16_t packet_get_payload_len(const struct packet *pkt) +{ + UNUSED(pkt); + + return 0; +} + +struct logger *stellar_get_logger(struct stellar *st) +{ + UNUSED(st); + + return NULL; +} + +int session_mq_publish_message(struct session *sess, int topic_id, void *msg) +{ + UNUSED(sess); + UNUSED(topic_id); + UNUSED(msg); + + return 0; +} + +int stellar_mq_create_topic(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg) +{ + UNUSED(st); + UNUSED(topic_name); + UNUSED(msg_free_cb); + UNUSED(msg_free_arg); + + return 0; +} + +int stellar_mq_get_topic_id(struct stellar *st, const char *topic_name) +{ + UNUSED(st); + UNUSED(topic_name); + + return 0; +} + +int stellar_session_mq_subscribe(struct stellar *st, int topic_id, on_session_msg_cb_func *plugin_on_msg_cb, int plugin_id) +{ + UNUSED(st); + UNUSED(topic_id); + UNUSED(plugin_on_msg_cb); + UNUSED(plugin_id); + + return 0; +} + +int stellar_session_plugin_register(struct stellar *st, session_ctx_new_func session_ctx_new, session_ctx_free_func session_ctx_free, void *plugin_env) +{ + UNUSED(st); + UNUSED(session_ctx_new); + UNUSED(session_ctx_free); + UNUSED(plugin_env); + + return 0; +} \ No newline at end of file diff --git a/test/decoders/stratum/pcap/01-bch_f2pool_cpuminer_1.pcapng b/test/decoders/stratum/pcap/01-bch_f2pool_cpuminer_1.pcapng new file mode 100644 index 0000000..725aed7 Binary files /dev/null and b/test/decoders/stratum/pcap/01-bch_f2pool_cpuminer_1.pcapng differ diff --git a/test/decoders/stratum/pcap/02-eth-antpool.pcapng b/test/decoders/stratum/pcap/02-eth-antpool.pcapng new file mode 100644 index 0000000..5902981 Binary files /dev/null and b/test/decoders/stratum/pcap/02-eth-antpool.pcapng differ diff --git a/test/decoders/stratum/pcap/03-xmr_f2pool_nanominer_1.pcapng b/test/decoders/stratum/pcap/03-xmr_f2pool_nanominer_1.pcapng new file mode 100644 index 0000000..dfb0516 Binary files /dev/null and b/test/decoders/stratum/pcap/03-xmr_f2pool_nanominer_1.pcapng differ diff --git a/test/decoders/stratum/pcap/04-zec-antpool.pcapng b/test/decoders/stratum/pcap/04-zec-antpool.pcapng new file mode 100644 index 0000000..d46ab7f Binary files /dev/null and b/test/decoders/stratum/pcap/04-zec-antpool.pcapng differ diff --git a/test/decoders/stratum/pcap/stratum_result.json b/test/decoders/stratum/pcap/stratum_result.json new file mode 100644 index 0000000..37747ed --- /dev/null +++ b/test/decoders/stratum/pcap/stratum_result.json @@ -0,0 +1,11 @@ +[ + { + "stratum": + { + "Tuple4": "192.168.50.243:58748-120.26.148.222:1228-6-0", + "type": "OTHER", + "mining_program": "cpuminer/2.5.1", + "mining_subscribe": "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"cpuminer/2.5.1\"]}\n" + } + } +] \ No newline at end of file diff --git a/test/decoders/stratum/plugin_test_main.cpp b/test/decoders/stratum/plugin_test_main.cpp new file mode 100644 index 0000000..8f3d996 --- /dev/null +++ b/test/decoders/stratum/plugin_test_main.cpp @@ -0,0 +1,135 @@ +#include "cJSON.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif +#include "stellar/stellar.h" +#ifdef __cplusplus +} +#endif + +// #define IGNORE_PRINTF +#ifdef IGNORE_PRINTF +#define printf(fmt, ...) (0) +#endif +static cJSON *g_test_result_root = NULL; +static cJSON *g_load_result_root = NULL; +static const char *result_json_path = NULL; + +extern "C" int commit_test_result_json(cJSON *node, const char *name) +{ + (void)name; + if (g_test_result_root) + { + // cJSON_AddItemToObject(g_test_result_root, name, node); + // cJSON_AddStringToObject(node, "name", name); + cJSON_AddItemToArray(g_test_result_root, node); + return 0; + } + return -1; +} + +static cJSON *load_result_from_jsonfile(const char *json_path) +{ + if (json_path == NULL) + return NULL; + + long file_len = 0; + char *file_content = NULL; + FILE *fp = NULL; + + fp = fopen(json_path, "r+"); + if (NULL == fp) + { + return NULL; + } + fseek(fp, 0, SEEK_END); + file_len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (file_len == 0) + { + fclose(fp); + return NULL; + } + file_content = (char *)malloc(file_len + 1); + fread(file_content, file_len, 1, fp); + file_content[file_len] = '\0'; + cJSON *load = cJSON_Parse(file_content); + free(file_content); + fclose(fp); + + return load; +} + +TEST(PROTOCOL, compare_result_json) +{ + EXPECT_EQ(cJSON_GetArraySize(g_test_result_root), cJSON_GetArraySize(g_load_result_root)); + int ret = cJSON_Compare(g_test_result_root, g_load_result_root, 0); + EXPECT_EQ(1, ret); + + if (ret != 1) + { + char *load_json_str = cJSON_Print(g_load_result_root); + printf("LOAD Raw:\n%s\n", load_json_str); + free(load_json_str); + char *result_json_str = cJSON_Print(g_test_result_root); + printf("TEST Raw:\n%s\n", result_json_str); + free(result_json_str); + + cJSON *t_load = g_load_result_root->child, *t_test = g_test_result_root->child; + while (t_load != NULL) + { + ret = cJSON_Compare(t_load, t_test, 0); + if (ret != 1) + { + load_json_str = cJSON_Print(t_load); + printf("LOAD Diff:\n%s\n", load_json_str); + free(load_json_str); + result_json_str = cJSON_Print(t_test); + printf("TEST Diff:\n%s\n", result_json_str); + free(result_json_str); + goto fail; + } + t_load = t_load->next; + t_test = t_test->next; + } + } + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +fail: + cJSON_Delete(g_load_result_root); + cJSON_Delete(g_test_result_root); + return; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + result_json_path = NULL; + } + else + { + result_json_path = argv[1]; + g_test_result_root = cJSON_CreateArray(); + g_load_result_root = load_result_from_jsonfile(result_json_path); + assert(g_load_result_root != NULL && g_test_result_root != NULL); + } + ::testing::InitGoogleTest(&argc, argv); + struct stellar *st = stellar_new("./conf/stellar.toml", "./plugin/spec.toml", "./conf/log.toml"); + stellar_run(st); + if (result_json_path != NULL) + { + ret = RUN_ALL_TESTS(); + } + stellar_free(st); + return ret; +} diff --git a/test/decoders/stratum/stratum_decoder_pcap_gtest.cpp b/test/decoders/stratum/stratum_decoder_pcap_gtest.cpp new file mode 100644 index 0000000..a5c5b72 --- /dev/null +++ b/test/decoders/stratum/stratum_decoder_pcap_gtest.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" + +#include "stellar/stratum_decoder.h" + +#include + + +#define LINUX_COOKED_CAPTURE 20 + +struct pcap_loop_arg +{ + pcap_t *pcap_handle; + void *ctx; +}; + +extern struct stratum_field *stratum_data_process(struct stratum_decoder_info *stratum_decoder_info, const char *tcpdata, size_t datalen); +extern void free_stratum_filed(struct stratum_field *stratum_field); +extern "C" void *stratum_decoder_init(struct stellar *st); + +struct stratum_decoder_info *stratum_decoder_info = NULL; + +static void pcap_handle_cb(pcap_loop_arg *userarg, const struct pcap_pkthdr *pkthdr, const u_char *packet) +{ + struct pcap_loop_arg *arg = (struct pcap_loop_arg *)userarg; + int payload_len = 0; + char *payload = NULL; + unsigned short eth_proto_type; + unsigned char *ip_header; + + int data_link_type = pcap_datalink(arg->pcap_handle); + switch (data_link_type) { + case DLT_EN10MB: + eth_proto_type = ntohs(*(unsigned short *)(packet + 12)); + ip_header = (unsigned char *)(packet + sizeof(struct ethhdr)); + break; + case 276://DLT_LINUX_SLL2 + eth_proto_type = ntohs(*(unsigned short *)packet); + ip_header = (unsigned char *)(packet + LINUX_COOKED_CAPTURE); + break; + default: + return; + } + + if (eth_proto_type == ETH_P_IP) { + int l4_proto = *(unsigned char *)(ip_header + 9); + if (l4_proto == IPPROTO_TCP) { + int ip_total_len = ntohs(*(unsigned short *)(ip_header + 2)); + int ip_header_len = (*(unsigned char *)ip_header & 0x0f) * 4; + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(iphdr) + 12) & 0xf0) >> 4); + payload_len = ip_total_len - ip_header_len - tcp_header_len; + payload = (char *)ip_header + ip_header_len + tcp_header_len; + } else { + return; + } + + } else if (eth_proto_type == ETH_P_IPV6) { + int l4_proto = *(unsigned char *)(ip_header + 6); + if (l4_proto == IPPROTO_TCP) { + int tcp_header_len = 4 * ((*(unsigned char *)(ip_header + sizeof(struct ip6_hdr) + 12) & 0xf0) >> 4); + payload_len = pkthdr->caplen - (ip_header - packet) - sizeof(struct ip6_hdr) - tcp_header_len; + payload = (char *)ip_header + sizeof(struct ip6_hdr) + tcp_header_len; + } else { + return; + } + } else { + return; + } + + struct stratum_field *stratum = stratum_data_process(stratum_decoder_info, payload, payload_len); + if (stratum != NULL) + { + arg->ctx = stratum; + pcap_breakloop(arg->pcap_handle); + } +} + +TEST(stratum_decoder, parse01) +{ + char error[100]; + struct pcap_loop_arg arg; + pcap_t *handle = pcap_open_offline("pcap/01-bch_f2pool_cpuminer_1.pcapng", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.pcap_handle = handle; + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct stratum_field *stratum = (struct stratum_field *)arg.ctx; + EXPECT_EQ(stratum->type, OTHER); + EXPECT_STREQ((const char *)stratum->mining_program.iov_base, "cpuminer/2.5.1"); + EXPECT_EQ(stratum->mining_pools.iov_len, 0); + EXPECT_STREQ((const char *)stratum->mining_subscribe.iov_base, "{\"id\": 1, \"method\": \"mining.subscribe\", \"params\": [\"cpuminer/2.5.1\"]}\n"); + + pcap_close(handle); + free_stratum_filed(stratum); +} + +TEST(stratum_decoder, parse02) +{ + char error[100]; + struct pcap_loop_arg arg; + pcap_t *handle = pcap_open_offline("pcap/02-eth-antpool.pcapng", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.pcap_handle = handle; + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct stratum_field *stratum = (struct stratum_field *)arg.ctx; + EXPECT_EQ(stratum->type, ETH); + EXPECT_STREQ((const char *)stratum->mining_program.iov_base, "lolMinerWorker"); + EXPECT_EQ(stratum->mining_pools.iov_len, 0); + EXPECT_STREQ((const char *)stratum->mining_subscribe.iov_base, "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"eth_submitLogin\",\"worker\":\"lolMinerWorker\",\"params\":[\"0xa0279Ad2aA6BDb440f041Aa0947178431d9Bd253.lolMinerWorker\", \"x\"]} \n"); + + pcap_close(handle); + free_stratum_filed(stratum); +} + +TEST(stratum_decoder, parse03) +{ + char error[100]; + struct pcap_loop_arg arg; + pcap_t *handle = pcap_open_offline("pcap/03-xmr_f2pool_nanominer_1.pcapng", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.pcap_handle = handle; + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct stratum_field *stratum = (struct stratum_field *)arg.ctx; + EXPECT_EQ(stratum->type, OTHER); + EXPECT_STREQ((const char *)stratum->mining_program.iov_base, "nanominer/3.3.5-cuda11"); + EXPECT_EQ(stratum->mining_pools.iov_len, 0); + EXPECT_STREQ((const char *)stratum->mining_subscribe.iov_base, "{\"id\": 1, \"method\": \"login\", \"params\": { \"login\":\"yhzzhk.001.001\",\"pass\" : \"x\", \"agent\" : \"nanominer/3.3.5-cuda11\"}}\n"); + + pcap_close(handle); + free_stratum_filed(stratum); +} + +TEST(stratum_decoder, parse04) +{ + char error[100]; + struct pcap_loop_arg arg; + pcap_t *handle = pcap_open_offline("pcap/04-zec-antpool.pcapng", error); + ASSERT_NE(handle, nullptr); + + memset(&arg, 0, sizeof(arg)); + arg.pcap_handle = handle; + pcap_loop(handle, -1, (pcap_handler)pcap_handle_cb, (u_char *)&arg); + + struct stratum_field *stratum = (struct stratum_field *)arg.ctx; + EXPECT_EQ(stratum->type, OTHER); + EXPECT_STREQ((const char *)stratum->mining_program.iov_base, "nheqminer/0.5c"); + EXPECT_STREQ((const char*)stratum->mining_pools.iov_base, "stratum-zec.antpool.com"); + EXPECT_STREQ((const char *)stratum->mining_subscribe.iov_base, "{\"id\":1,\"method\":\"mining.subscribe\",\"params\":[\"nheqminer/0.5c\", null,\"stratum-zec.antpool.com\",\"8899\"]}\n"); + + pcap_close(handle); + free_stratum_filed(stratum); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + stratum_decoder_info = (struct stratum_decoder_info*)stratum_decoder_init(NULL); + + int result = RUN_ALL_TESTS(); + + return result; +} \ No newline at end of file diff --git a/test/decoders/stratum/stratum_test_plugin.cpp b/test/decoders/stratum/stratum_test_plugin.cpp new file mode 100644 index 0000000..3ec563b --- /dev/null +++ b/test/decoders/stratum/stratum_test_plugin.cpp @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "cJSON.h" +#include "stellar/stellar.h" +#include "stellar/session.h" +#include "stellar/stellar_mq.h" +#include "stellar/stellar_exdata.h" + +#include "stratum_decoder.h" + +#define unused(x) ((void)(x)) +extern "C" int commit_test_result_json(cJSON *node, const char *name); + +int g_test_stratum_decoder_plugin_id = 0; +int g_stratum_message_topic_id = 0; + +void *ctx_new(struct session *session, void *plugin_env) +{ + unused(plugin_env); + unused(session); + + cJSON *root = cJSON_CreateObject(); + return (void *)root; +} + +void ctx_free(struct session *sess, void *session_ctx, void *plugin_env) +{ + unused(sess); + unused(plugin_env); + + commit_test_result_json((cJSON *)session_ctx, "socks_decoder_test"); +} + +void test_stratum_decoder_on_message(struct session *session, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) +{ + unused(plugin_env); + unused(topic_id); + + struct stratum_field *stratum = (struct stratum_field *)msg; + cJSON *root = (cJSON *)per_session_ctx; + + cJSON *stratum_json = cJSON_CreateObject(); + cJSON_AddItemToObject(root, "stratum", stratum_json); + + cJSON_AddStringToObject(stratum_json, "Tuple4", session_get0_readable_addr(session)); + cJSON_AddStringToObject(stratum_json, "type", stratum->type == ETH ? "ETH" : "OTHER"); + cJSON_AddStringToObject(stratum_json, "mining_pools", (char *)stratum->mining_pools.iov_base); + cJSON_AddStringToObject(stratum_json, "mining_program", (char *)stratum->mining_program.iov_base); + cJSON_AddStringToObject(stratum_json, "mining_subscribe", (char *)stratum->mining_subscribe.iov_base); + +} + +extern "C" void *STRATUM_DECODER_TEST_PLUG_INIT(struct stellar *st) +{ + g_test_stratum_decoder_plugin_id = stellar_session_plugin_register(st, ctx_new, ctx_free, NULL); + g_stratum_message_topic_id = stellar_mq_get_topic_id(st, STRATUM_MESSAGE_TOPIC); + + if (stellar_session_mq_subscribe(st, g_stratum_message_topic_id, test_stratum_decoder_on_message, g_test_stratum_decoder_plugin_id) < 0) + { + printf("subscribe topic %s failed\n", STRATUM_MESSAGE_TOPIC); + return NULL; + } + + return NULL; +} + +extern "C" void STRATUM_DECODER_TEST_PLUG_DESTROY(void * plugin_env) +{ + unused(plugin_env); +} \ No newline at end of file diff --git a/test/decoders/stratum/test_based_on_stellar/CMakeLists.txt b/test/decoders/stratum/test_based_on_stellar/CMakeLists.txt new file mode 100644 index 0000000..1de14e5 --- /dev/null +++ b/test/decoders/stratum/test_based_on_stellar/CMakeLists.txt @@ -0,0 +1,37 @@ +set(DECODER_NAME stratum) + +set(TEST_RUN_DIR ${CMAKE_BINARY_DIR}/test/decoders/stratum) +set(SAPP_DEVEL_DIR ${TEST_RUN_DIR}/lib) +set(TEST_MAIN stratum_test_main) + +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_SOURCE_DIR}/test) +include_directories(/usr/local/include/cjson) +include_directories(/opt/tsg/framework/include/stellar) +include_directories(/opt/MESA/include/MESA) +include_directories(/opt/tsg/stellar/include/) + +#various ways to add -rdynamic for centos7, centos8, and different cmake version +add_definitions(-rdynamic) +link_directories(${SAPP_DEVEL_DIR}) + +# assemble test env +add_test(NAME STRATUM_MKDIR_METRIC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/metrics; mkdir -p ${TEST_RUN_DIR}/plugin; mkdir -p ${TEST_RUN_DIR}/log; mkdir -p ${TEST_RUN_DIR}/pcap") +add_test(NAME STRATUM_COPY_SPEC COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/plugin/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/spec.toml ${TEST_RUN_DIR}/plugin/spec.toml") +add_test(NAME STRATUM_COPY_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/stellar.toml ${TEST_RUN_DIR}/conf/stellar.toml") +add_test(NAME STRATUM_COPY_LOG_CONF COMMAND sh -c "mkdir -p ${TEST_RUN_DIR}/conf/ && cp ${CMAKE_CURRENT_SOURCE_DIR}/env/log.toml ${TEST_RUN_DIR}/conf/log.toml") + +# update plugin to be tested +add_test(NAME STRATUM_CP_DECODER_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/decoders/stratum/stratum_dyn.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}.so") +add_test(NAME STRATUM_CP_DECODER_GTEST_SO COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/decoders/stratum/${DECODER_NAME}_test.so ${TEST_RUN_DIR}/plugin/${DECODER_NAME}_test.so") + +set_tests_properties(STRATUM_MKDIR_METRIC STRATUM_COPY_SPEC + STRATUM_COPY_CONF STRATUM_COPY_LOG_CONF + STRATUM_CP_DECODER_SO STRATUM_CP_DECODER_GTEST_SO + PROPERTIES FIXTURES_SETUP TestFixture) + +set(TEST_PCAP_DIR ${PROJECT_SOURCE_DIR}/test/decoders/stratum/pcap) + +# run tests +add_test(NAME STRATUM_DECODER_PLUGIN_TEST COMMAND sh -c "ln -sf ${TEST_PCAP_DIR}/01-bch_f2pool_cpuminer_1.pcapng ${TEST_RUN_DIR}/pcap/test.pcap; ./${TEST_MAIN} ${TEST_PCAP_DIR}/stratum_result.json" WORKING_DIRECTORY ${TEST_RUN_DIR}) + diff --git a/test/decoders/stratum/test_based_on_stellar/env/log.toml b/test/decoders/stratum/test_based_on_stellar/env/log.toml new file mode 100644 index 0000000..b5213d9 --- /dev/null +++ b/test/decoders/stratum/test_based_on_stellar/env/log.toml @@ -0,0 +1,4 @@ +[log] +output = "stderr" # stderr, file +file = "log/stellar.log" +level = "INFO" # TRACE, DEBUG, INFO, WARN, ERROR, FATAL diff --git a/test/decoders/stratum/test_based_on_stellar/env/spec.toml b/test/decoders/stratum/test_based_on_stellar/env/spec.toml new file mode 100644 index 0000000..6eafab8 --- /dev/null +++ b/test/decoders/stratum/test_based_on_stellar/env/spec.toml @@ -0,0 +1,9 @@ +[[plugin]] +path = "./plugin/stratum.so" +init = "stratum_decoder_init" +exit = "stratum_decoder_exit" + +[[plugin]] +path = "./plugin/stratum_test.so" +init = "STRATUM_DECODER_TEST_PLUG_INIT" +exit = "STRATUM_DECODER_TEST_PLUG_DESTROY" diff --git a/test/decoders/stratum/test_based_on_stellar/env/stellar.toml b/test/decoders/stratum/test_based_on_stellar/env/stellar.toml new file mode 100644 index 0000000..308c884 --- /dev/null +++ b/test/decoders/stratum/test_based_on_stellar/env/stellar.toml @@ -0,0 +1,64 @@ +[instance] + id = 1 # range: [0, 4095] (20 bit) + +[packet_io] + mode = "pcapfile" # pcapfile, pcaplist, marsio + app_symbol = "stellar" + dev_symbol = "nf_0_fw" + pcap_path = "./pcap/test.pcap" + nr_worker_thread = 1 # range: [1, 256] + cpu_mask = [5, 6, 7, 8, 9, 10, 11, 12] + idle_yield_interval_ms = 90 # range: [0, 60000] (ms) + +[ip_reassembly] + enable = 1 + bucket_entries = 32 # range: [1, 4294967295] (must be power of 2) + bucket_num = 1024 # range: [1, 4294967295] + + ip_frag_timeout_ms = 1000 # range: [1, 60000] (ms) + ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms) + ip_frag_expire_polling_limit = 1024 # range: [1, 1024] + +[session_manager] + tcp_session_max = 500 + udp_session_max = 500 + + evict_old_on_tcp_table_limit = 1 # range: [0, 1] + evict_old_on_udp_table_limit = 1 # range: [0, 1] + + expire_period_ms = 0 # range: [0, 60000] (ms) + expire_batch_max = 1024 # range: [1, 1024] + + [session_manager.tcp_timeout_ms] + init = 500 # range: [1, 60000] (ms) + handshake = 500 # range: [1, 60000] (ms) + data = 500 # range: [1, 15999999000] (ms) + half_closed = 500 # range: [1, 604800000] (ms) + time_wait = 500 # range: [1, 600000] (ms) + discard_default = 1000 # range: [1, 15999999000] (ms) + unverified_rst = 500 # range: [1, 600000] (ms) + + [session_manager.udp_timeout_ms] + data = 500 # range: [1, 15999999000] (ms) + discard_default = 500 # range: [1, 15999999000] (ms) + + [session_manager.duplicated_packet_bloom_filter] + enable = 0 + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.evicted_session_bloom_filter] + enable = 0 # range: [0, 1] + capacity = 1000000 # range: [1, 4294967295] + time_window_ms = 10000 # range: [1, 60000] (ms) + error_rate = 0.00001 # range: [0.0, 1.0] + + [session_manager.tcp_reassembly] + enable = 1 # range: [0, 1] + timeout_ms = 100 # range: [1, 60000] (ms) + buffered_segments_max = 256 # range: [2, 4096] per flow + +[stat] + merge_interval_ms = 500 # range: [0, 60000] (ms) + output_interval_ms = 1000 # range: [0, 60000] (ms) diff --git a/vendors/CMakeLists.txt b/vendors/CMakeLists.txt index 5ed2c1b..07d5711 100644 --- a/vendors/CMakeLists.txt +++ b/vendors/CMakeLists.txt @@ -97,4 +97,41 @@ add_library(libevent-static STATIC IMPORTED GLOBAL) add_dependencies(libevent-static libevent) set_property(TARGET libevent-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libevent.a) set_property(TARGET libevent-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include) -set_property(TARGET libevent-static PROPERTY INTERFACE_LINK_LIBRARIES pthread) \ No newline at end of file +set_property(TARGET libevent-static PROPERTY INTERFACE_LINK_LIBRARIES pthread) + +set(VENDOR_BUILD ${CMAKE_BINARY_DIR}/vendor/vbuild) +# colm-0.14.7 +ExternalProject_Add(colm PREFIX colm + URL ${CMAKE_CURRENT_SOURCE_DIR}/colm-0.14.7.tar.gz + CONFIGURE_COMMAND ./autogen.sh && ./configure --prefix=${VENDOR_BUILD} + BUILD_COMMAND make + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1) + +# ragel-7.0.4 +ExternalProject_Add(ragel PREFIX ragel + URL ${CMAKE_CURRENT_SOURCE_DIR}/ragel-7.0.4.tar.gz + CONFIGURE_COMMAND ./autogen.sh && ./configure --prefix=${VENDOR_BUILD} --disable-manual --with-colm=${VENDOR_BUILD} + DEPENDS colm + BUILD_COMMAND make + INSTALL_COMMAND make install + BUILD_IN_SOURCE 1) + +# HyperScan 5.4.2 +ExternalProject_Add(hyperscan PREFIX hyperscan + URL ${CMAKE_CURRENT_SOURCE_DIR}/hyperscan-5.4.2.tar.gz + DEPENDS ragel + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${VENDOR_BUILD} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC") + +ExternalProject_Get_Property(hyperscan INSTALL_DIR) +file(MAKE_DIRECTORY ${VENDOR_BUILD}/include) + +add_library(hyperscan_static STATIC IMPORTED GLOBAL) +add_dependencies(hyperscan_static hyperscan) +set_property(TARGET hyperscan_static PROPERTY IMPORTED_LOCATION ${VENDOR_BUILD}/lib64/libhs.a) +set_property(TARGET hyperscan_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${VENDOR_BUILD}/include) + +add_library(hyperscan_runtime_static STATIC IMPORTED GLOBAL) +add_dependencies(hyperscan_runtime_static hyperscan) +set_property(TARGET hyperscan_runtime_static PROPERTY IMPORTED_LOCATION ${VENDOR_BUILD}/lib64/libhs_runtime.a) +set_property(TARGET hyperscan_runtime_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${VENDOR_BUILD}/include) \ No newline at end of file diff --git a/vendors/colm-0.14.7.tar.gz b/vendors/colm-0.14.7.tar.gz new file mode 100644 index 0000000..a73e692 Binary files /dev/null and b/vendors/colm-0.14.7.tar.gz differ diff --git a/vendors/hyperscan-5.4.2.tar.gz b/vendors/hyperscan-5.4.2.tar.gz new file mode 100644 index 0000000..fa49221 Binary files /dev/null and b/vendors/hyperscan-5.4.2.tar.gz differ diff --git a/vendors/ragel-7.0.4.tar.gz b/vendors/ragel-7.0.4.tar.gz new file mode 100644 index 0000000..d37daf6 Binary files /dev/null and b/vendors/ragel-7.0.4.tar.gz differ