#!/bin/bash . /usr/src/k_framework/main.sh . /usr/src/m2/framework/bash_functions.sh # Author: Nerijus / Ricardas # Company: Kolmisoft # Year: 2015 # About: Script creates IPs whitelist by using IPs of Connection Points (Originators and Terminators) configured on M2. # It works by adding "M2-CONNECT-POINTS-WHITELIST" chain to iptables and listing allowed IPs there. SCRIPT_NAME="Connection Points Whitelist" VERSION="1.2.5" k_config_details k_iptables_locking_option # Configuration whitelist_ip_chain="M2-CONNECT-POINTS-WHITELIST" gui_whitelist_ip_chain="M2-WHITELIST-GUI" static_whitelisted_ips="127.0.0.1" m2_whitelist_rtpengine_check_disabled=$(sed 's/ //g' /etc/m2/system.conf | awk -F"=" '/m2_whitelist_rtpengine_check_disabled/{print $2}') if [[ -z $m2_whitelist_rtpengine_check_disabled ]]; then m2_whitelist_rtpengine_check_disabled=0 fi # Temporary files mkdir -p /tmp/gui_iptables db_whitelisted_ips=/tmp/gui_iptables/db_whitelisted_ips.txt db_whitelisted_subnet_ips=/tmp/gui_iptables/db_whitelisted_subnet_ips.txt iptables_whitelist_output=/tmp/gui_iptables/iptables_whitelist_output.txt iptables_whitelisted_ips=/tmp/gui_iptables/iptables_whitelisted_ips.txt whitelisted_ips_diff=/tmp/gui_iptables/whitelisted_ips_diff.txt whitelisted_ips_to_insert=/tmp/gui_iptables/whitelisted_ips_to_insert.txt whitelisted_ips_to_delete=/tmp/gui_iptables/whitelisted_ips_to_delete.txt whitelisted_ips_iptables_result=/tmp/gui_iptables/m4_ipauth_whitelist.txt mysql() { MYSQL_PWD="$DB_PASSWORD" /usr/bin/mysql -h "$DB_HOST" -u "$DB_USERNAME" $P_OPT "$DB_NAME" "$@" } text_blue() { echo -e "\033[0;34m$1\033[0m" } text_green() { echo -e "\033[0;32m$1\033[0m" } iptables_add_whitelisted_ip() { ip=$1 report "Adding IP $(text_green "$ip") to iptables whitelist chain $(text_blue $whitelist_ip_chain)" 3 if echo "$ip" | grep -Fq '-'; then ip_range=$(echo "$ip" | perl -ne '/(\d+\.\d+.\d+)(\.\d+)-(\d+)/ && print "$1$2-$1.$3\n"') /sbin/iptables $l_opt -I "$whitelist_ip_chain" -m iprange --src-range "$ip_range" -j ACCEPT else /sbin/iptables $l_opt -I "$whitelist_ip_chain" -s "$ip" -j ACCEPT fi } iptables_delete_whitelisted_ip() { ip=$1 report "Removing IP $(text_green $ip) from iptables whitelist chain $(text_blue $whitelist_ip_chain)" 3 if echo "$ip" | grep -Fq '-'; then ip_range=$(echo "$ip" | perl -ne '/(\d+\.\d+.\d+)(\.\d+)-(\d+)/ && print "$1$2-$1.$3\n"') /sbin/iptables $l_opt -D "$whitelist_ip_chain" -m iprange --src-range "$ip_range" -j ACCEPT else /sbin/iptables $l_opt -D "$whitelist_ip_chain" -s "$ip" -j ACCEPT fi } fix_whitelist_chain_priority() { # In media servers, whitelist priority should be 2 (after RTPENGINE) # in all other servers whitelist priority should be 1 if [ "$MEDIA_PRESENT" == "1" ] && ((m2_whitelist_rtpengine_check_disabled != 1)); then whitelist_chain_priority=2 else whitelist_chain_priority=1 fi # fail2ban moves its chains to the top of INPUT chain. Make sure that whitelist chain is above fail2ban chains. CHAIN_PRIORITY=$(/sbin/iptables $l_opt -nL INPUT --line-numbers | grep "$whitelist_ip_chain" | grep -v "Chain" | head -n 1 | awk '{print $1}') if [[ "${PIPESTATUS[0]}" -ne "0" || -z $CHAIN_PRIORITY ]]; then report "Failed to querry iptables for $whitelist_ip_chain chain priority" 1 exit 1 fi if [ "$CHAIN_PRIORITY" == "$whitelist_chain_priority" ]; then # Chain priority is OK return 0 elif [ "$CHAIN_PRIORITY" -gt "0" ] && [ "$CHAIN_PRIORITY" -lt "999" ] ; then # Let's fix chain priority report "Fixing chain $(text_blue $whitelist_ip_chain) priority (was $CHAIN_PRIORITY, should be $whitelist_chain_priority)" 2 /sbin/iptables $l_opt -D INPUT -j "$whitelist_ip_chain" /sbin/iptables $l_opt -I INPUT $whitelist_chain_priority -j "$whitelist_ip_chain" else report "Failed to determine $whitelist_ip_chain chain priority" 1 exit 1 fi } fix_gui_whitelist_chain_priority() { # M2-WHITELIST-GUI chain should always be below M2-CONNECT-POINTS-WHITELIST # Check which priority has chain M2-CONNECT-POINTS-WHITELIST whitelist_chain_conn_points_priority=$(/sbin/iptables $l_opt -L -n --line-numbers | grep $whitelist_ip_chain | grep -v "Chain" | head -n 1 | awk '{print $1}') # Check which priority has chain M2-WHITELIST-GUI whitelist_chain_gui_priority=$(/sbin/iptables $l_opt -L -n --line-numbers | grep $gui_whitelist_ip_chain | grep -v "Chain" | head -n 1 | awk '{print $1}') # If we both chains are added to input and we got their priorities, check if order is correct if [[ $whitelist_chain_conn_points_priority =~ ^[0-9]+$ ]]; then # Check if GUI IP whitelist chain priority is lower than connection points whitelist chain priority (by 1) expected_gui_chain_priprity=$(( whitelist_chain_conn_points_priority + 1 )) if [ "$whitelist_chain_gui_priority" != "$expected_gui_chain_priprity" ]; then report "Changing chain [$gui_whitelist_ip_chain] priority from [$whitelist_chain_gui_priority] to [$expected_gui_chain_priprity]" 3 /sbin/iptables $l_opt -D INPUT -j $gui_whitelist_ip_chain /sbin/iptables $l_opt -I INPUT $expected_gui_chain_priprity -j $gui_whitelist_ip_chain else # report "Chain [$whitelist_chain_gui] priority [$whitelist_chain_gui_priority] is ok" 0 : fi else # Something is wrong... just set GUI IP whitelist chain priority to 1 report "Failed to determine priority for chain [$whitelist_ip_chain], got priority [$whitelist_chain_conn_points_priority]" 1 if [ "$whitelist_chain_gui_priority" != "1" ]; then report "Priority for chain [$gui_whitelist_ip_chain] will be set to 1" 2 /sbin/iptables $l_opt -D INPUT -j $gui_whitelist_ip_chain /sbin/iptables $l_opt -I INPUT 1 -j $gui_whitelist_ip_chain fi fi } fix_rtpengine_chain_priority() { # Fix duplicate RTPENGINE rules duplicate_rtpengine_rule_count=$(/sbin/iptables $l_opt -nL INPUT | grep -c 'RTPENGINE') if [[ "$duplicate_rtpengine_rule_count" -gt "1" ]]; then duplicate_rtpengine_rule=$(/sbin/iptables $l_opt -nL INPUT --line-numbers | grep 'RTPENGINE' | grep -v '^1 ' | grep -Po '^\d+' | head -n 1) if [[ "$duplicate_rtpengine_rule" -gt "1" ]] && [[ "$duplicate_rtpengine_rule" -lt "999" ]]; then report "Duplicate RTPENGINE rule found in INPUT at index [$duplicate_rtpengine_rule], removing..." 2 /sbin/iptables $l_opt -D INPUT "$duplicate_rtpengine_rule" fi fi CHAIN_PRIORITY=$(/sbin/iptables $l_opt -nL INPUT --line-numbers | grep "RTPENGINE" | grep -v "Chain" | head -n 1 | awk '{print $1}') if [[ "${PIPESTATUS[0]}" -ne "0" || -z $CHAIN_PRIORITY ]]; then report "Failed to querry iptables for RTPENGINE chain priority" 1 report "Adding new RTPENGINE chain to INPUT" 3 /sbin/iptables $l_opt -D INPUT 1 -p udp -j RTPENGINE --id 8 &> /dev/null /sbin/iptables $l_opt -I INPUT 1 -p udp -j RTPENGINE --id 8 return 0 fi if [ "$CHAIN_PRIORITY" == "1" ]; then # Chain priority is OK return 0 elif [ "$CHAIN_PRIORITY" -gt "0" ] && [ "$CHAIN_PRIORITY" -lt "999" ] ; then # Let's fix chain priority report "Fixing chain $(text_blue RTPENGINE) priority (was $CHAIN_PRIORITY, should be 1)" 2 /sbin/iptables $l_opt -D INPUT 1 -p udp -j RTPENGINE --id 8 &> /dev/null /sbin/iptables $l_opt -I INPUT 1 -p udp -j RTPENGINE --id 8 else report "Failed to determine RTPENGINE chain priority" 1 report "Adding new RTPENGINE chain to INPUT" 3 /sbin/iptables $l_opt -D INPUT 1 -p udp -j RTPENGINE --id 8 &> /dev/null /sbin/iptables $l_opt -I INPUT 1 -p udp -j RTPENGINE --id 8 return 0 fi } fix_whitelist_return() { if ! grep -q "RETURN" $iptables_whitelist_output; then report "RETURN not found in $(text_blue $whitelist_ip_chain), fixing it" 2 /sbin/iptables $l_opt -A "$whitelist_ip_chain" -j RETURN fi } # Stop the script if another instance is running if grep -qEi 'debian' /etc/*release; then # Debian if [[ "$(/usr/bin/pgrep "$(basename "$0")")" ]]; then report "$(basename "$0") script is already running with PID $(/sbin/pidof -x "$(basename "$0")" -o %PPID)" 1 exit 1 fi else # Centos if [[ "$(/sbin/pidof -x "$(basename "$0")" -o %PPID)" ]]; then report "$(basename "$0") script is already running with PID $(/sbin/pidof -x "$(basename "$0")" -o %PPID)" 1 exit 1 fi fi k_start # Remove old tmp files rm -fr $db_whitelisted_ips &> /dev/null rm -fr $iptables_whitelisted_ips &> /dev/null rm -fr $db_whitelisted_subnet_ips &> /dev/null rm -fr $whitelisted_ips_diff &> /dev/null rm -fr $whitelisted_ips_to_insert &> /dev/null rm -fr $whitelisted_ips_to_delete &> /dev/null rm -fr $iptables_whitelist_output &> /dev/null # Check if whitelist is not disabled m2_connection_points_whitelist=$(sed 's/ //g' /etc/m2/system.conf | awk -F"=" '/m2_connection_points_whitelist/{print $2}') if [ -n "$m2_connection_points_whitelist" ] && [ "$m2_connection_points_whitelist" == "0" ]; then exit 0 fi report "Date: $(date)" 3 # Make sure that we can access database if ! m2_mysql_connect; then report "No DB access" 1 exit 1 fi # Create whitelist chain if it does not exist if ! /sbin/iptables $l_opt -L -n | grep -Fq "Chain $whitelist_ip_chain" &> /dev/null; then report "Whitelist chain $(text_blue $whitelist_ip_chain) not found in iptables, creating new chain" 2 /sbin/iptables $l_opt -N "$whitelist_ip_chain" fi # Whitelist chain might be created but not added to INPUT chain, lets check and correct that if ! /sbin/iptables $l_opt -L INPUT -n | grep -Fq "$whitelist_ip_chain" &> /dev/null; then report "Whitelist chain $(text_blue $whitelist_ip_chain) is not added to INPUT chain, add chain $(text_blue $whitelist_ip_chain) to INPUT chain" 2 if [ "$MEDIA_PRESENT" == "1" ]; then /sbin/iptables $l_opt -I INPUT 2 -j "$whitelist_ip_chain" else /sbin/iptables $l_opt -I INPUT 1 -j "$whitelist_ip_chain" fi fi # Get iptables whitelist output and use it in this script instead of running multiple iptables commands /sbin/iptables $l_opt -nL "$whitelist_ip_chain" > $iptables_whitelist_output if [ ! -s $iptables_whitelist_output ]; then report "Failed to retrieve iptables output, exiting..." 1 exit 1 fi # Make sure that RTPENGINE is first in INPUT chain if [ "$MEDIA_PRESENT" == "1" ]; then if ((m2_whitelist_rtpengine_check_disabled != 1)); then fix_rtpengine_chain_priority fi fi # Make sure that there is RETURN at the end of whitelist chain fix_whitelist_return # Make sure that whitelist chain is above fail2ban chain fix_whitelist_chain_priority # Make sure that GUI whitelist chain is above connection points whitelist chain fix_gui_whitelist_chain_priority # Get whitelisted IPs from DB mysql --disable-column-names -e 'SELECT DISTINCT host FROM devices WHERE host NOT IN ("0.0.0.0", "dynamic", "127.0.0.1") AND LENGTH(host) > 1 UNION (SELECT value FROM conflines WHERE name = "M2_proxy_host" AND LENGTH(value) > 1 LIMIT 1) UNION SELECT DISTINCT server_ip FROM servers WHERE server_ip NOT IN ("0.0.0.0", "dynamic", "127.0.0.1") AND LENGTH(server_ip) > 1' > $db_whitelisted_ips # Get whitelisted IPs from iptables (without IP range) grep -v "source IP range" $iptables_whitelist_output | grep -e "ACCEPT" | awk -F" " '{print $4}' > $iptables_whitelisted_ips # Get whitelisted IPs from iptables (with IP range) grep "source IP range" $iptables_whitelist_output | grep -e "ACCEPT" | awk -F" " '{print $9}' | perl -ne '/(\d+\.\d+.\d+\.\d+)-(\d+\.\d+.\d+\.)(\d+)/ && print "$1-$3\n"' >> $iptables_whitelisted_ips # Fix network address for IPs with subnet grep -F "/" $db_whitelisted_ips > $db_whitelisted_subnet_ips while IFS= read -r ip; do if echo "$ip" | grep -F '/' &> /dev/null; then network_address=$(ipcalc -n "$ip" | awk -F'=' '{print $2}') cidr=$(echo "$ip" | grep -Po "\/\d+") sed -i "s|$ip|${network_address}${cidr}|" $db_whitelisted_ips fi done < $db_whitelisted_subnet_ips # Add static whitelisted IPs for ip in $static_whitelisted_ips; do echo "$ip" >> $db_whitelisted_ips done # Sort IPs sort -o $db_whitelisted_ips $db_whitelisted_ips sort -o $iptables_whitelisted_ips $iptables_whitelisted_ips # Find differences diff $iptables_whitelisted_ips $db_whitelisted_ips > $whitelisted_ips_diff grep "^<" $whitelisted_ips_diff > $whitelisted_ips_to_delete grep "^>" $whitelisted_ips_diff > $whitelisted_ips_to_insert # Remove diff annotation sed -i 's|^< ||g' $whitelisted_ips_to_delete sed -i 's|^> ||g' $whitelisted_ips_to_insert # Add IPs to whitelist while IFS= read -r ip; do iptables_add_whitelisted_ip "$ip" done < $whitelisted_ips_to_insert # Delete IPs from whitelist while IFS= read -r ip; do iptables_delete_whitelisted_ip "$ip" done < $whitelisted_ips_to_delete if [ -s $whitelisted_ips_to_insert ] || [ -s $whitelisted_ips_to_delete ]; then report "iptables updated" 3 # Save iptables to file which will be used to display whitelisted connection points in GUI /sbin/iptables-save | grep -F "$whitelist_ip_chain" | grep -Fv '127.0.0.1' | grep ACCEPT | perl -ne '/(\d+\.\d+\.\d+\.\d+)(\/\d\d)?(?:(-)\d+\.\d+\.\d+\.(\d+))?/ && print "$1$2$3$4\n"' > $whitelisted_ips_iptables_result else report "iptables are up to date" 0 fi report "Script finished" 0