This commit is contained in:
m0duspwnens
2021-01-15 10:48:19 -05:00
8 changed files with 823 additions and 299 deletions

View File

@@ -19,6 +19,8 @@
/opt/so/log/telegraf/*.log
/opt/so/log/redis/*.log
/opt/so/log/salt/so-salt-minion-check
/opt/so/log/salt/minion
/opt/so/log/salt/master
{
{{ logrotate_conf | indent(width=4) }}
}

View File

@@ -24,9 +24,70 @@ fi
# Define a banner to separate sections
banner="========================================================================="
add_interface_bond0() {
local BNIC=$1
if [[ -z $MTU ]]; then
local MTU
MTU=$(lookup_pillar "mtu" "sensor")
fi
local nic_error=0
# Check if specific offload features are able to be disabled
for string in "generic-segmentation-offload" "generic-receive-offload" "tcp-segmentation-offload"; do
if ethtool -k "$BNIC" | grep $string | grep -q "on [fixed]"; then
echo "The hardware or driver for interface ${BNIC} is not supported, packet capture may not work as expected."
((nic_error++))
break
fi
done
case "$2" in
-v|--verbose)
local verbose=true
;;
esac
for i in rx tx sg tso ufo gso gro lro; do
if [[ $verbose != true ]]; then
ethtool -K "$BNIC" $i off
else
ethtool -K "$BNIC" $i off &>/dev/null
fi
done
# Check if the bond slave connection has already been created
nmcli -f name,uuid -p con | grep -q "bond0-slave-$BNIC"
local found_int=$?
if [[ $found_int != 0 ]]; then
# Create the slave interface and assign it to the bond
nmcli con add type ethernet ifname "$BNIC" con-name "bond0-slave-$BNIC" master bond0 -- \
ethernet.mtu "$MTU" \
connection.autoconnect "yes"
else
local int_uuid
int_uuid=$(nmcli -f name,uuid -p con | sed -n "s/bond0-slave-$BNIC //p" | tr -d ' ')
nmcli con mod "$int_uuid" \
ethernet.mtu "$MTU" \
connection.autoconnect "yes"
fi
ip link set dev "$BNIC" arp off multicast off allmulticast off promisc on
# Bring the slave interface up
if [[ $verbose != true ]]; then
nmcli con up "bond0-slave-$BNIC"
else
nmcli con up "bond0-slave-$BNIC" &>/dev/null
fi
if [ "$nic_error" != 0 ]; then
return "$nic_error"
fi
}
header() {
echo
printf '%s\n' "$banner" "$*" "$banner"
printf '%s\n' "" "$banner" " $*" "$banner"
}
lookup_salt_value() {
@@ -111,7 +172,7 @@ set_version() {
}
require_manager() {
if is_manager; then
if is_manager_node; then
echo "This is a manager, We can proceed."
else
echo "Please run this command on the manager; the manager controls the grid."
@@ -119,7 +180,7 @@ require_manager() {
fi
}
is_manager() {
is_manager_node() {
# Check to see if this is a manager node
role=$(lookup_role)
is_single_node_grid && return 0
@@ -129,7 +190,7 @@ is_manager() {
return 1
}
is_sensor() {
is_sensor_node() {
# Check to see if this is a sensor (forward) node
role=$(lookup_role)
is_single_node_grid && return 0
@@ -232,6 +293,93 @@ __check_apt_lock() {
return $lock
}
valid_cidr() {
# Verify there is a backslash in the string
echo "$1" | grep -qP "^[^/]+/[^/]+$" || return 1
local cidr
local ip
cidr=$(echo "$1" | sed 's/.*\///')
ip=$(echo "$1" | sed 's/\/.*//' )
if valid_ip4 "$ip"; then
[[ $cidr =~ ([0-9]|[1-2][0-9]|3[0-2]) ]] && return 0 || return 1
else
return 1
fi
}
valid_cidr_list() {
local all_valid=0
IFS="," read -r -a net_arr <<< "$1"
for net in "${net_arr[@]}"; do
valid_cidr "$net" || all_valid=1
done
return $all_valid
}
valid_dns_list() {
local all_valid=0
IFS="," read -r -a dns_arr <<< "$1"
for addr in "${dns_arr[@]}"; do
valid_ip4 "$addr" || all_valid=1
done
return $all_valid
}
valid_fqdn() {
local fqdn=$1
echo "$fqdn" | grep -qP '(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)' \
&& return 0 \
|| return 1
}
valid_hostname() {
local hostname=$1
[[ $hostname =~ ^[a-zA-Z0-9\-]+$ ]] && [[ $hostname != 'localhost' ]] && return 0 || return 1
}
valid_ip4() {
local ip=$1
echo "$ip" | grep -qP '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' && return 0 || return 1
}
valid_int() {
local num=$1
local min=${2:-1}
local max=${3:-1000}
[[ $num =~ ^[0-9]*$ ]] && [[ $num -ge $min ]] && [[ $num -le $max ]] && return 0 || return 1
}
# {% raw %}
valid_string() {
local str=$1
local min_length=${2:-1}
local max_length=${3:-64}
echo "$str" | grep -qP '^\S+$' && [[ ${#str} -ge $min_length ]] && [[ ${#str} -le $max_length ]] && return 0 || return 1
}
# {% endraw %}
valid_username() {
local user=$1
echo "$user" | grep -qP '^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$' && return 0 || return 1
}
wait_for_web_response() {
url=$1
expected=$2

View File

@@ -0,0 +1,7 @@
#!/bin/bash
. /usr/sbin/so-common
set -e
add_interface_bond0 "$1"

View File

@@ -47,25 +47,25 @@ if ! docker ps | grep -q so-tcpreplay; then
echo "Replay functionality not enabled; attempting to enable now (may require Internet access)..."
echo
if is_manager; then
if is_manager_node; then
TRUSTED_CONTAINERS=("so-tcpreplay")
mkdir -p /opt/so/log/tcpreplay
update_docker_containers "tcpreplay" "" "" "/opt/so/log/tcpreplay/init.log"
fi
if is_sensor; then
if ! is_manager; then
if is_sensor_node; then
if ! is_manager_node; then
echo "Attempting to start replay container. If this fails then you may need to run this command on the manager first."
fi
so-tcpreplay-start || fail "Unable to initialize tcpreplay"
fi
fi
if is_sensor; then
if is_sensor_node; then
echo "Replaying PCAP(s) at ${REPLAYSPEED} Mbps on interface ${REPLAYIFACE}..."
docker exec so-tcpreplay /usr/bin/bash -c "/usr/local/bin/tcpreplay -i ${REPLAYIFACE} -M${REPLAYSPEED} $@"
echo "Replay completed. Warnings shown above are typically expected."
elif is_manager; then
elif is_manager_node; then
echo "The sensor nodes in this grid can now replay traffic."
else
echo "Unable to replay traffic since this node is not a sensor node."

View File

@@ -356,18 +356,14 @@ clear_manager() {
}
collect_soremote_inputs() {
whiptail_create_soremote_user
SCMATCH=no
while [[ $SCMATCH != yes ]]; do
whiptail_create_soremote_user_password1
whiptail_create_soremote_user_password2
check_soremote_pass
done
}
collect_adminuser_inputs() {
whiptail_create_admin_user
while ! valid_username "$ADMINUSER"; do
whiptail_invalid_input
whiptail_create_admin_user
done
APMATCH=no
while [[ $APMATCH != yes ]]; do
whiptail_create_admin_user_password1
@@ -376,8 +372,73 @@ collect_adminuser_inputs() {
done
}
collect_cur_close_days() {
whiptail_cur_close_days
while ! valid_int "$CURCLOSEDAYS" "1"; do
whiptail_invalid_input
whiptail_cur_close_days
done
}
collect_dns() {
whiptail_management_interface_dns
while ! valid_dns_list "$MDNS"; do
whiptail_invalid_input
whiptail_management_interface_dns
done
MDNS=$(echo "$MDNS" | tr -s "," " ") # MDNS needs to be space separated, we prompt for comma separated for consistency
}
collect_dns_domain() {
whiptail_management_interface_dns_search
while ! valid_fqdn "$MSEARCH"; do
whiptail_invalid_input
whiptail_management_interface_dns_search
done
}
collect_dockernet() {
if ! whiptail_dockernet_check; then
whiptail_dockernet_net
while ! valid_ip4 "$DOCKERNET"; do
whiptail_invalid_input
whiptail_dockernet_net
done
fi
}
collect_es_cluster_name() {
if whiptail_manager_adv_escluster; then
whiptail_manager_adv_escluster_name
while ! valid_string "$ESCLUSTERNAME"; do
whiptail_invalid_string "ES cluster name"
whiptail_manager_adv_escluster_name
done
fi
}
collect_es_space_limit() {
whiptail_log_size_limit
while ! valid_int "$log_size_limit" "1"; do # Upper/lower bounds?
whiptail_invalid_input
whiptail_log_size_limit
done
}
collect_fleet_custom_hostname_inputs() {
whiptail_fleet_custom_hostname
while ! valid_fqdn "$FLEETCUSTOMHOSTNAME" || [[ $FLEETCUSTOMHOSTNAME != "" ]]; do
whiptail_invalid_input
whiptail_fleet_custom_hostname
done
}
collect_fleetuser_inputs() {
@@ -404,6 +465,218 @@ collect_fleetuser_inputs() {
done
}
collect_gateway() {
whiptail_management_interface_gateway
while ! valid_ip4 "$MGATEWAY"; do
whiptail_invalid_input
whiptail_management_interface_gateway
done
}
collect_helix_key() {
whiptail_helix_apikey # validate?
}
collect_homenet_mngr() {
whiptail_homenet_manager
while ! valid_cidr_list "$HNMANAGER"; do
whiptail_invalid_input
whiptail_homenet_manager
done
}
collect_homenet_snsr() {
if whiptail_homenet_sensor_inherit; then
export HNSENSOR=inherit
else
whiptail_homenet_sensor
while ! valid_cidr_list "$HNSENSOR"; do
whiptail_invalid_input
whiptail_homenet_sensor
done
fi
}
collect_hostname() {
HOSTNAME=$(cat /etc/hostname)
if [[ "$HOSTNAME" == *'localhost'* ]]; then HOSTNAME=securityonion; fi
whiptail_set_hostname
while ! valid_hostname "$HOSTNAME"; do
whiptail_invalid_hostname
whiptail_set_hostname
done
}
collect_int_ip_mask() {
whiptail_management_interface_ip_mask
while ! valid_cidr "$manager_ip_mask"; do
whiptail_invalid_input
whiptail_management_interface_ip_mask
done
MIP=$(echo "$manager_ip_mask" | sed 's/\/.*//' )
MMASK=$(echo "$manager_ip_mask" | sed 's/.*\///')
}
collect_mngr_hostname() {
whiptail_management_server
while ! valid_hostname "$MSRV"; do
whiptail_invalid_hostname
whiptail_management_server
done
if ! getent hosts "$MSRV"; then
add_manager_hostfile
else
MSRVIP=$(getent hosts "$MSRV" | awk 'NR==1{print $1}')
fi
}
collect_mtu() {
whiptail_bond_nics_mtu
while ! valid_int "$MTU" "68"; do
whiptail_invalid_input
whiptail_bond_nics_mtu
done
}
collect_node_es_heap() {
whiptail_node_es_heap
while ! valid_int "$NODE_ES_HEAP_SIZE"; do
whiptail_invalid_input
whiptail_node_es_heap
done
}
collect_node_ls_heap() {
whiptail_node_ls_heap
while ! valid_int "$NODE_LS_HEAP_SIZE"; do
whiptail_invalid_input
whiptail_node_ls_heap
done
}
collect_node_ls_input() {
whiptail_node_ls_input_threads
while ! valid_int "$LSINPUTTHREADS"; do
whiptail_invalid_input
whiptail_node_ls_input_threads
done
}
collect_node_ls_pipeline_batch_size() {
whiptail_node_ls_pipline_batchsize
while ! valid_int "$LSPIPELINEBATCH"; do
whiptail_invalid_input
whiptail_node_ls_pipline_batchsize
done
}
collect_node_ls_pipeline_worker_count() {
whiptail_node_ls_pipeline_worker
while ! valid_int "$LSPIPELINEWORKERS"; do
whiptail_invalid_input
whiptail_node_ls_pipeline_worker
done
}
collect_oinkcode() {
whiptail_oinkcode
while ! valid_string "$OINKCODE" "" "128"; do #TODO: verify max length here
whiptail_invalid_input
whiptail_oinkcode
done
}
collect_patch_schedule() {
whiptail_patch_schedule
case "$patch_schedule" in
'New Schedule')
whiptail_patch_schedule_select_days
whiptail_patch_schedule_select_hours
collect_patch_schedule_name_new
patch_schedule_os_new
;;
'Import Schedule')
collect_patch_schedule_name_import
;;
'Automatic')
PATCHSCHEDULENAME='auto'
;;
'Manual')
PATCHSCHEDULENAME='manual'
;;
esac
}
collect_patch_schedule_name_new() {
whiptail_patch_name_new_schedule
while ! valid_string "$PATCHSCHEDULENAME"; do
whiptail_invalid_string "schedule name"
whiptail_patch_name_new_schedule
done
}
collect_patch_schedule_name_import() {
whiptail_patch_schedule_import
while ! valid_string "$PATCHSCHEDULENAME"; do
whiptail_invalid_string "schedule name"
whiptail_patch_schedule_import
done
}
collect_redirect_host() {
whiptail_set_redirect_host
while ! valid_ip4 "$REDIRECTHOST" && ! valid_hostname "$REDIRECTHOST" && ! valid_fqdn "$REDIRECTHOST"; do
whiptail_invalid_input
whiptail_set_redirect_host
done
}
collect_so_allow() {
if whiptail_so_allow_yesno; then
whiptail_so_allow
while ! valid_cidr "$ALLOW_CIDR" && ! valid_ip4 "$ALLOW_CIDR"; do
whiptail_invalid_input
whiptail_so_allow
done
fi
}
collect_soremote_inputs() {
whiptail_create_soremote_user
SCMATCH=no
while [[ $SCMATCH != yes ]]; do
whiptail_create_soremote_user_password1
whiptail_create_soremote_user_password2
check_soremote_pass
done
}
collect_suri() {
whiptail_basic_suri
while ! valid_int "$BASICSURI"; do
whiptail_invalid_input
whiptail_basic_suri
done
}
collect_webuser_inputs() {
# Get a password for the web admin user
@@ -421,9 +694,9 @@ collect_webuser_inputs() {
while [[ $WPMATCH != yes ]]; do
whiptail_create_web_user_password1
while ! check_password "$WEBPASSWD1"; do
whiptail_invalid_pass_characters_warning
whiptail_create_web_user_password1
done
whiptail_invalid_pass_characters_warning
whiptail_create_web_user_password1
done
if echo "$WEBPASSWD1" | so-user valpass >> "$setup_log" 2>&1; then
whiptail_create_web_user_password2
check_web_pass
@@ -433,6 +706,15 @@ collect_webuser_inputs() {
done
}
collect_zeek() {
whiptail_basic_zeek
while ! valid_int "$BASICZEEK"; do
whiptail_invalid_input
whiptail_basic_zeek
done
}
configure_minion() {
local minion_type=$1
echo "Configuring minion type as $minion_type" >> "$setup_log" 2>&1
@@ -570,31 +852,22 @@ compare_versions() {
configure_network_sensor() {
echo "Setting up sensor interface" >> "$setup_log" 2>&1
local nic_error=0
# Set the MTU
if [[ $NSMSETUP != 'ADVANCED' ]]; then
if [[ $is_cloud ]]; then MTU=1575; else MTU=1500; fi
fi
if [[ $is_cloud ]]; then
INTERFACE=${BNICS[0]}
local nmcli_con_arg="type ethernet"
local nmcli_con_args=( "type" "ethernet" )
else
INTERFACE='bond0'
local nmcli_con_arg="type bond mode 0"
local nmcli_con_args=( "type" "bond" "mode" "0" )
fi
# Create the bond interface only if it doesn't already exist
nmcli -f name,uuid -p con | grep -q "$INTERFACE" >> "$setup_log" 2>&1
local found_int=$?
if [[ $found_int != 0 ]]; then
nmcli con add ifname "$INTERFACE" con-name "$INTERFACE" $nmcli_con_arg -- \
nmcli con add ifname "$INTERFACE" con-name "$INTERFACE" "${nmcli_con_args[@]}" -- \
ipv4.method disabled \
ipv6.method ignore \
ethernet.mtu $MTU \
ethernet.mtu "$MTU" \
connection.autoconnect "yes" >> "$setup_log" 2>&1
else
local int_uuid
@@ -603,53 +876,17 @@ configure_network_sensor() {
nmcli con mod "$int_uuid" \
ipv4.method disabled \
ipv6.method ignore \
ethernet.mtu $MTU \
ethernet.mtu "$MTU" \
connection.autoconnect "yes" >> "$setup_log" 2>&1
fi
local err=0
for BNIC in "${BNICS[@]}"; do
# Check if specific offload features are able to be disabled
for string in "generic-segmentation-offload" "generic-receive-offload" "tcp-segmentation-offload"; do
if ethtool -k "$BNIC" | grep $string | grep -q "on [fixed]"; then
echo "The hardware or driver for interface ${BNIC} is not supported, packet capture may not work as expected." >> "$setup_log" 2>&1
nic_error=1
break
fi
done
# Turn off various offloading settings for the interface
for i in rx tx sg tso ufo gso gro lro; do
ethtool -K "$BNIC" $i off >> "$setup_log" 2>&1
done
if [[ $is_cloud ]]; then
nmcli con up "$BNIC" >> "$setup_log" 2>&1
else
# Check if the bond slave connection has already been created
nmcli -f name,uuid -p con | grep -q "bond0-slave-$BNIC" >> "$setup_log" 2>&1
local found_int=$?
if [[ $found_int != 0 ]]; then
# Create the slave interface and assign it to the bond
nmcli con add type ethernet ifname "$BNIC" con-name "bond0-slave-$BNIC" master bond0 -- \
ethernet.mtu $MTU \
connection.autoconnect "yes" >> "$setup_log" 2>&1
else
local int_uuid
int_uuid=$(nmcli -f name,uuid -p con | sed -n "s/bond0-slave-$BNIC //p" | tr -d ' ')
nmcli con mod "$int_uuid" \
ethernet.mtu $MTU \
connection.autoconnect "yes" >> "$setup_log" 2>&1
fi
nmcli con up "bond0-slave-$BNIC" >> "$setup_log" 2>&1 # Bring the slave interface up
fi
add_interface_bond0 "$BNIC" --verbose >> "$setup_log" 2>&1
local ret=$?
[[ $ret -eq 0 ]] || err=$ret
done
if [ $nic_error != 0 ]; then
return 1
fi
return $err
}
copy_salt_master_config() {
@@ -974,12 +1211,20 @@ docker_seed_registry() {
download_repo_tarball() {
mkdir -p /root/manager_setup/securityonion
{
local manager_ver
manager_ver=$($sshcmd -i /root/.ssh/so.key soremote@"$MSRV" cat /etc/soversion)
$scpcmd -i /root/.ssh/so.key soremote@"$MSRV":/opt/so/repo/"$manager_ver".tar.gz /root/manager_setup
} >> "$setup_log" 2>&1
mkdir -p /root/manager_setup
local manager_ver
manager_ver=$($sshcmd -i /root/.ssh/so.key soremote@"$MSRV" cat /etc/soversion) >> "$setup_log" 2>&1
# Fail if we can't determine the version
if [[ $manager_ver == '' ]]; then
rm /root/install_opt
local message="Could not determine the version of Security Onion running on the manager, please check your network settings."
echo "$message" | tee -a "$setup_log"
kill -SIGUSR1 "$(ps --pid $$ -oppid=)"; exit
fi
$scpcmd -i /root/.ssh/so.key soremote@"$MSRV":/opt/so/repo/"$manager_ver".tar.gz /root/manager_setup >> "$setup_log" 2>&1
# Fail if the file doesn't download
if ! [ -f /root/manager_setup/"$manager_ver".tar.gz ]; then
@@ -988,7 +1233,8 @@ download_repo_tarball() {
echo "$message" | tee -a "$setup_log"
kill -SIGUSR1 "$(ps --pid $$ -oppid=)"; exit 1
fi
mkdir -p /root/manager_setup/securityonion
{
tar -xzf /root/manager_setup/"$manager_ver".tar.gz -C /root/manager_setup/securityonion
rm -rf /root/manager_setup/"$manager_ver".tar.gz
@@ -1059,10 +1305,26 @@ generate_repo_tarball() {
tar -czf /opt/so/repo/"$SOVERSION".tar.gz ../.
}
generate_sensor_vars() {
# Set the MTU
if [[ $NSMSETUP != 'ADVANCED' ]]; then
if [[ $is_cloud ]]; then MTU=1575; else MTU=1500; fi
fi
export MTU
# Set interface variable
if [[ $is_cloud ]]; then
INTERFACE=${BNICS[0]}
else
INTERFACE='bond0'
fi
export INTERFACE
}
get_redirect() {
whiptail_set_redirect
if [ "$REDIRECTINFO" = "OTHER" ]; then
whiptail_set_redirect_host
collect_redirect_host
fi
}
@@ -1388,22 +1650,21 @@ network_init() {
network_init_whiptail() {
case "$setup_type" in
'iso')
whiptail_set_hostname
collect_hostname
whiptail_management_nic
whiptail_dhcp_or_static
if [ "$address_type" != 'DHCP' ]; then
whiptail_management_interface_ip
whiptail_management_interface_mask
whiptail_management_interface_gateway
whiptail_management_interface_dns
whiptail_management_interface_dns_search
collect_int_ip_mask
collect_gateway
collect_dns
collect_dns_domain
fi
;;
'network')
whiptail_network_notice
whiptail_dhcp_warn
whiptail_set_hostname
collect_hostname
whiptail_management_nic
;;
esac
@@ -2028,6 +2289,7 @@ sensor_pillar() {
if [ "$HNSENSOR" != 'inherit' ]; then
echo " hnsensor: $HNSENSOR" >> "$pillar_file"
fi
}
set_default_log_size() {

View File

@@ -277,10 +277,10 @@ if ! [[ -f $install_opt_file ]]; then
fi
if [[ $is_minion ]]; then
whiptail_management_server
collect_mngr_hostname
fi
if [[ $is_minion ]] || [[ $reinit_networking ]] || ! [[ -f $net_init_file ]]; then
if [[ $is_minion ]] || [[ $reinit_networking ]] || [[ $is_iso ]] && ! [[ -f $net_init_file ]]; then
whiptail_management_interface_setup
fi
@@ -379,6 +379,10 @@ fi
# Start user prompts
if [[ $is_helix ]]; then
collect_helix_key
fi
if [[ $is_helix || $is_sensor ]]; then
whiptail_sensor_nics
fi
@@ -388,10 +392,10 @@ if [[ $is_helix || $is_sensor || $is_import ]]; then
fi
if [[ ! $is_import ]]; then
whiptail_patch_schedule
collect_patch_schedule
fi
whiptail_homenet_manager
collect_homenet_mngr
if [[ $is_helix || $is_manager || $is_node || $is_import ]]; then
set_base_heapsizes
@@ -401,22 +405,22 @@ if [[ $is_manager && ! $is_eval ]]; then
whiptail_manager_adv
if [ "$MANAGERADV" = 'ADVANCED' ]; then
if [ "$install_type" = 'MANAGER' ] || [ "$install_type" = 'MANAGERSEARCH' ]; then
whiptail_manager_adv_escluster
collect_es_cluster_name
fi
fi
whiptail_metadata_tool
if [ "$MANAGERADV" = 'ADVANCED' ] && [ "$ZEEKVERSION" != 'SURICATA' ]; then
whiptail_manager_adv_service_zeeklogs
fi
[[ $MANAGERADV == "ADVANCED" ]] && [[ $ZEEKVERSION == "ZEEK" ]] && whiptail_manager_adv_service_zeeklogs
# Don't run this function for now since Snort is not yet supported
# whiptail_nids
NIDS=Suricata
whiptail_rule_setup
if [ "$RULESETUP" != 'ETOPEN' ]; then
whiptail_oinkcode
collect_oinkcode
fi
fi
if [[ $is_manager ]]; then
@@ -430,7 +434,7 @@ if [[ $is_manager ]]; then
info "Disabling Strelka rules: STRELKA='$STRELKA'"
fi
whiptail_dockernet_check
collect_dockernet
fi
if [[ $is_manager || $is_import ]]; then
@@ -450,28 +454,28 @@ if [[ $is_distmanager ]]; then
fi
if [[ $is_sensor && ! $is_eval ]]; then
whiptail_homenet_sensor
collect_homenet_snsr
whiptail_sensor_config
if [ $NSMSETUP == 'ADVANCED' ]; then
whiptail_zeek_pins
[[ $ZEEKVERSION == "ZEEK" ]] && whiptail_zeek_pins
whiptail_suricata_pins
whiptail_bond_nics_mtu
collect_mtu
else
whiptail_basic_zeek
whiptail_basic_suri
[[ $ZEEKVERSION == "ZEEK" ]] && collect_zeek
collect_suri
fi
fi
if [[ $is_node && ! $is_eval ]]; then
whiptail_node_advanced
if [ "$NODESETUP" == 'NODEADVANCED' ]; then
whiptail_node_es_heap
whiptail_node_ls_heap
whiptail_node_ls_pipeline_worker
whiptail_node_ls_pipline_batchsize
whiptail_node_ls_input_threads
whiptail_cur_close_days
whiptail_log_size_limit
collect_node_es_heap
collect_node_ls_heap
collect_node_ls_pipeline_worker_count
collect_node_ls_pipeline_batch_size
collect_node_ls_input
collect_cur_close_days
collect_es_space_limit
else
NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE
NODE_LS_HEAP_SIZE=$LS_HEAP_SIZE
@@ -490,7 +494,7 @@ else
FLEETNODEPASSWD1=$WEBPASSWD1
fi
if [[ $is_manager || $is_import ]]; then whiptail_so_allow; fi
if [[ $is_manager || $is_import ]]; then collect_so_allow; fi
whiptail_make_changes
@@ -569,19 +573,20 @@ set_redirect >> $setup_log 2>&1
set_progress_str 2 'Updating packages'
update_packages >> $setup_log 2>&1
if [[ $is_sensor || $is_helix ]]; then
set_progress_str 3 'Configuring sensor interface'
configure_network_sensor >> $setup_log 2>&1
fi
if [[ $is_sensor || $is_helix || $is_import ]]; then
set_progress_str 4 'Generating sensor pillar'
set_progress_str 3 'Generating sensor pillar'
generate_sensor_vars
sensor_pillar >> $setup_log 2>&1
if [[ $is_sensor || $is_helix ]]; then
steno_pillar >> $setup_log
fi
fi
if [[ $is_sensor || $is_helix ]]; then
set_progress_str 4 'Configuring sensor interface'
configure_network_sensor >> $setup_log 2>&1
fi
set_progress_str 5 'Installing Salt and dependencies'
saltify 2>> $setup_log

View File

@@ -65,7 +65,6 @@ whiptail_basic_zeek() {
whiptail_check_exitstatus $exitstatus
}
whiptail_bond_nics_mtu() {
[ -n "$TESTING" ] && return
@@ -76,7 +75,6 @@ whiptail_bond_nics_mtu() {
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_cancel() {
@@ -121,6 +119,8 @@ whiptail_create_admin_user() {
ADMINUSER=$(whiptail --title "Security Onion Install" --inputbox \
"Please enter a username for a new system admin user: \nThe local onion account will be disabled during this install" 10 60 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_create_admin_user_password1() {
@@ -244,17 +244,6 @@ whiptail_create_web_user_password2() {
}
whiptail_fleet_custom_hostname() {
[ -n "$TESTING" ] && return
FLEETCUSTOMHOSTNAME=$(whiptail --title "Security Onion Install" --inputbox \
"What FQDN should osquery clients use for connections to this Fleet node? Leave blank if the local system hostname will be used." 10 60 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_requirements_error() {
local requirement_needed=$1
@@ -312,20 +301,6 @@ whiptail_storage_requirements() {
whiptail_check_exitstatus $exitstatus
}
whiptail_invalid_pass_warning() {
[ -n "$TESTING" ] && return
whiptail --title "Security Onion Setup" --msgbox "Please choose a more secure password." 8 75
}
whiptail_invalid_pass_characters_warning() {
[ -n "$TESTING" ] && return
whiptail --title "Security Onion Setup" --msgbox "Password is invalid. Please exclude single quotes, double quotes, dollar signs, and backslashes from the password." 8 75
}
whiptail_cur_close_days() {
[ -n "$TESTING" ] && return
@@ -403,11 +378,6 @@ whiptail_dockernet_check(){
whiptail --title "Security Onion Setup" --yesno \
"Do you want to keep the default Docker IP range? \n \n(Choose yes if you don't know what this means)" 10 75
local exitstatus=$?
if [[ $exitstatus == 1 ]]; then
whiptail_dockernet_net
fi
}
whiptail_dockernet_net() {
@@ -500,37 +470,36 @@ whiptail_helix_apikey() {
}
#TODO: Combine these two functions
whiptail_homenet_manager() {
[ -n "$TESTING" ] && return
HNMANAGER=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your HOME_NET, separating CIDR blocks with a comma (,):" 10 75 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3)
"Enter your home network(s), separating CIDR blocks with a comma (,):" 10 75 "10.0.0.0/8,192.168.0.0/16,172.16.0.0/12" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
export HNMANAGER
}
whiptail_homenet_sensor() {
whiptail_homenet_sensor_inherit() {
[ -n "$TESTING" ] && return
# Ask to inherit from manager
whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the HOME_NET from the Manager?" 8 75
}
whiptail_homenet_sensor() {
[ -n "$TESTING" ] && return
HNSENSOR=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your home network(s), separating CIDR blocks with a comma (,):" 10 75 "10.0.0.0/8,192.168.0.0/16,172.16.0.0/12" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
if [ $exitstatus == 0 ]; then
export HNSENSOR=inherit
else
HNSENSOR=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your HOME_NET, separating CIDR blocks with a comma (,):" 10 75 10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
export HNSENSOR
fi
export HNSENSOR
}
whiptail_install_type() {
@@ -612,6 +581,20 @@ whiptail_install_type_other() {
export install_type
}
whiptail_invalid_input() { # TODO: This should accept a list of arguments to specify what general pattern the input should follow
[ -n "$TESTING" ] && return
whiptail --title "Security Onion Setup" --msgbox " Invalid input, please try again." 7 40
}
whiptail_invalid_string() {
[ -n "$TESTING" ] && return
whiptail --title "Security Onion Setup" --msgbox "Invalid input, please try again.\n\nThe $1 cannot contain spaces." 9 45
}
whiptail_invalid_pass_characters_warning() {
[ -n "$TESTING" ] && return
@@ -633,6 +616,18 @@ whiptail_invalid_user_warning() {
whiptail --title "Security Onion Setup" --msgbox "Please enter a valid email address." 8 75
}
whiptail_invalid_hostname() {
[ -n "$TESTING" ] && return
local error_message
error_message=$(echo "Please choose a valid hostname. It cannot be localhost; and must contain only \
the ASCII letters 'A-Z' and 'a-z' (case-sensitive), the digits '0' through '9', \
and hyphen ('-')" | tr -d '\t')
whiptail --title "Security Onion Setup" \
--msgbox "$error_message" 10 75
}
whiptail_log_size_limit() {
[ -n "$TESTING" ] && return
@@ -651,8 +646,8 @@ whiptail_first_menu_iso() {
[ -n "$TESTING" ] && return
option=$(whiptail --title "Security Onion Setup" --menu "Select an option" 10 75 2 \
"Security Onion Installer" "Run the standard Security Onion installation " \
"Configure Network" "Configure networking only " \
"Install " "Run the standard Security Onion installation " \
"Configure Network " "Configure networking only " \
3>&1 1>&2 2>&3
)
local exitstatus=$?
@@ -674,10 +669,11 @@ whiptail_management_interface_dns() {
[ -n "$TESTING" ] && return
MDNS=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your DNS servers separated by a space:" 10 60 8.8.8.8 8.8.4.4 3>&1 1>&2 2>&3)
"Enter your DNS servers separated by commas:" 10 60 "8.8.8.8,8.8.4.4" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_management_interface_dns_search() {
@@ -696,7 +692,17 @@ whiptail_management_interface_gateway() {
[ -n "$TESTING" ] && return
MGATEWAY=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your gateway:" 10 60 X.X.X.X 3>&1 1>&2 2>&3)
"Enter your gateway's IPv4 address:" 10 60 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_management_interface_ip_mask() {
[ -n "$TESTING" ] && return
manager_ip_mask=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your IPv4 address with CIDR mask (e.g. 192.168.1.2/24):" 10 60 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
@@ -791,7 +797,6 @@ whiptail_net_setup_complete() {
exit 0
}
whiptail_management_server() {
[ -n "$TESTING" ] && return
@@ -802,28 +807,6 @@ whiptail_management_server() {
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
while [[ $MSRV == *'localhost'* || ! ( $MSRV =~ ^[a-zA-Z0-9\-]*$ ) ]] ; do
local error_message
error_message=$(echo "Please choose a valid hostname. It cannot contain localhost; and must contain only \
the ASCII letters 'A-Z' and 'a-z' (case-sensitive), the digits '0' through '9', \
and hyphen ('-')" | tr -d '\t')
whiptail --title "Security Onion Setup" \
--msgbox "$error_message" 10 75
MSRV=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter your Manager Server hostname. It is CASE SENSITIVE!" 10 75 XXXX 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
done
if ! getent hosts "$MSRV"; then
add_manager_hostfile
else
MSRVIP=$(getent hosts "$MSRV" | awk 'NR==1{print $1}')
fi
}
# Ask if you want to do advanced setup of the Manager
@@ -849,11 +832,6 @@ whiptail_manager_adv_escluster(){
whiptail --title "Security Onion Setup" --yesno \
"Do you want to set up a traditional ES cluster for using replicas and/or Hot-Warm indices? Recommended only for those who have experience with ES clustering! " 12 75
local exitstatus=$?
if [[ $exitstatus == 0 ]]; then
whiptail_manager_adv_escluster_name
fi
}
# Get a cluster name
@@ -957,13 +935,13 @@ whiptail_metadata_tool() {
[ -n "$TESTING" ] && return
# Legacy variable naming
ZEEKVERSION=$(whiptail --title "Security Onion Setup" --radiolist "What tool would you like to use to generate metadata?" 20 75 4 \
"ZEEK" "Zeek (formerly known as Bro)" ON \
"SURICATA" "Suricata" OFF 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_nids() {
@@ -1016,7 +994,7 @@ whiptail_node_es_heap() {
[ -n "$TESTING" ] && return
NODE_ES_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter ES Heap Size: \n \n(Recommended value is pre-populated)" 10 75 $ES_HEAP_SIZE 3>&1 1>&2 2>&3)
"\nEnter ES heap size: \n \n(Recommended value is pre-populated)" 10 75 $ES_HEAP_SIZE 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
@@ -1028,19 +1006,7 @@ whiptail_node_ls_heap() {
[ -n "$TESTING" ] && return
NODE_LS_HEAP_SIZE=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter LogStash Heap Size: \n \n(Recommended value is pre-populated)" 10 75 $LS_HEAP_SIZE 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_node_ls_pipeline_worker() {
[ -n "$TESTING" ] && return
LSPIPELINEWORKERS=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter LogStash Pipeline Workers: \n \n(Recommended value is pre-populated)" 10 75 "$num_cpu_cores" 3>&1 1>&2 2>&3)
"\nEnter Logstash heap size: \n \n(Recommended value is pre-populated)" 10 75 $LS_HEAP_SIZE 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
@@ -1052,7 +1018,19 @@ whiptail_node_ls_pipline_batchsize() {
[ -n "$TESTING" ] && return
LSPIPELINEBATCH=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter LogStash Pipeline Batch Size: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3)
"\nEnter Logstash pipeline batch size: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
whiptail_node_ls_pipeline_worker() {
[ -n "$TESTING" ] && return
LSPIPELINEWORKERS=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter number of Logstash pipeline workers: \n \n(Recommended value is pre-populated)" 10 75 "$num_cpu_cores" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
@@ -1064,7 +1042,7 @@ whiptail_node_ls_input_threads() {
[ -n "$TESTING" ] && return
LSINPUTTHREADS=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter LogStash Input Threads: \n \n(Default value is pre-populated)" 10 75 1 3>&1 1>&2 2>&3)
"\nEnter number of Logstash input threads: \n \n(Default value is pre-populated)" 10 75 1 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
@@ -1101,53 +1079,21 @@ whiptail_patch_name_new_schedule() {
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
while [[ -z "$PATCHSCHEDULENAME" ]]; do
whiptail --title "Security Onion Setup" --msgbox "Please enter a name for this OS patch schedule." 8 75
PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \
"What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the manager under /opt/so/salt/patch/os/schedules/<schedulename>.yml" 10 75 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
done
}
whiptail_patch_schedule() {
[ -n "$TESTING" ] && return
local patch_schedule
patch_schedule=$(whiptail --title "Security Onion Setup" --radiolist \
"Choose OS patch schedule: \nThis will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 15 75 5 \
"Automatic" "Updates installed every 8 hours if available" ON \
"Manual" "Updates will be installed manually" OFF \
"Import Schedule" "Import named schedule on following screen" OFF \
"New Schedule" "Configure and name new schedule on next screen" OFF 3>&1 1>&2 2>&3 )
"Choose OS patch schedule: \nThis will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 15 75 5 \
"Automatic" "Updates installed every 8 hours if available" ON \
"Manual" "Updates will be installed manually" OFF \
"Import Schedule" "Import named schedule on following screen" OFF \
"New Schedule" "Configure and name new schedule on next screen" OFF 3>&1 1>&2 2>&3 )
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
case $patch_schedule in
'New Schedule')
whiptail_patch_schedule_select_days
whiptail_patch_schedule_select_hours
whiptail_patch_name_new_schedule
patch_schedule_os_new
;;
'Import Schedule')
whiptail_patch_schedule_import
;;
'Automatic')
PATCHSCHEDULENAME='auto'
;;
'Manual')
PATCHSCHEDULENAME='manual'
;;
esac
}
whiptail_patch_schedule_import() {
@@ -1327,32 +1273,11 @@ whiptail_set_hostname() {
[ -n "$TESTING" ] && return
HOSTNAME=$(cat /etc/hostname)
if [[ "$HOSTNAME" == *'localhost'* ]]; then HOSTNAME=securityonion; fi
HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter the hostname (not FQDN) you would like to set:" 10 75 "$HOSTNAME" 3>&1 1>&2 2>&3)
"Enter the hostname (not FQDN) you would like to set:" 10 75 "$HOSTNAME" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
while [[ $HOSTNAME == *'localhost'* || ! ( $HOSTNAME =~ ^[a-zA-Z0-9\-]*$ ) ]] ; do
local error_message
error_message=$(echo "Please choose a valid hostname. It cannot contain localhost; and must contain only \
the ASCII letters 'a' through 'z' (case-insensitive), the digits '0' through '9', \
and hyphen ('-')" | tr -d '\t')
whiptail --title "Security Onion Setup" \
--msgbox "$error_message" 10 75
HOSTNAME=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter the hostname (not FQDN) you would like to set:" 10 75 "$HOSTNAME" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
done
}
whiptail_set_redirect() {
@@ -1373,7 +1298,7 @@ whiptail_set_redirect_host() {
[ -n "$TESTING" ] && return
REDIRECTHOST=$(whiptail --title "Security Onion Setup" --inputbox \
"Enter the Hostname or IP you would like to use for the web interface:" 10 75 "$HOSTNAME" 3>&1 1>&2 2>&3)
"Enter the Hostname, IP, or FQDN you would like to use for the web interface:" 10 75 "$HOSTNAME" 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
}
@@ -1423,37 +1348,25 @@ whiptail_setup_failed() {
whiptail --title "Security Onion Setup" --msgbox "$message" $height 75
}
whiptail_shard_count() {
whiptail_so_allow_yesno() {
[ -n "$TESTING" ] && return
SHARDCOUNT=$(whiptail --title "Security Onion Setup" --inputbox \
"\nEnter ES Shard Count: \n \n(Default value is pre-populated)" 10 75 125 3>&1 1>&2 2>&3)
local exitstatus=$?
whiptail_check_exitstatus $exitstatus
whiptail --title "Security Onion Setup" \
--yesno "Do you want to run so-allow to allow access to the web tools?" \
8 75
}
whiptail_so_allow() {
[ -n "$TESTING" ] && return
whiptail --title "Security Onion Setup" \
--yesno "Do you want to run so-allow to allow access to the web tools?" \
8 75
local exitstatus=$?
if [[ $exitstatus == 0 ]]; then
ALLOW_CIDR=$(whiptail --title "Security Onion Setup" \
ALLOW_CIDR=$(whiptail --title "Security Onion Setup" \
--inputbox "Enter a single IP address or an IP range, in CIDR notation, to allow:" \
10 75 3>&1 1>&2 2>&3)
local exitstatus=$?
export ALLOW_ROLE='a'
export ALLOW_CIDR
fi
local exitstatus=$?
export ALLOW_ROLE='a'
export ALLOW_CIDR
}
whiptail_storage_requirements() {

187
tests/validation.sh Normal file
View File

@@ -0,0 +1,187 @@
#!/bin/bash
. ../salt/common/tools/sbin/so-common
script_ret=0
GREEN="\e[1;32m"
RED="\e[1;31m"
RESET="\e[0m"
test_fun() {
local expected_result=$1
shift
local fun=$1
shift
$fun "$@"
local ret=$?
[[ $ret -eq 0 ]] && res="O" || res="X"
[[ $ret -ne $expected_result ]] && script_ret=1
local prefix=$1
[[ -n $2 ]] && prefix="$prefix, min=$2"
[[ -n $3 ]] && prefix="$prefix, max=$3"
[[ $prefix == "" ]] && prefix="[EMPTY]"
[[ $ret -eq $expected_result ]] \
&& printf "${GREEN}%b${RESET}" " $res" \
|| printf "${RED}%b${RESET}" " $res"
printf "%s\n" " - $prefix"
}
header "FQDN"
test_fun 0 valid_fqdn "rwwiv.com"
test_fun 0 valid_fqdn "ddns.rwwiv.com"
test_fun 1 valid_fqdn ".com"
test_fun 1 valid_fqdn "rwwiv."
test_fun 1 valid_fqdn ""
sleep 0.15s
header "ip4"
test_fun 0 valid_ip4 "192.168.1.1"
test_fun 0 valid_ip4 "192.168.1.255"
test_fun 1 valid_ip4 "192.168.1.256"
test_fun 1 valid_ip4 "192.168..1"
test_fun 1 valid_ip4 "192.168.1.1."
test_fun 1 valid_ip4 ""
sleep 0.15s
header "CIDR (ipv4)"
test_fun 0 valid_cidr "192.168.1.0/24"
test_fun 0 valid_cidr "192.168.1.0/12"
test_fun 1 valid_cidr "192.168.1.0"
test_fun 1 valid_ip4 "192.168.1.0/"
test_fun 1 valid_ip4 "/24"
test_fun 1 valid_cidr ""
sleep 0.15s
header "CIDR list"
test_fun 0 valid_cidr_list "10.0.0.0/8,192.168.0.0/16,172.16.0.0/12"
test_fun 0 valid_cidr_list "10.0.0.0/8"
test_fun 1 valid_cidr_list "10.0.0.0/8,192.168.0.0/16172.16.0.0/12"
test_fun 1 valid_cidr_list "10.0.0.0"
sleep 0.15s
header "DNS"
test_fun 0 valid_dns_list "8.8.8.8,8.8.4.4"
test_fun 0 valid_dns_list "8.8.8.8"
test_fun 1 valid_dns_list "8.8.8.8 8.8.4.4"
test_fun 1 valid_dns_list "8.8.8.,8.8.4.4"
test_fun 1 valid_dns_list "192.168.9."
sleep 0.15s
header "int (default min: 1, default max: 1000)"
test_fun 0 valid_int "24"
test_fun 0 valid_int "1"
test_fun 0 valid_int "2" "2"
test_fun 0 valid_int "1000"
test_fun 1 valid_int "10001"
test_fun 1 valid_int "24" "" "20"
test_fun 1 valid_int "-1"
test_fun 1 valid_int "1" "2"
test_fun 1 valid_int "257" "" "256"
test_fun 1 valid_int "not_a_num"
test_fun 1 valid_int ""
sleep 0.15s
header "hostname"
test_fun 0 valid_hostname "so-sensor01"
test_fun 0 valid_hostname "so"
test_fun 1 valid_hostname "so_sensor01"
test_fun 1 valid_hostname "so.sensor01"
test_fun 1 valid_hostname "localhost"
test_fun 1 valid_hostname ""
sleep 0.15s
header "string (default min_length: 1, default max_length: 64)"
test_fun 0 valid_string "string"
test_fun 0 valid_string "s"
test_fun 0 valid_string "very_long_string_64_sdhkjashasdfkajjagskfjhgkslfkjhlaskfhlaskjhf"
test_fun 0 valid_string "12"
test_fun 1 valid_string "string with spaces"
test_fun 1 valid_string "very_long_string_<64_sdhflkjashasdfkajshfgkjsahgfkjagskfjhgkslfkjhlaskfhlaskjhf"
test_fun 1 valid_string "too_short" "12"
test_fun 1 valid_string "too_long" "" "4"
test_fun 1 valid_string ""
sleep 0.15s
header "Linux user"
test_fun 0 valid_username "so_user_01"
test_fun 0 valid_username "onionuser"
test_fun 1 valid_username "12fa"
test_fun 1 valid_username "so.user.01"
test_fun 1 valid_username "very_long_username_asdflashfsafasdfasdfkahsgkjahfdkjhsg"
echo
exit $script_ret