diff --git a/salt/common/files/log-rotate.conf b/salt/common/files/log-rotate.conf index 8f1df0307..f8a16a038 100644 --- a/salt/common/files/log-rotate.conf +++ b/salt/common/files/log-rotate.conf @@ -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) }} } diff --git a/salt/common/tools/sbin/so-common b/salt/common/tools/sbin/so-common index 881be83ca..d73ec18f2 100755 --- a/salt/common/tools/sbin/so-common +++ b/salt/common/tools/sbin/so-common @@ -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 diff --git a/salt/common/tools/sbin/so-monitor-add b/salt/common/tools/sbin/so-monitor-add new file mode 100644 index 000000000..7eb100ee8 --- /dev/null +++ b/salt/common/tools/sbin/so-monitor-add @@ -0,0 +1,7 @@ +#!/bin/bash + +. /usr/sbin/so-common + +set -e + +add_interface_bond0 "$1" diff --git a/salt/common/tools/sbin/so-tcpreplay b/salt/common/tools/sbin/so-tcpreplay index e8e24a474..22722ac9b 100755 --- a/salt/common/tools/sbin/so-tcpreplay +++ b/salt/common/tools/sbin/so-tcpreplay @@ -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." diff --git a/setup/so-functions b/setup/so-functions index e731da3b9..83a3ec7fd 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -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() { diff --git a/setup/so-setup b/setup/so-setup index 2cee0dc6a..91103d21a 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -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 diff --git a/setup/so-whiptail b/setup/so-whiptail index 7bbc12042..20627f13f 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -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/.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() { diff --git a/tests/validation.sh b/tests/validation.sh new file mode 100644 index 000000000..d16c8bbb9 --- /dev/null +++ b/tests/validation.sh @@ -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