Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative TLS Load Test #5097

Open
wants to merge 8 commits into
base: v3.2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions src/tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ SECRET = testing123
#
# Build the directory for testing the server
#
all: tests
all: tests tests.load

clean:
@rm -f test.conf dictionary *.ok *.log $(BUILD_DIR)/tests/eap
Expand All @@ -136,20 +136,30 @@ test.conf: dictionary config/eap-test
fi
${Q}echo "testdir =" $(TEST_PATH) >> $@
${Q}echo 'logdir = $${testdir}' >> $@
${Q}echo "maindir =" $(RADDB_PATH) >> $@
${Q}echo "maindir =" $(RADDB_PATH:/=) >> $@
${Q}echo 'radacctdir = $${testdir}' >> $@
${Q}echo 'pidfile = $${testdir}/radiusd.pid' >> $@
${Q}echo 'panic_action = "gdb -batch -x $${testdir}/panic.gdb %e %p > $${testdir}/gdb.log 2>&1; cat $${testdir}/gdb.log"' >> $@
${Q}echo 'security {' >> $@
${Q}echo ' allow_vulnerable_openssl = yes' >> $@
${Q}echo '}' >> $@
${Q}echo >> $@
${Q}echo 'modconfdir = $${maindir}mods-config' >> $@
${Q}echo 'modconfdir = $${maindir}/mods-config' >> $@
${Q}echo 'certdir = $${maindir}/certs' >> $@
${Q}echo 'cadir = $${maindir}/certs' >> $@
${Q}echo '$$INCLUDE $${testdir}/config/' >> $@
${Q}echo '$$INCLUDE $${maindir}/radiusd.conf' >> $@

$(RADDB_PATH)certs/server.pem:
${Q}openssl genrsa -out test.key 2048
${Q}openssl req -x509 -sha256 -new -nodes -key test.key -days 3650 -subj "/C=--/ST=--/L=--/O=--/CN=--" -out test.crt
${Q}cat test.key test.crt > $(RADDB_PATH)certs/server.pem

$(RADDB_PATH)certs/ca.pem:
${Q}openssl genrsa -out test.key 2048
${Q}openssl req -x509 -sha256 -new -nodes -key test.key -days 3650 -subj "/C=--/ST=--/L=--/O=--/CN=--" -out test.crt
${Q}cat test.key test.crt > $(RADDB_PATH)certs/ca.pem

#
# Rename "inner-tunnel", and ensure that it only uses the "eap-test" module.
#
Expand All @@ -175,9 +185,10 @@ config/eap-test: $(RADDB_PATH)mods-available/eap config/eap-test-inner-tunnel
-e 's/cipher_list = "DEFAULT"/cipher_list = "DEFAULT${SECLEVEL}"/' \
< $< > $@

radiusd.pid: test.conf
radiusd.pid: test.conf $(RADDB_PATH)certs/ca.pem $(RADDB_PATH)certs/server.pem
${Q}rm -rf $(TEST_PATH)/gdb.log $(TEST_PATH)/radius.log $(TEST_PATH)/tlscache
${Q}mkdir -p $(TEST_PATH)/tlscache
$(info ${RADIUSD_BIN} -Pxxxxml ${TEST_PATH}/radius.log -d ${top_builddir}/src/tests -n test -i 127.0.0.1 -p ${PORT} -D ${DICT_PATH})
delexagon marked this conversation as resolved.
Show resolved Hide resolved
${Q}printf "Starting server... "
${Q}if ! $(RADIUSD_BIN) -Pxxxxml $(TEST_PATH)/radius.log -d ${top_builddir}/src/tests -n test -i 127.0.0.1 -p $(PORT) -D $(DICT_PATH); then \
echo "failed"; \
Expand Down Expand Up @@ -326,4 +337,8 @@ tests.runtests: test.conf | radiusd.kill radiusd.pid
${Q}chmod a+x runtests.sh
${Q}BIN_PATH="$(BIN_PATH)" PORT="$(PORT)" ./runtests.sh $(TESTS)

# probably not the best way to do this
tests.load:
${Q}(cd tls-load && BUILD_DIR=${BUILD_PATH} LIB_DIR=${LIB_PATH} DICT_DIR=${top_builddir}/share RADDB_DIR=${top_builddir}/raddb ./run_test.sh -o output 10)

tests: tests.runtests tests.eap
6 changes: 6 additions & 0 deletions src/tests/tls-load/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ARG from=ubuntu:latest
FROM ${from} as build
ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update
RUN apt-get install -y libtalloc-dev
18 changes: 18 additions & 0 deletions src/tests/tls-load/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# TLS Load Testing

