Files
firewall_containers/firewall/firewall-add
gyurix 4631bccf6c
All checks were successful
continuous-integration/drone/push Build is passing
refactor iptables handling for improved compatibility across operating systems
2025-03-05 18:26:14 +01:00

496 lines
17 KiB
Bash
Executable File

#!/bin/sh
# Debugging function
debug() {
if [ $DEBUG -eq 1 ]; then
echo $(date)" DEBUG: "$1 $2 $3
else
echo $(date)" DEBUG: "$1 $2 $3 >>/var/log/iptables.log
fi
}
# Task type variables
DEBUG=0
ROUTE=$ROUTE
HOST=$HOST
PREROUTING=$PREROUTING
POSTROUTING=$POSTROUTING
# Mandatory task variables
CHAIN=$CHAIN
NAME=$NAME
COMMENT="$COMMENT"
NAME="$NAME-$COMMENT"
PROTOCOL=$TYPE
OPERATION=$OPERATION
EXTRA_OPTIONS="$2 $3 $4"
set | grep SOURCE
set | grep TARGET
set | grep ROLES
SERVICE_FILES=$SERVICE_FILES
HOST_FILE=$HOST_FILE
if [ "$HOST_FILE" == "" ]; then
HOST_FILE="/etc/dns/hosts.local"
fi
RETRIES_NUMBER=$RETRIES_NUMBER
if [ -z "$RETRIES_NUMBER" ]; then
RETRIES_NUMBER=2
fi
# turn on debug mode by extra option "debug"
if [[ "$(echo "$EXTRA_OPTIONS" | grep debug)" != "" ]]; then
DEBUG=1
fi
# finding IPv4 addresses from application names.
name_resolver() {
local DNS_IP
local DNS=$1
APP_IP=""
UP_COUNT=0
SRV_COUNT=0
echo "DNS: "$DNS
for D in $(echo $DNS); do
if [ -z "$STRICK_CHECK" ]; then
# find $D as SELECTOR in hosts file
EXISTS=$(grep -w $D $HOST_FILE)
#EXISTS=$(grep -w "$D-" $HOST_FILE); # TODO?
if [ -n "$EXISTS" ]; then # selector exists in hosts file
# remove all matching selectors and all selctors followed by "-"
#APP_IP=$(echo $EXISTS | sed s/$D-.//g | sed s/$D//g);
APP_IP=$(echo "$EXISTS" | awk '{print $1}')
debug "APP_IP: "$APP_IP
else
debug "no matching APPLICATION NAME found in $HOST_FILE"
fi
else
D=$(echo $D | cut -d "-" -f1)
UP=$(docker ps --format '{{.Names}}\t{{.Status}}' | grep Up | awk '{print $1}' | grep $D"-")
# filtering for ROLES variables if exists.
if [[ "$ROLES" != "null" && ! -z "$ROLES" ]]; then
UPS=""
for U in $(echo $UP); do
for ROLE in $(echo $ROLES); do
FILTERED_BY_ROLE=$(docker inspect $U -f '{{.Config.Labels.roles}}' | uniq | grep $ROLE)
if [[ "$(echo $FILTERED_BY_ROLE)" != "" ]]; then
UPS="$UPS $U"
fi
done
done
UP=$UPS
fi
UP_COUNT=$((UP_COUNT + $(echo $UP | wc -w)))
for SRV_FILE in $(echo $SERVICE_FILES); do
CONTAINER_NAMES=$(jq -r .containers[].NAME $SRV_FILE)
for NAME in $(echo $CONTAINER_NAMES); do
NEWNAME=$(echo $NAME | cut -d "-" -f1)
if [ "$D" == "$NEWNAME" ]; then
if [[ "$ROLES" != "null" && ! -z "$ROLES" ]]; then
C_ROLES=$(jq -r --arg NAME "$NAME" '.containers[] | select(.NAME==$NAME)' $SRV_FILE | jq -r .ROLES)
for ROLE in $(echo $ROLES); do
# TODO, ha C_ROLES tobb erteket tartalmaz
if [ "$ROLE" == "$C_ROLES" ]; then
SRV_COUNT=$((SRV_COUNT + 1))
fi
done
else
SRV_COUNT=$((SRV_COUNT + 1))
fi
fi
done
done
if [ ! -z "$UP" ]; then
for D_IP in $(echo $UP); do
DNS_IP=$(docker inspect $D_IP -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
if [ "$APP_IP" == "" ]; then
APP_IP="$DNS_IP"
else
APP_IP="$APP_IP $DNS_IP"
fi
echo "APP_IP: "$APP_IP
done
else
debug "no matching running process found"
fi
fi
done
if [[ ! -z "$STRICK_CHECK" && $UP_COUNT -lt $SRV_COUNT ]]; then
if [ "$2" == "" ]; then
RETRIES=0
else
RETRIES=$2
fi
if [ $RETRIES -le $RETRIES_NUMBER ]; then
debug "Try to reread container names at $RETRIES"
sleep 1
RETRIES=$((RETRIES + 1))
name_resolver $DNS $RETRIES
else
debug "Not enough running process found for executing firewall rules, exiting"
exit
fi
fi
}
if [[ -z "$TYPE" ]]; then
TYPE="tcp"
fi
if [[ -z "$SOURCE_IP" ]]; then
if [[ -z "$SOURCE" ]]; then
#SOURCE_IP="0.0.0.0/0";
echo "No source IP added"
elif [ "$(set | grep -w SOURCE_IFACE)" != "" ]; then
SOURCE=$SOURCE_IFACE
echo "VPN interface added instead of IP or domain name"
else
IDX=0
for i in $(echo $SOURCE); do
if [[ "$i" != [0-9]*"."[0-9]*"."[0-9]*"."[0-9]* ]]; then
name_resolver $i
debug "source ip is $APP_IP"
if [[ -z "$APP_IP" ]]; then
debug "No any IP address found for SOURCE: $SOURCE, try again to resolv"
name_resolver $i
debug "source ip is $APP_IP"
if [[ -z "$APP_IP" ]]; then
debug "No any IP address found for SOURCE: $SOURCE, giving up"
fi
fi
for IP in $(echo $APP_IP); do
IDX=$(expr 1 + $IDX)
eval SOURCE_IP_$IDX=$IP
done
else
IDX=$(expr 1 + $IDX)
if [[ "$(echo $i | cut -d . -f4)" == "0" ]]; then
SOURCE_IP="$i/24"
eval SOURCE_IP_$IDX="$i/24"
debug "source ip is $SOURCE_IP"
else
eval SOURCE_IP_$IDX=$i
IP=$i
debug "source ip is $IP"
fi
fi
done
if [ $IDX = 1 ]; then
SOURCE_IP=$IP
fi
fi
fi
if [[ -z "$TARGET_IP" ]]; then
if [[ -z "$TARGET" ]]; then
#TARGET_IP="0.0.0.0/0";
echo "No target IP added"
else
IDX=0
for i in $(echo $TARGET); do
if [[ "$i" != [0-9]*"."[0-9]*"."[0-9]*"."[0-9]* ]]; then
name_resolver $i
debug "target ip is $APP_IP"
if [[ -z "$APP_IP" ]]; then
debug "No any IP address found for TARGET: $TARGET, try again to resolv"
name_resolver $i
debug "target ip is $APP_IP"
if [[ -z "$APP_IP" ]]; then
debug "No any IP address found for TARGET: $TARGET, giving up"
fi
fi
for IP in $(echo $APP_IP); do
IDX=$(expr 1 + $IDX)
eval TARGET_IP_$IDX=$IP
done
else
IDX=$(expr 1 + $IDX)
if [[ "$(echo $i | cut -d . -f4)" == "0" ]]; then
TARGET_IP="$i/24"
eval TARGET_IP_$IDX="$i/24"
debug "target ip is $TARGET_IP"
else
eval TARGET_IP_$IDX=$i
IP=$i
debug "target ip is $IP"
fi
fi
done
if [ $IDX = 1 ]; then
TARGET_IP=$IP
fi
fi
fi
delete_lines() {
if [ "$1" != "" ]; then
CHAIN=$1
fi
if [ -n "$LINES" ]; then
for i in $LINES; do
debug "$IPTABLES -D $CHAIN $i"
$IPTABLES -w -D $CHAIN $i
sleep 0.1
done
fi
}
prerouting() {
if [ "$(set | grep -w SOURCE_IFACE)" != "" ]; then
if [ "$TARGET_IP" != "" ] && [ "$TARGET_PORT" != "" ]; then
debug "$IPTABLES -I PREROUTING -i $SOURCE_IFACE -p $PROTOCOL --dport $SOURCE_PORT -m comment --comment $COMMENT -j DNAT --to $TARGET_IP:$TARGET_PORT"
$IPTABLES -w -I PREROUTING -i $SOURCE_IFACE -p $PROTOCOL --dport $SOURCE_PORT -m comment --comment "$COMMENT" -j DNAT --to $TARGET_IP:$TARGET_PORT
fi
elif [ "$SOURCE_IP" != "" ]; then
if [ "$SOURCE_PORT" != "" ]; then
if [ "$TARGET_IP" != "" ]; then
if [ "$TARGET_PORT" != "" ]; then
LINES=$($IPTABLES -w -L --line-number -n | grep DNAT | grep $SOURCE_PORT | grep $TARGET_IP | grep $TARGET_PORT | grep $COMMENT | awk '{print $1}' | tac)
debug "Previous prerouting lines: "$LINES
# DELETE UNECESSARY LINES FROM PREVIOUS RULES
delete_lines "PREROUTING"
debug "$IPTABLES -I PREROUTING -d $SOURCE_IP -p $PROTOCOL --dport $SOURCE_PORT -m comment --comment $COMMENT -j DNAT --to $TARGET_IP:$TARGET_PORT"
$IPTABLES -w -I PREROUTING -d $SOURCE_IP -p $PROTOCOL --dport $SOURCE_PORT -m comment --comment "$COMMENT" -j DNAT --to $TARGET_IP:$TARGET_PORT
fi
fi
fi
fi
}
postrouting() {
if [ -n "$SOURCE_IP" ]; then
SOURCE_IP_FOR_POSTROUTING="$(echo $SOURCE_IP | cut -d . -f1-3).0/24"
debug "source ip is $SOURCE_IP_FOR_POSTROUTING"
LINES=$($IPTABLES -w -L --line-number -n | grep MASQUERADE | grep $COMMENT | grep $SOURCE_IP_FOR_POSTROUTING | grep $SOURCE_PORT | awk '{print $1}' | tac)
debug "Previous postrouting lines: "$LINES
# DELETE UNECESSARY LINES FROM PREVIOUS RULES
delete_lines "POSTROUTING"
debug "$IPTABLES -I POSTROUTING -s $SOURCE_IP_FOR_POSTROUTING -p $PROTOCOL --sport $SOURCE_PORT -m comment --comment "$COMMENT" -j MASQUERADE"
$IPTABLES -w -I POSTROUTING -s $SOURCE_IP_FOR_POSTROUTING -p $PROTOCOL --sport $SOURCE_PORT -m comment --comment "$COMMENT" -j MASQUERADE
fi
if [ -n "$TARGET_IP" ]; then
TARGET_IP_FOR_POSTROUTING="$(echo $TARGET_IP | cut -d . -f1-3).0/24"
debug "target ip is $TARGET_IP_FOR_POSTROUTING"
LINES=$($IPTABLES -w -L --line-number -n | grep $COMMENT | grep $TARGET_IP_FOR_POSTROUTING | grep $TARGET_PORT | awk '{print $1}' | tac)
debug "Previous postrouting lines: "$LINES
# DELETE UNECESSARY LINES FROM PREVIOUS RULES
delete_lines "POSTROUTING"
debug "$IPTABLES -I POSTROUTING -s $TARGET_IP_FOR_POSTROUTING -p $PROTOCOL --dport $TARGET_PORT -m comment --comment "$COMMENT" -j MASQUERADE"
$IPTABLES -w -I POSTROUTING -d $TARGET_IP_FOR_POSTROUTING -p $PROTOCOL --dport $TARGET_PORT -m comment --comment "$COMMENT" -j MASQUERADE
fi
}
ip_route() {
COUNT_NETWORK=$(set | grep NETWORK | wc -l)
for network_index in $(seq 1 $COUNT_NETWORK); do
if set | grep NETWORK_; then
NETWORK=$(eval "echo \${"NETWORK_$network_index"}")
GATEWAY=$(eval "echo \${"GATEWAY_$network_index"}")
fi
debug "ip route add "$NETWORK"/24 via "$GATEWAY
$IP_ROUTE add $NETWORK/24 via $GATEWAY
done
}
if [[ "$ROUTE" == "true" ]]; then
IP_ROUTE="nsenter -t $(docker inspect --format {{.State.Pid}} $NAME) -n -- ip route"
ip_route
exit
fi
##############################
echo 1 >/proc/sys/net/ipv4/ip_forward
##############################
if /usr/sbin/iptables-legacy -L | grep DOCKER-USER; then
IPTABLES="/usr/sbin/iptables-legacy"
else
IPTABLES="/usr/sbin/iptables"
fi
###############################
COUNT_SOURCE_IP=$(set | grep SOURCE_IP | wc -l)
COUNT_SOURCE_PORT=$(set | grep SOURCE_PORT | wc -l)
COUNT_TARGET_IP=$(set | grep TARGET_IP | wc -l)
COUNT_TARGET_PORT=$(set | grep TARGET_PORT | wc -l)
# SOURCE AND TARGET PORTS ARE IN PAIRS
if [ "$COUNT_SOURCE_PORT" == "$COUNT_TARGET_PORT" ]; then
PAIRS="1"
else
PAIRS="0"
fi
if [ "$COUNT_SOURCE_IP" == 0 ]; then COUNT_SOURCE_IP=1; fi
for source_ip_index in $(seq 1 $COUNT_SOURCE_IP); do
if set | grep SOURCE_IP_; then
SOURCE_IP=$(eval "echo \${"SOURCE_IP_$source_ip_index"}")
fi
if [ "$COUNT_SOURCE_PORT" == 0 ]; then COUNT_SOURCE_PORT=1; fi
for source_port_index in $(seq 1 $COUNT_SOURCE_PORT); do
if set | grep SOURCE_PORT_; then
SOURCE_PORT=$(eval "echo \${"SOURCE_PORT_$source_port_index"}")
fi
if [ "$COUNT_TARGET_IP" == 0 ]; then COUNT_TARGET_IP=1; fi
for target_ip_index in $(seq 1 $COUNT_TARGET_IP); do
if set | grep TARGET_IP_; then
TARGET_IP=$(eval "echo \${"TARGET_IP_$target_ip_index"}")
fi
if [ "$COUNT_TARGET_PORT" == 0 ]; then COUNT_TARGET_PORT=1; fi
for target_port_index in $(seq 1 $COUNT_TARGET_PORT); do
if set | grep TARGET_PORT_; then
TARGET_PORT=$(eval "echo \${"TARGET_PORT_$target_port_index"}")
fi
debug "PAIRS: $PAIRS"
debug "source_port_index: $source_port_index"
debug "target_port_index: $target_port_index"
# if case of pairs if indexes doesn't match then omit routing
if [ "$PAIRS" == "1" ] && [ "$source_port_index" != "$target_port_index" ]; then
debug "OMIT ROUTING"
continue
fi
#############################
# NSENTER Specific settings #
if [[ "$PREROUTING" == "true" ]] || [[ "$POSTROUTING" == "true" ]] || [[ "$HOST" == "true" ]]; then
if [ "$HOST" == "true" ]; then
IPTABLES="/sbin/iptables -t nat"
debug "iptables: "$IPTABLES
else
IPTABLES="nsenter -t $(docker inspect --format {{.State.Pid}} $NAME) -n -- /sbin/iptables-legacy -t nat"
debug "iptables: "$IPTABLES
fi
if [[ "$PREROUTING" == "true" ]]; then
prerouting
fi
if [[ "$POSTROUTING" == "true" ]]; then
postrouting
fi
else
############################
# Host firewall settings ###
if $IPTABLES -w -n --list $CHAIN | grep ESTABLISHED | grep RELATED | grep ACCEPT; then
echo "nothing to do"
else
$IPTABLES -w -I $CHAIN -m state --state established,related -j ACCEPT
fi
IPTABLES_OPTIONS=""
GREP_OPTIONS=""
if [ "$SOURCE_IP" != "" ]; then
if [ "$(echo $SOURCE_IP | cut -d . -f4)" == "0" ]; then
SOURCE_IP="$(echo $SOURCE_IP | cut -d . -f1-3).0/24"
fi
IPTABLES_OPTIONS=$IPTABLES_OPTIONS" -s $SOURCE_IP"
GREP_OPTIONS=$GREP_OPTIONS"|grep -e $SOURCE_IP"
if [ "$SOURCE_PORT" != "" ]; then
IPTABLES_OPTIONS=$IPTABLES_OPTIONS" --sport $SOURCE_PORT"
GREP_OPTIONS=$GREP_OPTIONS"|grep -e $SOURCE_PORT"
fi
fi
if [ "$TARGET_IP" != "" ]; then
if [ "$(echo $TARGET_IP | cut -d . -f4)" == "0" ]; then
TARGET_IP="$(echo $TARGET_IP | cut -d . -f1-3).0/24"
fi
IPTABLES_OPTIONS=$IPTABLES_OPTIONS" -d $TARGET_IP"
GREP_OPTIONS=$GREP_OPTIONS"|grep -e $TARGET_IP"
if [ "$TARGET_PORT" != "" ]; then
IPTABLES_OPTIONS=$IPTABLES_OPTIONS" --dport $TARGET_PORT"
GREP_OPTIONS=$GREP_OPTIONS"|grep -e $TARGET_PORT"
fi
fi
if [[ "$SOURCE_IP" != "" && "$TARGET_IP" != "" ]]; then
#
# DELETE UNECESSARY LINES FROM PREVIOUS RULES
IPTABLES_COMMAND="$IPTABLES -w --line-number -n --list $CHAIN | grep $PROTOCOL $GREP_OPTIONS | awk '{print \$1}'| tac"
debug "$IPTABLES_COMMAND"
LINES=$(eval $IPTABLES_COMMAND)
delete_lines
if [ "$OPERATION" == "DELETE" ]; then
IPTABLES_COMMAND="$IPTABLES -w --line-number -n --list $CHAIN | grep -w "$COMMENT" | awk '{print \$1}'| tac"
debug "$IPTABLES_COMMAND"
LINES=$(eval $IPTABLES_COMMAND)
delete_lines
else
debug "$IPTABLES -I $CHAIN -p $PROTOCOL $IPTABLES_OPTIONS -m comment --comment "$COMMENT" -j ACCEPT"
$IPTABLES -w -I $CHAIN -p $PROTOCOL $IPTABLES_OPTIONS -m comment --comment "$COMMENT" -j ACCEPT
fi
fi
#############################
fi
done # target_port
done # target_ip
done # source_port
done # source_ip