#! /usr/bin/env bash # -*- coding: utf-8 -*- # Codes RED='\033[0;31m' GREEN='\033[0;32m' NC='\033[0m' OK_STR="${GREEN}OK${NC}" FAIL_STR="${RED}FAIL${NC}" CSCLI_BIN="./cscli" CSCLI="${CSCLI_BIN} -c dev.yaml" JQ="jq -e" CROWDSEC_API_URL="http://localhost:8081" CROWDSEC_VERSION="" API_KEY="" RELEASE_FOLDER_FULL="" FAILED="false" MUST_FAIL="false" get_latest_release() { CROWDSEC_VERSION=$(curl --silent "https://api.github.com/repos/crowdsecurity/crowdsec/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') } ### Helpers function docurl { URI=$1 curl -s -H "X-Api-Key: ${API_KEY}" "${CROWDSEC_API_URL}${URI}" } function bouncer_echo { if [[ ${FAILED} == "false" ]]; then echo -e "[bouncer] $1: ${OK_STR}" else echo -e "[bouncer] $1: ${FAIL_STR}" fi FAILED="false" } function cscli_echo { if [[ ${FAILED} == "false" ]]; then echo -e "[cscli] $1: ${OK_STR}" else echo -e "[cscli] $1: ${FAIL_STR}" fi FAILED="false" } function fail { FAILED="true" MUST_FAIL="true" } ## End helpersĀ ## function init { if [[ ! -d ${RELEASE_FOLDER} ]]; then cd .. get_latest_release BUILD_VERSION=${CROWDSEC_VERSION} make release if [ $? != 0 ]; then echo "Unable to make the release (make sur you have go installed), exiting" exit 1 fi RELEASE_FOLDER="crowdsec-${CROWDSEC_VERSION}" fi RELEASE_FOLDER_FULL="$(readlink -f ${RELEASE_FOLDER})" TEST_ENV_FOLDER="${RELEASE_FOLDER_FULL}/tests/" cd ${RELEASE_FOLDER}/ if [[ ! -d "${TEST_ENV_FOLDER}" ]]; then echo "Installing crowdsec test environment" ./test_env.sh fi reset } function test_ipv4_ip { echo "" echo "##########################################" echo "$FUNCNAME" echo "##########################################" echo "" ${CSCLI} decisions list -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "first decisions list" docurl /v1/decisions | ${JQ} '. == null' > /dev/null || fail bouncer_echo "first bouncer decisions request (must be empty)" #add ip decision echo "adding decision for 1.2.3.4" ${CSCLI} decisions add -i 1.2.3.4 > /dev/null 2>&1 || fail ${CSCLI} decisions list -o json | ${JQ} '.[].decisions[0].value == "1.2.3.4"' > /dev/null || fail cscli_echo "getting all decision" docurl /v1/decisions | ${JQ} '.[0].value == "1.2.3.4"' > /dev/null || fail bouncer_echo "getting all decision" #check ip match ${CSCLI} decisions list -i 1.2.3.4 -o json | ${JQ} '.[].decisions[0].value == "1.2.3.4"' > /dev/null || fail cscli_echo "getting decision for 1.2.3.4" docurl /v1/decisions?ip=1.2.3.4 | ${JQ} '.[0].value == "1.2.3.4"' > /dev/null || fail bouncer_echo "getting decision for 1.2.3.4" ${CSCLI} decisions list -i 1.2.3.5 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decision for 1.2.3.5" docurl /v1/decisions?ip=1.2.3.5 | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decision for 1.2.3.5" #check outer range match ${CSCLI} decisions list -r 1.2.3.0/24 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decision for 1.2.3.0/24" docurl "/v1/decisions?range=1.2.3.0/24" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decision for 1.2.3.0/24" ${CSCLI} decisions list -r 1.2.3.0/24 --contained -o json |${JQ} '.[].decisions[0].value == "1.2.3.4"' > /dev/null || fail cscli_echo "getting decisions where IP in 1.2.3.0/24" docurl "/v1/decisions?range=1.2.3.0/24&contains=false" | ${JQ} '.[0].value == "1.2.3.4"' > /dev/null || fail bouncer_echo "getting decisions where IP in 1.2.3.0/24" } function test_ipv4_range { echo "" echo "##########################################" echo "$FUNCNAME" echo "##########################################" echo "" cscli_echo "adding decision for range 4.4.4.0/24" ${CSCLI} decisions add -r 4.4.4.0/24 > /dev/null 2>&1 || fail ${CSCLI} decisions list -o json | ${JQ} '.[0].decisions[0].value == "4.4.4.0/24", .[1].decisions[0].value == "1.2.3.4"'> /dev/null || fail cscli_echo "getting all decision" docurl ${APIK} "/v1/decisions" | ${JQ} '.[0].value == "1.2.3.4", .[1].value == "4.4.4.0/24"'> /dev/null || fail bouncer_echo "getting all decision" #check ip within/outside of range ${CSCLI} decisions list -i 4.4.4.3 -o json | ${JQ} '.[].decisions[0].value == "4.4.4.0/24"' > /dev/null || fail cscli_echo "getting decisions for ip 4.4.4." docurl ${APIK} "/v1/decisions?ip=4.4.4.3" | ${JQ} '.[0].value == "4.4.4.0/24"' > /dev/null || fail bouncer_echo "getting decisions for ip 4.4.4." ${CSCLI} decisions list -i 4.4.4.4 -o json --contained | ${JQ} '. == null'> /dev/null || fail cscli_echo "getting decisions for ip contained in 4.4.4." docurl ${APIK} "/v1/decisions?ip=4.4.4.4&contains=false" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip contained in 4.4.4." ${CSCLI} decisions list -i 5.4.4.3 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip 5.4.4." docurl ${APIK} "/v1/decisions?ip=5.4.4.3" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip 5.4.4." ${CSCLI} decisions list -r 4.4.0.0/16 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range 4.4.0.0/1" docurl ${APIK} "/v1/decisions?range=4.4.0.0/16" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range 4.4.0.0/1" ${CSCLI} decisions list -r 4.4.0.0/16 -o json --contained | ${JQ} '.[].decisions[0].value == "4.4.4.0/24"' > /dev/null || fail cscli_echo "getting decisions for ip/range in 4.4.0.0/1" docurl ${APIK} "/v1/decisions?range=4.4.0.0/16&contains=false" | ${JQ} '.[0].value == "4.4.4.0/24"' > /dev/null || fail bouncer_echo "getting decisions for ip/range in 4.4.0.0/1" #check subrange ${CSCLI} decisions list -r 4.4.4.2/28 -o json | ${JQ} '.[].decisions[0].value == "4.4.4.0/24"' > /dev/null || fail cscli_echo "getting decisions for range 4.4.4.2/2" docurl ${APIK} "/v1/decisions?range=4.4.4.2/28" | ${JQ} '.[].value == "4.4.4.0/24"' > /dev/null || fail bouncer_echo "getting decisions for range 4.4.4.2/2" ${CSCLI} decisions list -r 4.4.3.2/28 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range 4.4.3.2/2" docurl ${APIK} "/v1/decisions?range=4.4.3.2/28" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range 4.4.3.2/2" } function test_ipv6_ip { echo "" echo "##########################################" echo "$FUNCNAME" echo "##########################################" echo "" cscli_echo "adding decision for ip 1111:2222:3333:4444:5555:6666:7777:8888" ${CSCLI} decisions add -i 1111:2222:3333:4444:5555:6666:7777:8888 > /dev/null 2>&1 ${CSCLI} decisions list -o json | ${JQ} '.[].decisions[0].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail cscli_echo "getting all decision" docurl ${APIK} "/v1/decisions" | ${JQ} '.[].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail bouncer_echo "getting all decision" ${CSCLI} decisions list -i 1111:2222:3333:4444:5555:6666:7777:8888 -o json | ${JQ} '.[].decisions[0].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail cscli_echo "getting decisions for ip 1111:2222:3333:4444:5555:6666:7777:8888" docurl ${APIK} "/v1/decisions?ip=1111:2222:3333:4444:5555:6666:7777:8888" | ${JQ} '.[].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail bouncer_echo "getting decisions for ip 1111:2222:3333:4444:5555:6666:7777:888" ${CSCLI} decisions list -i 1211:2222:3333:4444:5555:6666:7777:8888 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip 1211:2222:3333:4444:5555:6666:7777:8888" docurl ${APIK} "/v1/decisions?ip=1211:2222:3333:4444:5555:6666:7777:8888" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip 1211:2222:3333:4444:5555:6666:7777:888" ${CSCLI} decisions list -i 1111:2222:3333:4444:5555:6666:7777:8887 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip 1111:2222:3333:4444:5555:6666:7777:8887" docurl ${APIK} "/v1/decisions?ip=1111:2222:3333:4444:5555:6666:7777:8887" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip 1111:2222:3333:4444:5555:6666:7777:888" ${CSCLI} decisions list -r 1111:2222:3333:4444:5555:6666:7777:8888/48 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range 1111:2222:3333:4444:5555:6666:7777:8888/48" docurl ${APIK} "/v1/decisions?range=1111:2222:3333:4444:5555:6666:7777:8888/48" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range 1111:2222:3333:4444:5555:6666:7777:8888/48" ${CSCLI} decisions list -r 1111:2222:3333:4444:5555:6666:7777:8888/48 --contained -o json | ${JQ} '.[].decisions[0].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail cscli_echo "getting decisions for ip/range in range 1111:2222:3333:4444:5555:6666:7777:8888/48" docurl ${APIK} "/v1/decisions?range=1111:2222:3333:4444:5555:6666:7777:8888/48&&contains=false" | ${JQ} '.[].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail bouncer_echo "getting decisions for ip/range in 1111:2222:3333:4444:5555:6666:7777:8888/48" ${CSCLI} decisions list -r 1111:2222:3333:4444:5555:6666:7777:8888/64 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range 1111:2222:3333:4444:5555:6666:7777:8888/64" docurl ${APIK} "/v1/decisions?range=1111:2222:3333:4444:5555:6666:7777:8888/64" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range 1111:2222:3333:4444:5555:6666:7777:8888/64" ${CSCLI} decisions list -r 1111:2222:3333:4444:5555:6666:7777:8888/64 -o json --contained | ${JQ} '.[].decisions[0].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail cscli_echo "getting decisions for ip/range in 1111:2222:3333:4444:5555:6666:7777:8888/64" docurl ${APIK} "/v1/decisions?range=1111:2222:3333:4444:5555:6666:7777:8888/64&&contains=false" | ${JQ} '.[].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail bouncer_echo "getting decisions for ip/range in 1111:2222:3333:4444:5555:6666:7777:8888/64" } function test_ipv6_range { echo "" echo "##########################################" echo "$FUNCNAME" echo "##########################################" echo "" cscli_echo "adding decision for range aaaa:2222:3333:4444::/64" ${CSCLI} decisions add -r aaaa:2222:3333:4444::/64 > /dev/null 2>&1 || fail ${CSCLI} decisions list -o json | ${JQ} '.[0].decisions[0].value == "aaaa:2222:3333:4444::/64", .[1].decisions[0].value == "1111:2222:3333:4444:5555:6666:7777:8888"' > /dev/null || fail cscli_echo "getting all decision" docurl ${APIK} "/v1/decisions" | ${JQ} '.[0].value == "1111:2222:3333:4444:5555:6666:7777:8888", .[1].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail bouncer_echo "getting all decision" #check ip within/out of range ${CSCLI} decisions list -i aaaa:2222:3333:4444:5555:6666:7777:8888 -o json | ${JQ} '.[].decisions[0].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail cscli_echo "getting decisions for ip aaaa:2222:3333:4444:5555:6666:7777:8888" docurl ${APIK} "/v1/decisions?ip=aaaa:2222:3333:4444:5555:6666:7777:8888" | ${JQ} '.[].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail bouncer_echo "getting decisions for ip aaaa:2222:3333:4444:5555:6666:7777:8888" ${CSCLI} decisions list -i aaaa:2222:3333:4445:5555:6666:7777:8888 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip aaaa:2222:3333:4445:5555:6666:7777:8888" docurl ${APIK} "/v1/decisions?ip=aaaa:2222:3333:4445:5555:6666:7777:8888" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip aaaa:2222:3333:4445:5555:6666:7777:8888" ${CSCLI} decisions list -i aaa1:2222:3333:4444:5555:6666:7777:8887 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip aaa1:2222:3333:4444:5555:6666:7777:8887" docurl ${APIK} "/v1/decisions?ip=aaa1:2222:3333:4444:5555:6666:7777:8887" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip aaa1:2222:3333:4444:5555:6666:7777:8887" #check subrange within/out of range ${CSCLI} decisions list -r aaaa:2222:3333:4444:5555::/80 -o json | ${JQ} '.[].decisions[0].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail cscli_echo "getting decisions for range aaaa:2222:3333:4444:5555::/80" docurl ${APIK} "/v1/decisions?range=aaaa:2222:3333:4444:5555::/80" | ${JQ} '.[].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail bouncer_echo "getting decisions for range aaaa:2222:3333:4444:5555::/80" ${CSCLI} decisions list -r aaaa:2222:3333:4441:5555::/80 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range aaaa:2222:3333:4441:5555::/80" docurl ${APIK} "/v1/decisions?range=aaaa:2222:3333:4441:5555::/80" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range aaaa:2222:3333:4441:5555::/80" ${CSCLI} decisions list -r aaa1:2222:3333:4444:5555::/80 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range aaa1:2222:3333:4444:5555::/80" docurl ${APIK} "/v1/decisions?range=aaa1:2222:3333:4444:5555::/80" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range aaa1:2222:3333:4444:5555::/80" #check outer range ${CSCLI} decisions list -r aaaa:2222:3333:4444:5555:6666:7777:8888/48 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for range aaaa:2222:3333:4444:5555:6666:7777:8888/48" docurl ${APIK} "/v1/decisions?range=aaaa:2222:3333:4444:5555:6666:7777:8888/48" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for range aaaa:2222:3333:4444:5555:6666:7777:8888/48" ${CSCLI} decisions list -r aaaa:2222:3333:4444:5555:6666:7777:8888/48 -o json --contained | ${JQ} '.[].decisions[0].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail cscli_echo "getting decisions for ip/range in aaaa:2222:3333:4444:5555:6666:7777:8888/48" docurl ${APIK} "/v1/decisions?range=aaaa:2222:3333:4444:5555:6666:7777:8888/48&contains=false" | ${JQ} '.[].value == "aaaa:2222:3333:4444::/64"' > /dev/null || fail bouncer_echo "getting decisions for ip/range in aaaa:2222:3333:4444:5555:6666:7777:8888/48" ${CSCLI} decisions list -r aaaa:2222:3333:4445:5555:6666:7777:8888/48 -o json | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip/range aaaa:2222:3333:4445:5555:6666:7777:8888/48" docurl ${APIK} "/v1/decisions?range=aaaa:2222:3333:4445:5555:6666:7777:8888/48" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip/range in aaaa:2222:3333:4445:5555:6666:7777:8888/48" #bbbb:db8:: -> bbbb:db8:0000:0000:0000:7fff:ffff:ffff ${CSCLI} decisions add -r bbbb:db8::/81 > /dev/null 2>&1 cscli_echo "adding decision for range bbbb:db8::/81" > /dev/null || fail ${CSCLI} decisions list -o json -i bbbb:db8:0000:0000:0000:6fff:ffff:ffff | ${JQ} '.[].decisions[0].value == "bbbb:db8::/81"' > /dev/null || fail cscli_echo "getting decisions for ip bbbb:db8:0000:0000:0000:6fff:ffff:ffff" docurl ${APIK} "/v1/decisions?ip=bbbb:db8:0000:0000:0000:6fff:ffff:ffff" | ${JQ} '.[].value == "bbbb:db8::/81"' > /dev/null || fail bouncer_echo "getting decisions for ip in bbbb:db8:0000:0000:0000:6fff:ffff:ffff" ${CSCLI} decisions list -o json -i bbbb:db8:0000:0000:0000:8fff:ffff:ffff | ${JQ} '. == null' > /dev/null || fail cscli_echo "getting decisions for ip bbbb:db8:0000:0000:0000:8fff:ffff:ffff" docurl ${APIK} "/v1/decisions?ip=bbbb:db8:0000:0000:0000:8fff:ffff:ffff" | ${JQ} '. == null' > /dev/null || fail bouncer_echo "getting decisions for ip in bbbb:db8:0000:0000:0000:8fff:ffff:ffff" } function start_test { ## ipv4 testing test_ipv4_ip test_ipv4_range reset ## ipv6 testing test_ipv6_ip test_ipv6_range } function reset { cd ${RELEASE_FOLDER_FULL}/tests/ rm data/crowdsec.db > /dev/null 2>&1 || echo "" killall crowdsec > /dev/null 2>&1 || echo "" ${CSCLI} hub update ${CSCLI} machines add -a API_KEY=`${CSCLI} bouncers add TestingBouncer -o=raw` ./crowdsec -c dev.yaml> crowdsec-out.log 2>&1 & sleep 2 } function down { cd ${RELEASE_FOLDER_FULL}/tests/ rm data/crowdsec.db killall crowdsec #rm -rf tests/ } usage() { echo "Usage:" echo "" echo " ./ip_mgmt_tests.sh -h Display this help message." echo " ./ip_mgmt_tests.sh Run all the testsuite. Go must be available to make the release" echo " ./ip_mgmt_tests.sh --release If go is not installed, please provide a path to the crowdsec-vX.Y.Z release folder" echo "" exit 0 } while [[ $# -gt 0 ]] do key="${1}" case ${key} in --release|-r) RELEASE_FOLDER="${2}" shift #past argument shift ;; -h|--help) usage exit 0 ;; *) # unknown option echo "Unknown argument ${key}." usage exit 1 ;; esac done init start_test down if [[ ${MUST_FAIL} == "true" ]]; then echo "" echo "One or more tests have failed !" exit 1 fi