Runs local radiusd load testing for TLS using docker compose.
Requires Docker.
### Usage:
`./run_test.sh -o output (number of concurrent clients/servers running)`
### Options:
- `-n`: number of messages to send per client (default is 1000)
- `-l`: log level for home/proxy servers (default is 1, 1=`radiusd -f`, 2=`radiusd -fx`, 3=`radiusd -fxx`, other=no log files generated)
- `-o`: where to put log files after running (if left empty, output will not be generated)

### Output:
- `client_*.log`: Output of radclient for each running client
- `home_*.log`: Output from radiusd of home servers
- `proxy.log`: Output from radiusd of proxy server

### Result:
The script will exit 0 if all clients succeed or 1 if any client fails, and will print a corresponding message.
79 changes: 79 additions & 0 deletions src/tests/tls-load/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
version: "3"

name: test-container

networks:
test-net:

services:
tasks:
image: radius_libraries
build:
context: .
args:
from: ${BASE_IMAGE}
entrypoint: bash -c "mkdir /test/containers ; rm /test/containers/*"
volumes:
- ./test:/test

proxy:
depends_on:
- home
- client
image: radius_libraries
build:
context: .
args:
from: ${BASE_IMAGE}
entrypoint: /test/proxy-entrypoint.sh
environment:
- LOG_LEVEL
networks:
- test-net
volumes:
- ./test:/test
- ${BUILD_DIR}:/etc/freeradius
- ${DICT_DIR}:/dict
- ${LIB_DIR}:/usr/lib/freeradius
- ${RADDB_DIR}:/raddb
- ./certs:/certs

home:
depends_on:
- tasks
image: radius_libraries
build:
context: .
args:
from: ${BASE_IMAGE}
entrypoint: bash /test/home-entrypoint.sh
environment:
- LOG_LEVEL
networks:
- test-net
volumes:
- ./test:/test
- ${BUILD_DIR}:/etc/freeradius
- ${DICT_DIR}:/dict
- ${LIB_DIR}:/usr/lib/freeradius
- ${RADDB_DIR}:/raddb
- ./certs:/certs

client:
depends_on:
- tasks
image: radius_libraries
build:
context: .
args:
from: ${BASE_IMAGE}
entrypoint: /test/client-entrypoint.sh
environment:
- NUM_REQUESTS
networks:
- test-net
volumes:
- ./test:/test
- ${BUILD_DIR}:/etc/freeradius
- ${DICT_DIR}:/dict
- ${LIB_DIR}:/usr/lib/freeradius
84 changes: 84 additions & 0 deletions src/tests/tls-load/run_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/bin/bash
# Other shells not tested
# Arguments in caps are exported to containers or relevant in docker-compose.yml

export BASE_IMAGE=${BASE_IMAGE:-ubuntu:latest}
export BUILD_DIR=${BUILD_DIR:-../../../build}
export DICT_DIR=${DICT_DIR:-../../../share}
export LIB_DIR=${LIB_DIR:-../../../build/lib/.libs}
export RADDB_DIR=${RADDB_DIR:-../../../raddb}
yes | docker compose rm
if ! [ "$?" -eq 0 ]; then
echo "Docker failed"
exit 1
fi

### ARGUMENT PARSING ###
# Note -s and -b require the freeradius docker image to be rebuilt, meaning it must be removed, or renamed with -i.
while getopts ':n:l:d:r:o:bm' OPTION; do
case "$OPTION" in
n)
NUM_REQUESTS="$OPTARG"
;;
l)
LOG_LEVEL="$OPTARG"
;;
o)
output_dir="$OPTARG"
;;
?)
echo "Usage: $0 [-n number_of_requests_per_realm] [-l log_level (0=none, 1,2,3=radiusd -f, -fx, -fxx)] [-o output_log_dir] number_of_realms"
exit 1
;;
esac
done
shift "$(($OPTIND-1))"

max_container_num=100
num_realms="$1"
if [[ "/$num_realms" = "/" ]]; then
echo "No container num given"
exit 1
fi
if [ "$num_realms" -gt "$max_container_num" ]; then
echo "You have tried to create more than $max_container_num docker containers, exiting load testing script without running"
exit 1
fi
export NUM_REQUESTS=${NUM_REQUESTS:-5000}
export LOG_LEVEL=${LOG_LEVEL:-1}

### DOCKER ###
docker compose up -d --scale home="$num_realms" --scale client="$num_realms"
if ! [ "$?" -eq 0 ]; then
echo "Docker failed"
exit 1
fi

# Check for when all of the client containers have exited
while docker compose ps | grep client; do
sleep 3
done

docker compose stop

# Move all the output to an external directory if specified
if [[ "/$output_dir" != "/" ]]; then
docker logs test-container-proxy-1 > "$output_dir"/proxy.log
i=1
while [ "$i" -le $num_realms ]; do
docker logs test-container-client-"$i" > "$output_dir"/client_"$i".log&
docker logs test-container-home-"$i" > "$output_dir"/home_"$i".log&
i=$((i+1))
done
fi

# Check that the number of clients that were created is the same as the number of clients that were created and exited successfully
if [ $(docker compose ps --all | grep -c client) -eq $(docker compose ps --all | grep -c "client.*Exited (0)") ]; then
echo "TLS load test succeeded"
yes | docker compose rm &> /dev/null
exit 0
else
echo "TLS load test failed"
yes | docker compose rm &> /dev/null
exit 1
fi
18 changes: 18 additions & 0 deletions src/tests/tls-load/test/client-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
touch /test/containers/realm_"$HOSTNAME"
# Unfortunately, I don't really know a better way to synchronize the clients than a short sleep length
# and a sufficient number of requests.
# It still seems like sometimes one can start inordinately later than the others.
while ! [ -f "/test/containers/proxy-running" ]; do
sleep 0.1
done
rm /test/containers/realm_"$HOSTNAME"
echo /etc/freeradius/lib/local/.libs >> /etc/ld.so.conf
ldconfig
echo User-Name="bob@realm_$HOSTNAME",User-Password="bob",Message-Authenticator=0x00 | /etc/freeradius/bin/local/radclient -D /dict -c "$NUM_REQUESTS" test-container-proxy-1 auth testing123
if [ "$?" -ne 0 ] ; then
echo "This container failed"
exit 1
else
echo "This container succeeded"
fi
Empty file.
10 changes: 10 additions & 0 deletions src/tests/tls-load/test/home-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
echo /etc/freeradius/lib/local/.libs >> /etc/ld.so.conf
delexagon marked this conversation as resolved.
Show resolved Hide resolved
ldconfig
if [ "$LOG_LEVEL" -eq 2 ]; then
exec /etc/freeradius/bin/local/radiusd -D /dict -d /test/home -fx -l stdout
elif [ "$LOG_LEVEL" -eq 3 ]; then
exec /etc/freeradius/bin/local/radiusd -D /dict -d /test/home -fxx -l stdout
else
exec /etc/freeradius/bin/local/radiusd -D /dict -d /test/home -f -l stdout
fi
104 changes: 104 additions & 0 deletions src/tests/tls-load/test/home/radiusd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#
# Minimal radiusd.conf for testing
#
raddb = /raddb
modconfdir = ${raddb}/mods-config
testdir = /test
pidfile = ${testdir}/radiusd.pid
panic_action = "gdb -batch -x ${raddb}/panic.gdb %e %p > ${testdir}/gdb-radiusd.log 2>&1; cat ${testdir}/gdb-radiusd.log"
certdir = /certs
cadir = /certs
libdir = /usr/lib/freeradius

max_requests = 1048576

thread pool {
start_servers = 5
max_servers = 32
min_spare_servers = 3
max_spare_servers = 10
max_requests_per_server = 0
cleanup_delay = 5
max_queue_size = 65536
auto_limit_acct = no
}

#
# Referenced by some modules for default thread pool configuration
#
modules {
$INCLUDE ${raddb}/mods-available/always
}

clients radsec {
client all {
ipaddr = 0.0.0.0/0
proto = tls
}
}

listen {
type = auth

ipaddr = *
port = 1812
proto = tcp

clients = radsec

virtual_server = default

tls {
private_key_password = whatever
private_key_file = ${certdir}/server.pem
certificate_file = ${certdir}/server.pem
ca_file = ${cadir}/ca.pem
fragment_size = 8192
ca_path = ${cadir}
cipher_list = "DEFAULT"
tls_min_version = "1.2"
tls_max_version = "1.2"
}
}

listen {
type = acct

ipaddr = *
port = 1813
proto = tcp

clients = radsec

virtual_server = default

tls {
private_key_password = whatever
private_key_file = ${certdir}/server.pem
certificate_file = ${certdir}/server.pem
ca_file = ${cadir}/ca.pem
fragment_size = 8192
ca_path = ${cadir}
cipher_list = "DEFAULT"
tls_min_version = "1.3"
tls_max_version = "1.3"
}
}

server default {
authorize {
update control {
Auth-Type := accept
}
}

preacct {
update control {
Response-Packet-Type := Accounting-Response
}
}

acct {
ok
}
}
Loading