#!/bin/bash # # # # ConfigServer Firewall - Docker Patch # # @author Aetherinox # @package ConfigServer Firewall # @file docker.sh # @type Patch # @desc This CSF script scans all docker containers that exist within the server and adds each # container ip to the ConfigServer Firewall. # # @usage chmod +x /usr/local/include/csf/post.d/docker.sh # sudo /usr/local/include/csf/post.d/docker.sh # # this can also be installed by executing the install.sh script # # export PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # # # define > configs # # docker0_eth main docker network interface # can be created using the command: # - `sudo docker network create --driver=bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1 traefik`` # file_csf_allow the defined allow list file # csf_comment comment added to each whitelisted ip within iptables # containers_ip_cidr list of ip address blocks you will be using for your docker setup. these blocks will be whitelisted through ConfigServer Firewall # # docker0_eth="docker0" csf_comment="Docker container whitelist" file_csf_allow="/etc/csf/csf.allow" # # # define > network ips # # this is the list of IP addresses you will use with docker that must be # whitelisted. # # containers_ip_cidr=( '172.17.0.0/16' ) # # # define > system # # sys_arch=$(dpkg --print-architecture) sys_code=$(lsb_release -cs) # # # vars > app # # app_dir_this_a="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" # current script full path app_dir_this_b="${PWD}" # current script full path (alternative) app_file_this=$(basename "$0") # docker.sh (with ext) app_file_bin="${app_file_this%.*}" # docker (without ext) app_pid=$BASHPID # app pid app_title="ConfigServer Firewall - Docker Patch" # app title; displayed with --version app_about="Sets up your firewall rules to work with Docker and Traefik. \n"\ " This script requires that you have iptables installed on your system. \n"\ " The required packages will be installed if you do not have them." # app about; displayed with --version app_ver=("14" "24" "0") # current script version # # # define > configs # # cfg_dev_enabled=false cfg_verbose_enabled=false # # # define > app repo # # repo_name="csf-firewall" repo_author="Aetherinox" repo_branch="main" repo_url="https://github.com/${repo_author}/${repo_name}" # # # define > colors # # Use the color table at: # - https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 # # END=$'\e[0m' WHITE=$'\e[97m' BOLD=$'\e[1m' DIM=$'\e[2m' UNDERLINE=$'\e[4m' STRIKE=$'\e[9m' BLINK=$'\e[5m' INVERTED=$'\e[7m' HIDDEN=$'\e[8m' BLACK=$'\e[38;5;0m' FUCHSIA1=$'\e[38;5;205m' FUCHSIA2=$'\e[38;5;198m' RED=$'\e[38;5;160m' RED2=$'\e[38;5;196m' ORANGE=$'\e[38;5;202m' ORANGE2=$'\e[38;5;208m' MAGENTA=$'\e[38;5;5m' BLUE=$'\e[38;5;033m' BLUE2=$'\e[38;5;39m' BLUE3=$'\e[38;5;68m' CYAN=$'\e[38;5;51m' GREEN=$'\e[38;5;2m' GREEN2=$'\e[38;5;76m' YELLOW=$'\e[38;5;184m' YELLOW2=$'\e[38;5;190m' YELLOW3=$'\e[38;5;193m' GREY1=$'\e[38;5;240m' GREY2=$'\e[38;5;244m' GREY3=$'\e[38;5;250m' NAVY=$'\e[38;5;62m' OLIVE=$'\e[38;5;144m' PEACH=$'\e[38;5;210m' # # # print an error and exit with failure # $1: error message # # function error() { echo -e " ⭕ ${GREY2}${app_file_this}${END}: \n ${BOLD}${RED}Error${END}: ${END}$1" echo -e exit 0 } # # # func > check sudo # # this script requires permissions to copy, etc. # require the user to run as sudo # # check_sudo() { if [ "$EUID" -ne 0 ]; then echo -e echo -e " ${ORANGE}WARNING ${END}This script requires ${YELLOW2}sudo${END}" echo -e " Without this elevated permission; iptables will not add the proper rules." echo -e " before this script can be ran.${END}" echo -e echo -e " You may trigger sudo by running the following command:${END}" echo -e " ${GREY2}sudo ./${app_file_this}${END}" echo -e exit 1 fi } # # # func > version > compare greater than # # this function compares two versions and determines if an update may # be available. or the user is running a lesser version of a program. # # get_version_compare_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } # # # func > get version # # returns current version of app # converts to human string. # e.g. "1" "2" "4" "0" # 1.2.4.0 # # get_version() { ver_join=${app_ver[@]} ver_str=${ver_join// /.} echo ${ver_str} } # # # func > service exists # # service_exists() { local n=$1 if [[ $(systemctl list-units --all -t service --full --no-legend "$n.service" | sed 's/^\s*//g' | cut -f1 -d' ') == $n.service ]]; then return 0 else return 1 fi } # # # Find CSF path on system; throw error if not found # # csf_path=$(command -v csf) if [ -z "$csf_path" ]; then echo -e echo -e " ${ORANGE}WARNING ${END}This Script Requires ConfigServer Firewall${END}" echo -e " You must install the application ${RED}ConfigServer Firewall${END} on your server" echo -e " before this script can be ran.${END}" echo -e echo -e " You can download ConfigServer Firewall from the following links:${END}" echo -e " ${GREY2}https://github.com/Aetherinox/csf-firewall/releases${END}" echo -e " ${GREY2}https://download.configserver.com/csf.tgz${END}" echo -e exit 0 fi # # # distro # # returns distro information. # # # # # freedesktop.org and systemd # # if [ -f /etc/os-release ]; then . /etc/os-release sys_os=$NAME sys_os_ver=$VERSION_ID # # # linuxbase.org # # elif type lsb_release >/dev/null 2>&1; then sys_os=$(lsb_release -si) sys_os_ver=$(lsb_release -sr) # # # versions of Debian/Ubuntu without lsb_release cmd # # elif [ -f /etc/lsb-release ]; then . /etc/lsb-release sys_os=$DISTRIB_ID sys_os_ver=$DISTRIB_RELEASE # # # older Debian/Ubuntu/etc distros # # elif [ -f /etc/debian_version ]; then sys_os=Debian sys_os_ver=$(cat /etc/debian_version) # # # fallback: uname, e.g. "Linux ", also works for BSD # # else sys_os=$(uname -s) sys_os_ver=$(uname -r) fi # # # Ensure we're in the correct directory # # cd "${app_dir_this_a}" # # # clear screen before starting step 1 # # clear # # # Check sudo # # check_sudo # # # find > iptables # # if ! [ -x "$(command -v iptables)" ]; then echo -e " ${GREEN}OK ${END}Installing package ${BLUE2}iptables${END}" sudo apt-get update -y -q >/dev/null 2>&1 sudo apt-get install iptables -y -qq >/dev/null 2>&1 fi # # # iptables > assign path to var # # path_iptables4=$(which iptables) path_iptables6=$(which ip6tables) # # # empty var > iptables4 # # if [ -z "${path_iptables4}" ]; then echo -e echo -e " ${ORANGE}WARNING ${END}This Script Requires Iptables${END}" echo -e " This package is required before you can utilize this script with ConfigServer Firewall." echo -e echo -e " Try installing the package with:${END}" echo -e " ${GREY2}sudo apt-get update${END}" echo -e " ${GREY2}sudo apt-get install iptables${END}" echo -e exit 0 fi # # # Truncate text; add ... # # @usage $(trim "$name" 20 "...") # # trim() { if (( "${#1}" > "$2" )); then echo "${1:0:$2}$3" else echo "$1" fi } # # # func > cmd > help # # activate using ./install.sh --help or -h # # cmd_help() { echo -e echo "${GREY1} ┌────────────────────────────────────────────────────────────────────────────────────────┐${END}" echo printf " ${BLUE2}${app_title} (v$(get_version))${END}\n\n" 1>&2 printf " ${GREY2}${app_about}${END}\n" 1>&2 echo -e printf ' %-5s %-40s\n' " ${GREEN}Usage:${END}" "" 1>&2 printf ' %-5s %-40s\n' " " "${app_file_this} ${GREY1}[${GREY2}options${END}${GREY1}]${END}" 1>&2 printf ' %-5s %-40s\n\n' " " "${app_file_this} ${GREY1}[${GREY2}-h | --help${END}${GREY1}] [${GREY2}-v | --version${END}${GREY1}] [${GREY2}-d | --dev${END}${GREY1}] [${GREY2}-l | --list${END}${GREY1}] [${GREY2}-r | --reset${END}${GREY1}]" 1>&2 printf ' %-5s %-40s\n' " ${GREEN}Options:${END}" "" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-d, --dev" "developer mode" 1>&2 printf ' %-5s %-18s %-40s\n' " " "" " ${GREY2}includes verbose logging${END}" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-l, --list" "shows all current docker containers with information" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-c, --clear" "clears entire iptables rule list" 1>&2 printf ' %-5s %-18s %-40s\n' " " "" " ${GREY2}firewall will be completely open after this finishes${END}" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-r, --restart" "restarts config server firewall and lfd" 1>&2 printf ' %-5s %-18s %-40s\n' " " "" " ${GREY2}firewall will be completely open after this finishes${END}" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-v, --version" "current version of ${app_file_this} script" 1>&2 printf ' %-5s %-18s %-40s\n' " " "-h, --help" "show help menu" 1>&2 echo echo "${GREY1} └────────────────────────────────────────────────────────────────────────────────────────┘${END}" echo -e } # # # func > cmd > version info & about # # @usage docker.sh --version # docker.sh -v # # cmd_version() { echo -e echo "${GREY1} ┌────────────────────────────────────────────────────────────────────────────────────────┐${END}" echo printf " ${BLUE2}${app_title} (v$(get_version))${END}\n\n" 1>&2 printf " ${GREY2}${app_about}${END}\n" 1>&2 echo -e printf " ${GREY2}@repo ${BLUE2}${repo_url}\n" 1>&2 printf " ${GREY2}@system ${BLUE2}${sys_os} | ${sys_os_ver}\n" 1>&2 printf " ${GREY2}@notice ${YELLOW}Before running this script, open ${FUCHSIA1}${app_dir_this_a}/${app_file_this}\n" 1>&2 printf " ${GREY2} ${YELLOW}and edit the settings at the top of the file.\n" 1>&2 echo echo "${GREY1} └────────────────────────────────────────────────────────────────────────────────────────┘${END}" echo -e } # # # func > cmd > clear iptables # # clears the entire iptables list # # @usage docker.sh --clear # docker.sh -c # # cmd_iptables_clear() { sudo ${path_iptables4} -F sudo ${path_iptables4} -X sudo ${path_iptables4} -t nat -F sudo ${path_iptables4} -t nat -X sudo ${path_iptables4} -t mangle -F sudo ${path_iptables4} -t mangle -X echo -e " ${BOLD}${GREY1}+ IPTABLES ${WHITE}Successfully reset iptable chains and rules${END}" } # # # func > cmd > csf > restart # # restarts csf and lfd # # @usage docker.sh --restart # docker.sh -r # # cmd_csf_restart() { echo -e if service_exists lfd; then echo -e " ${BOLD}${GREY1}+ lfd.service ${END}${GREEN}Restarting${END}" sudo systemctl restart lfd.service else echo -e echo -e " ${ORANGE}WARNING ${END}Could not find service ${YELLOW2}lfd.service${END}" echo -e " It is either not installed or the service is disabled. Enable the service first." echo -e echo -e " Once CSF is installed, you can enable the service by running:${END}" echo -e " ${GREY2}sudo csf -e${END}" echo -e sudo systemctl status lfd fi if service_exists csf; then echo -e " ${BOLD}${GREY1}+ csf.service ${END}${GREEN}Restarting${END}" sudo systemctl restart csf.service else echo -e echo -e " ${ORANGE}WARNING ${END}Could not find service ${YELLOW2}csf.service${END}" echo -e " It is either not installed or the service is disabled. Enable the service first." echo -e echo -e " Once CSF is installed, you can enable the service by running:${END}" echo -e " ${GREY2}sudo csf -e${END}" echo -e sudo systemctl status csf fi echo -e } # # # func > cmd > list containers # # lists all of the docker containers, with information such as veth adapter, ip, container id, name, etc. # # @usage docker.sh --list # docker.sh -l # # cmd_containers_list() { # # # get all containers from docker # # containers=`docker ps -q` # # # count docker containers; must be greater than 1 # # if [ `echo ${containers} | wc -c` -gt "1" ]; then echo -e echo " ${GREY1} ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐${END}" printf '%-17s %-30s %-38s %-26s %-33s %-33s %-30s %-40s %-50s' \ " " \ "${GREY2} Container${END}" \ "${GREY2} Name" \ "${GREY2} Shell${END}" \ "${GREY2} IP${END}" \ "${GREY2} IfLink ID${END}" \ "${GREY2} Veth Adapter${END}" \ "${GREY2} Network Mode${END}" \ "${GREY2} Network List${END}" # # # Loop containers # # for cont_id in ${containers}; do # # # Output: # CONTAINER ............... : 5b251b810e7d # NETMODE ................. : 63599565ed58b275d60087e218e2875aec3c3258976433d061721f0cb666e0b8 # # Example: # Running `docker inspect -f "{{.HostConfig.NetworkMode}}" 5b251b810e7d` outputs: # 63599565ed58b275d60087e218e2875aec3c3258976433d061721f0cb666e0b8 # # cont_netmode=`docker inspect -f "{{.HostConfig.NetworkMode}}" ${cont_id}` # mail_default cont_network=`docker inspect -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}' ${cont_id}` # mail_default \n traefik (multiple lines) cont_network_list=`docker inspect -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s " $net}}{{end}}' ${cont_id}` # mail_default traefik (unformatted list) cont_network_json=`docker inspect -f "{{json .NetworkSettings.Networks}}" ${cont_id}` # {"mail_default":{"IPAMConfig":null,"Links":null,"Aliases":["mail-antispam","antispam"],"MacAddress":"01:22:00:0a:00:01" cont_name=`docker inspect -f "{{.Name}}" ${cont_id}` # /mail-smtp cont_name=${cont_name#/} # mail-smtp (remove forward slash) cont_name=$(echo "$cont_name" | sed "s/ //g") # mail-smtp (remove spaces) cont_iflink=`docker exec -i "$cont_id" bash -c 'cat /sys/class/net/eth0/iflink' 2> /dev/null` # 3605 cont_shell="Bash" # bash (default shell) err_bash_notfound=`echo "$cont_iflink" 2> /dev/null | grep -c "exec failed"` # # # Bash Not Found # # if [[ "$err_bash_notfound" == "1" ]]; then cont_iflink=`docker exec -it "$cont_id" sh -c 'cat /sys/class/net/eth0/iflink' 2>/dev/null` err_sh_notfound=`echo "$cont_iflink" 2> /dev/null | grep -c "exec failed"` # # # Sh Not Found # # if [[ "$err_sh_notfound" == "1" ]]; then cont_shell="Unknown" cont_iflink="Unknown" else cont_iflink=`echo "$cont_iflink" | sed 's/[^0-9]*//g'` cont_shell="SH" fi else cont_iflink=`echo "$cont_iflink" | sed 's/[^0-9]*//g'` fi # # # container > running || unresponsive || offline # # cont_status=$(docker ps --format '{{.Names}}' | grep -c "^${cont_name}$") if [ "$( docker container inspect -f '{{.State.Running}}' $cont_name )" != "true" ]; then cont_iflink="Offline" fi if [ -z "${cont_iflink}" ]; then cont_iflink="Unresponsive" fi # # # Get veth network interface # # if [ -n "${cont_iflink}" ]; then cont_veth=$(sudo grep -l -s "$cont_iflink" /sys/class/net/veth*/ifindex) cont_veth=`echo "$cont_veth" | sed -e 's;^.*net/\(.*\)/ifindex$;\1;'` if [ -z "${cont_veth}" ]; then cont_veth="Unknown" fi fi # # # Chart Truncation # # cont_name_chart=$(trim "$cont_name" 20 "...") cont_network_list_chart=$(trim "$cont_network_list" 50 "...") cont_network_mode_chart=$(trim "$cont_netmode" 18 "...") cont_network_ip_chart="Not Found" cont_network_list="$cont_network" declare -a cont_network_arr=( $cont_network ) # # # Netmode > Default # # if [ "$cont_netmode" == "default" ]; then cont_bridge_name="${docker0_eth}" cont_ipaddr=`docker inspect -f "{{.NetworkSettings.IPAddress}}" ${cont_id}` cont_network_ip_chart="$cont_ipaddr" # # # Netmode > Other # # else # Loop Networks while IFS= read -r cont_network_list; do # cont_bridge_name=`docker inspect -f "{{with index .NetworkSettings.Networks \"bridge\"}}{{.NetworkID}}{{end}}" cb9a6ae9c19e | cut -c -12` cont_bridge=$(docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network_list}\"}}{{.NetworkID}}{{end}}" ${cont_id} | cut -c -12) # docker network inspect -f {{"br-e95004d90f8d" | or (index .Options "com.docker.network.bridge.name")}} e95004d90f8d cont_bridge_name=`docker network inspect -f '{{"'br-$cont_bridge'" | or (index .Options "com.docker.network.bridge.name")}}' $cont_bridge` cont_ipaddr=`docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network_list}\"}}{{.IPAddress}}{{end}}" ${cont_id}` cont_ipaddr_orig=${cont_ipaddr} cont_network_ip_chart="$cont_ipaddr" if [ -z "${cont_bridge}" ]; then cont_bridge="${RED2}Not found${END}"; fi if [ -z "${cont_bridge_name}" ]; then cont_bridge_name="${RED2}Not found${END}"; fi if [ -z "${cont_ipaddr}" ]; then cont_ipaddr="${RED2}Not found${END}"; cont_network_ip_chart="Not Found"; fi done <<< "$cont_network_list" fi # # # List each container # # printf '\n%-17s %-30s %-38s %-26s %-33s %-33s %-30s %-40s %-50s' \ " " \ "${GREY2} ${cont_id}${END}" \ "${GREY2} ${cont_name_chart}" \ "${GREY2} ${cont_shell}${END}" \ "${GREY2} ${cont_network_ip_chart}${END}" \ "${GREY2} ${cont_iflink}${END}" \ "${GREY2} ${cont_veth}${END}" \ "${GREY2} ${cont_network_mode_chart}${END}" \ "${GREY2} [${#cont_network_arr[@]}] ${cont_network_list_chart}${END}" done echo -e echo " ${GREY1} └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘${END}" echo -e echo -e fi } # # # command-line options # # reminder that any functions which need executed must be defined BEFORE # this point. Bash sucks like that. # # --dev show advanced printing # --help show help and usage information # --version display version information # # while [ $# -gt 0 ]; do case "$1" in -d|--dev) cfg_dev_enabled=true echo -e " ${MAGENTA}MODE ${END}Developer Enabled${END}" ;; -h*|--help*) cmd_help exit 1 ;; -l|--list) cmd_containers_list exit 1 ;; -r|--restart) cmd_csf_restart exit 1 ;; -c|--clear) cmd_iptables_clear exit 1 ;; -v|--version) cmd_version exit 1 ;; *) cmd_help exit 1 ;; esac shift done # # # Clean container ips added by script once per restart # # if [[ $csf_path ]]; then echo -e echo -e " ${BOLD}${GREY1}+ CSF ${WHITE}Cleaning ${file_csf_allow}${END}" sudo sed --in-place "/${csf_comment}/d" ${file_csf_allow} fi # # # {bridge} = docker0 # {subnet} = 172.17.0.0/16 # # + MASQUERADE rule: 172.17.0.0/16 on docker0 # + FORWARD rule: accept established connections for docker0 # + FORWARD rule: allow communication for docker0 # + MASQUERADE rule: 172.18.0.0/16 on br-2e0fde4b0664 # + FORWARD rule: accept established connections for br-2e0fde4b0664 # + FORWARD rule: allow communication for br-2e0fde4b0664 # # # # # Chain Exists # # chainExists() { [ $# -lt 1 -o $# -gt 2 ] && { echo "Usage: chainExists [table]" >&2 return 1 } local chain_name="$1" ; shift [ $# -eq 1 ] && local table="-t $1" if [ `sudo ${path_iptables4} -n --list "$chain_name" $table 2> /dev/null | grep "$chain_name" | wc -l` -eq 0 ]; then echo 0; else echo 1; fi } # # # Rule Exists # # ruleExists() { [ $# -lt 1 ] && { echo "Usage: ruleExists " >&2 return 1 } local chain_rule="$1" if [ `iptables -C "$chain_rule" > /dev/null 2>&1` ]; then echo 1; else echo 0; fi } # # # Forward > Add # # Allow containers to communicate with themselves & outside world # # add_to_forward() { local docker_int=$1 if ! sudo ${path_iptables4} -C FORWARD -o ${docker_int} -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT &>/dev/null; then sudo ${path_iptables4} -A FORWARD -o ${docker_int} -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -o ${docker_int} -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -A FORWARD -o ${docker_int} -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT${END}" fi if ! sudo ${path_iptables4} -C FORWARD -o ${docker_int} -j DOCKER &>/dev/null; then sudo ${path_iptables4} -A FORWARD -o ${docker_int} -j DOCKER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -o ${docker_int} -j DOCKER${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -A FORWARD -o ${docker_int} -j DOCKER${END}" fi if ! sudo ${path_iptables4} -C FORWARD -i ${docker_int} ! -o ${docker_int} -j ACCEPT &>/dev/null; then sudo ${path_iptables4} -A FORWARD -i ${docker_int} ! -o ${docker_int} -j ACCEPT echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -i ${docker_int} ! -o ${docker_int} -j ACCEPT${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -A FORWARD -i ${docker_int} ! -o ${docker_int} -j ACCEPT${END}" fi if ! sudo ${path_iptables4} -C FORWARD -i ${docker_int} -o ${docker_int} -j ACCEPT &>/dev/null; then sudo ${path_iptables4} -A FORWARD -i ${docker_int} -o ${docker_int} -j ACCEPT echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -i ${docker_int} -o ${docker_int} -j ACCEPT${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -A FORWARD -i ${docker_int} -o ${docker_int} -j ACCEPT${END}" fi } # # # NAT > Add # # add_to_nat() { local docker_int=$1 local subnet=$2 # ipv4 if [ "$subnet" != "${subnet#*[0-9].[0-9]}" ]; then sudo ${path_iptables4} -t nat -A POSTROUTING -s ${subnet} ! -o ${docker_int} -j MASQUERADE sudo ${path_iptables4} -t nat -A DOCKER -i ${docker_int} -j RETURN echo -e " ${GREY1}+ RULE v4: ${FUCHSIA2}-t nat -A POSTROUTING -s ${subnet} ! -o ${docker_int} -j MASQUERADE${END}" echo -e " ${GREY1}+ RULE v4: ${FUCHSIA2}-t nat -A DOCKER -i ${docker_int} -j RETURN${END}" # ipv6 elif [ "$subnet" != "${subnet#*:[0-9a-fA-F]}" ]; then sudo ${path_iptables6} -t nat -A POSTROUTING -s ${subnet} ! -o ${docker_int} -j MASQUERADE sudo ${path_iptables6} -A DOCKER -i ${docker_int} -j RETURN echo -e " ${GREY1}+ RULE v6: ${FUCHSIA2}-t nat -A POSTROUTING -s ${subnet} ! -o ${docker_int} -j MASQUERADE${END}" echo -e " ${GREY1}+ RULE v6: ${FUCHSIA2}-A DOCKER -i ${docker_int} -j RETURN${END}" else echo "Unrecognized subnet format '$subnet'" fi } # # # Docker Isolation > Add # # add_to_docker_isolation() { local docker_int=$1 sudo ${path_iptables4} -A DOCKER-ISOLATION-STAGE-1 -i ${docker_int} ! -o ${docker_int} -j DOCKER-ISOLATION-STAGE-2 sudo ${path_iptables4} -A DOCKER-ISOLATION-STAGE-2 -o ${docker_int} -j DROP echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-1 -i ${docker_int} ! -o ${docker_int} -j DOCKER-ISOLATION-STAGE-2${END}" echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-2 -o ${docker_int} -j DROP${END}" } # # # sudo update-alternatives --set iptables /usr/sbin/iptables-legacy # # # # # iptables-save & restore # # sudo iptables-save | grep -v -- '-j DOCKER' | sudo iptables-restore # # # Chain DOCKER - Flush or Create # # -N Creates new chain # -X Delete a user defined-chain # -F Flush rules in chain # # if [ $(chainExists DOCKER) -eq 1 ] ; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Flush existing chain DOCKER${END}" sudo ${path_iptables4} -F DOCKER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-F DOCKER${END}" else echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Create new chain DOCKER${END}" sudo ${path_iptables4} -N DOCKER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-N DOCKER${END}" fi # # # Chain DOCKER-ISOLATION-STAGE-1 - Flush or Create # # -N Creates new chain # -X Delete a user defined-chain # -F Flush rules in chain # # if [ $(chainExists DOCKER-ISOLATION-STAGE-1) -eq 1 ] ; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Flush existing chain DOCKER-ISOLATION-STAGE-1${END}" sudo ${path_iptables4} -F DOCKER-ISOLATION-STAGE-1 echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-F DOCKER-ISOLATION-STAGE-1${END}" else echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Create new chain DOCKER-ISOLATION-STAGE-1${END}" sudo ${path_iptables4} -N DOCKER-ISOLATION-STAGE-1 echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-N DOCKER-ISOLATION-STAGE-1${END}" fi # # # Chain DOCKER-ISOLATION-STAGE-2 - Flush or Create # # -N Creates new chain # -X Delete a user defined-chain # -F Flush rules in chain # # if [ $(chainExists DOCKER-ISOLATION-STAGE-2) -eq 1 ] ; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Flush existing chain DOCKER-ISOLATION-STAGE-2${END}" sudo ${path_iptables4} -F DOCKER-ISOLATION-STAGE-2 echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-F DOCKER-ISOLATION-STAGE-2${END}" else echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Create new chain DOCKER-ISOLATION-STAGE-2${END}" sudo ${path_iptables4} -N DOCKER-ISOLATION-STAGE-2 echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-N DOCKER-ISOLATION-STAGE-2${END}" fi # # # Chain DOCKER-USER - Flush or Create # # -N Creates new chain # -X Delete a user defined-chain # -F Flush rules in chain # # if [ $(chainExists DOCKER-USER) -eq 1 ] ; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Flush existing chain DOCKER-USER${END}" sudo ${path_iptables4} -F DOCKER-USER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-F DOCKER-USER${END}" else echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Create new chain DOCKER-USER${END}" sudo ${path_iptables4} -N DOCKER-USER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-N DOCKER-USER${END}" fi # # # Chain DOCKER-USER (table nat) - Flush or Create # # -N Creates new chain # -X Delete a user defined-chain # -F Flush rules in chain # -t Table to manipulate # # if [ $(chainExists DOCKER nat) -eq 1 ] ; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Flush existing chain DOCKER; table NAT${END}" sudo ${path_iptables4} -t nat -F DOCKER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-t nat -F DOCKER${END}" else echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Create new chain DOCKER; table NAT${END}" sudo ${path_iptables4} -t nat -N DOCKER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-t nat -N DOCKER${END}" fi # # # Add Rules: # - INPUT add docker0 ACCEPT # - FORWARD add DOCKER-USER # - FORWARD add DOCKER-ISO-1 # # -A Append rule # -i Incoming network interface # -j Target for rule; ACCEPT, DROP, REJECT # # if ! sudo ${path_iptables4} -C INPUT -i docker0 -j ACCEPT &>/dev/null; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Add ACCEPT policy for chain INPUT on DOCKER0 integrate${END}" sudo ${path_iptables4} -A INPUT -i ${docker0_eth} -j ACCEPT echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A INPUT -i ${docker0_eth} -j ACCEPT${END}" fi # # # Chain FORWARD (policy DROP) # # target prot opt source destination # DOCKER-USER all -- anywhere anywhere # # if ! sudo ${path_iptables4} -C FORWARD -j DOCKER-USER &>/dev/null; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Add JUMP rule in chain FORWARD to chain DOCKER-USER${END}" sudo ${path_iptables4} -A FORWARD -j DOCKER-USER echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -j DOCKER-USER${END}" fi # # # Chain FORWARD (policy DROP) # # target prot opt source destination # DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere # # if ! sudo ${path_iptables4} -C FORWARD -j DOCKER-ISOLATION-STAGE-1 &>/dev/null; then echo -e " ${BOLD}${GREY1}+ IPTABLES ${END}Add JUMP rule in chain FORWARD to chain DOCKER-ISOLATION-STAGE-1${END}" sudo ${path_iptables4} -A FORWARD -j DOCKER-ISOLATION-STAGE-1 echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-A FORWARD -j DOCKER-ISOLATION-STAGE-1${END}" fi # # # add docker0 to forward # # add_to_forward ${docker0_eth} # # # To view PREROUTING and POSTROUTING rules; add `-t nat` with: # sudo iptables -t nat -L --line-numbers -n # # Check if rule exists with: # sudo iptables -C PREROUTING -t nat -m addrtype --dst-type LOCAL -j DOCKER # # target prot opt source destination # DOCKER 0 -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL # # sudo ${path_iptables4} -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER sudo ${path_iptables4} -t nat -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER # # # whitelist ip addresses associated with docker # # echo -e echo -e " ${GREY1}―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――${END}" echo -e echo -e " ${BOLD}${GREY1}+ POSTROUTING ${WHITE}Adding IPs from primary IP list${END}" for j in "${!containers_ip_cidr[@]}"; do # # # get ip addresses # # ip_block=${containers_ip_cidr[$j]} echo -e " ${BOLD}${WHITE} + ${YELLOW2}${ip_block}${END}" # # # Masquerade outbound connections from containers # # check rules with: # sudo iptables -C POSTROUTING -t nat ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE # sudo iptables -C POSTROUTING -t nat -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE # # if ! `sudo ${path_iptables4} -C POSTROUTING -t nat ! -o ${docker0_eth} -s ${ip_block} -j MASQUERADE &>/dev/null`; then sudo ${path_iptables4} -t nat -A POSTROUTING ! -o ${docker0_eth} -s ${ip_block} -j MASQUERADE echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-t nat -A POSTROUTING ! -o ${docker0_eth} -s ${ip_block} -j MASQUERADE${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -t nat -A POSTROUTING ! -o ${docker0_eth} -s ${ip_block} -j MASQUERADE${END}" fi if ! `sudo ${path_iptables4} -C POSTROUTING -t nat -s ${ip_block} ! -o ${docker0_eth} -j MASQUERADE &>/dev/null`; then sudo ${path_iptables4} -t nat -A POSTROUTING -s ${ip_block} ! -o ${docker0_eth} -j MASQUERADE echo -e " ${GREY1}+ RULE: ${FUCHSIA2}-t nat -A POSTROUTING -s ${ip_block} ! -o ${docker0_eth} -j MASQUERADE${END}" else echo -e " ${GREY1}! RULE: ${YELLOW}SKIP:${FUCHSIA2} -t nat -A POSTROUTING -s ${ip_block} ! -o ${docker0_eth} -j MASQUERADE${END}" fi done # # # Separator # # echo -e echo -e " ${GREY1}―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――${END}" echo -e # # # Get bridges # # Output: # 7018d23c9bb4 # 2e0fde4b0664 # # echo -e " ${BOLD}${GREY1}+ BRIDGES ${WHITE}Configuring network bridges${END}" bridges=`docker network ls -q --filter='Driver=bridge'` bridge_ids=`docker network ls -q --filter driver=bridge --format "{{.ID}}"` for cont_bridge in $bridges; do # # # Output: # BRIDGE ............... : 242441c7d76c # DOCKER_NET_INT_1 ..... : docker0 # SUBNET ............... : 172.17.0.0/16 # # cont_bridge_name=`docker network inspect -f '{{"'br-$cont_bridge'" | or (index .Options "com.docker.network.bridge.name")}}' $cont_bridge` subnet=`docker network inspect -f '{{(index .IPAM.Config 0).Subnet}}' $cont_bridge` printf '\n%-17s %-35s %-55s' " " "${GREY1}BRIDGE" "${BLUE2}${cont_bridge}${END}" printf '\n%-17s %-35s %-55s' " " "${GREY1}DOCKER INTERFACE" "${BLUE2}${cont_bridge_name}${END}" printf '\n%-17s %-35s %-55s' " " "${GREY1}SUBNET" "${BLUE2}${subnet}${END}" echo -e add_to_nat ${cont_bridge_name} ${subnet} add_to_forward ${cont_bridge_name} add_to_docker_isolation ${cont_bridge_name} done # # # Separator # # echo -e echo -e " ${GREY1}―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――${END}" echo -e # # # Loop containers # # echo -e " ${BOLD}${GREY1}+ CONTAINERS ${WHITE}Configure containers${END}" # # # get all containers from docker # # containers=`docker ps -q` # # # count docker containers; must be greater than 1 # # if [ `echo ${containers} | wc -c` -gt "1" ]; then # # # Loop containers # # for cont_id in ${containers}; do # # # Output: # CONTAINER ............... : 5b251b810e7d # NETMODE ................. : 63599565ed58b275d60087e218e2875aec3c3258976433d061721f0cb666e0b8 # # Example: # Running `docker inspect -f "{{.HostConfig.NetworkMode}}" 5b251b810e7d` outputs: # 63599565ed58b275d60087e218e2875aec3c3258976433d061721f0cb666e0b8 # # cont_netmode=`docker inspect -f "{{.HostConfig.NetworkMode}}" ${cont_id}` cont_network=`docker inspect -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}' ${cont_id}` cont_network_list=`docker inspect -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s " $net}}{{end}}' ${cont_id}` cont_network_json=`docker inspect -f "{{json .NetworkSettings.Networks}}" ${cont_id}` cont_name=`docker inspect -f "{{.Name}}" ${cont_id}` cont_name=${cont_name#/} # remove forward slash cont_name=$(echo "$cont_name" | sed "s/ //g") # remove spaces cont_iflink=`docker exec -i "$cont_id" bash -c 'cat /sys/class/net/eth0/iflink' 2> /dev/null` cont_shell="Bash" err_bash_notfound=`echo "$cont_iflink" 2> /dev/null | grep -c "exec failed"` # # # Bash Not Found # # if [[ "$err_bash_notfound" == "1" ]]; then cont_iflink=`docker exec -it "$cont_id" sh -c 'cat /sys/class/net/eth0/iflink' 2>/dev/null` err_sh_notfound=`echo "$cont_iflink" 2> /dev/null | grep -c "exec failed"` # # # Sh Not Found # # if [[ "$err_sh_notfound" == "1" ]]; then cont_shell="Unknown" cont_iflink="Unknown" else cont_iflink=`echo "$cont_iflink" | sed 's/[^0-9]*//g'` cont_shell="SH" fi else cont_iflink=`echo "$cont_iflink" | sed 's/[^0-9]*//g'` fi # # # Container > Running # # cont_status=$(docker ps --format '{{.Names}}' | grep -c "^${cont_name}$") if [ "$( docker container inspect -f '{{.State.Running}}' $cont_name )" != "true" ]; then cont_iflink="Not running" fi if [ -z "${cont_iflink}" ]; then cont_iflink="Unresponsive" fi # # # Get veth network interface # # if [ -n "${cont_iflink}" ]; then cont_veth=$(sudo grep -l -s "$cont_iflink" /sys/class/net/veth*/ifindex) cont_veth=`echo "$cont_veth" | sed -e 's;^.*net/\(.*\)/ifindex$;\1;'` if [ -z "${cont_veth}" ]; then cont_veth="Unknown" fi fi # # # Chart Truncation # # cont_name_chart=$(trim "$cont_name" 20 "...") cont_network_list_chart=$(trim "$cont_network_list" 50 "...") cont_network_mode_chart=$(trim "$cont_netmode" 18 "...") cont_network_ip_chart="Not Found" cont_network_list="$cont_network" declare -a cont_network_arr=( $cont_network ) # # # Netmode > Default # # if [ $cont_netmode == "default" ]; then cont_bridge_name=${docker0_eth} cont_ipaddr=`docker inspect -f "{{.NetworkSettings.IPAddress}}" ${cont_id}` cont_network_ip_chart="$cont_ipaddr" # # # Netmode > Other # # else # Loop Networks while IFS= read -r cont_network_list; do # cont_bridge_name=`docker inspect -f "{{with index .NetworkSettings.Networks \"bridge\"}}{{.NetworkID}}{{end}}" cb9a6ae9c19e | cut -c -12` cont_bridge=$(docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network_list}\"}}{{.NetworkID}}{{end}}" ${cont_id} | cut -c -12) # 2e0fde4b0664 # docker network inspect -f {{"br-e95004d90f8d" | or (index .Options "com.docker.network.bridge.name")}} e95004d90f8d cont_bridge_name=`docker network inspect -f '{{"'br-$cont_bridge'" | or (index .Options "com.docker.network.bridge.name")}}' $cont_bridge` # br-2e0fde4b0664 cont_ipaddr=`docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network_list}\"}}{{.IPAddress}}{{end}}" ${cont_id}` # 172.18.0.13 cont_ipaddr_orig=${cont_ipaddr} # 172.18.0.13 cont_network_ip_chart="$cont_ipaddr" # 172.18.0.13 if [ -z "${cont_bridge}" ]; then cont_bridge="${RED2}Not found${END}"; fi if [ -z "${cont_bridge_name}" ]; then cont_bridge_name="${RED2}Not found${END}"; fi if [ -z "${cont_ipaddr}" ]; then cont_ipaddr="${RED2}Not found${END}"; cont_network_ip_chart="Not Found"; fi done <<< "$cont_network_list" fi # # # List each container # # echo -e echo " ${GREY1} ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐${END}" echo " ${GREY1} │ │" printf '%-17s %-30s %-38s %-26s %-33s %-33s %-30s %-40s %-50s' \ " " \ "${GREY2} Container${END}" \ "${GREY2} Name" \ "${GREY2} Shell${END}" \ "${GREY2} IP${END}" \ "${GREY2} IfLink ID${END}" \ "${GREY2} Veth Adapter${END}" \ "${GREY2} Network Mode${END}" \ "${GREY2} Network List${END}" printf '\n%-17s %-30s %-38s %-26s %-33s %-33s %-30s %-40s %-50s' \ " " \ "${GREY2} ${cont_id}${END}" \ "${GREY2} ${cont_name_chart}" \ "${GREY2} ${cont_shell}${END}" \ "${GREY2} ${cont_network_ip_chart}${END}" \ "${GREY2} ${cont_iflink}${END}" \ "${GREY2} ${cont_veth}${END}" \ "${GREY2} ${cont_network_mode_chart}${END}" \ "${GREY2} [${#cont_network_arr[@]}] ${cont_network_list_chart}${END}" echo -e echo " ${GREY1} │ │" echo " ${GREY1} └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘${END}" # # # Netmode > Default # # if [ $cont_netmode == "default" ]; then cont_bridge_name=${docker0_eth} # This will return empty if IP manually assigned from docker-compose.yml for container # docker inspect -f "{{.NetworkSettings.IPAddress}}" 5b251b810e7d cont_ipaddr=`docker inspect -f "{{.NetworkSettings.IPAddress}}" ${cont_id}` # # # Netmode > Other # # else # # # return all container info # sudo docker inspect -f '' badaaca1d5da # # # # # network_adapter=$(docker container inspect -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}' ${container}) # # RETURNS: # 'traefik' # # # # # should return: # 2e0fde4b0664 # # # Loop Network while IFS= read -r cont_network; do printf '\n%-17s %-46s' " " "${GREY1}│ ${END}" cont_bridge=$(docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network}\"}}{{.NetworkID}}{{end}}" ${cont_id} | cut -c -12) # # # should return: # br-2e0fde4b0664 # # cont_bridge_name=`docker network inspect -f '{{"'br-$cont_bridge'" | or (index .Options "com.docker.network.bridge.name")}}' $cont_bridge` # # # should return: # 172.18.0.7 (or any other IP) # # cont_ipaddr=`docker inspect -f "{{with index .NetworkSettings.Networks \"${cont_network}\"}}{{.IPAddress}}{{end}}" ${cont_id}` cont_ipaddr_orig=${cont_ipaddr} if [ -z "${cont_bridge}" ]; then cont_bridge="${RED2}Not found${END}"; fi if [ -z "${cont_bridge_name}" ]; then cont_bridge_name="${RED2}Not found${END}"; fi if [ -z "${cont_ipaddr}" ]; then cont_ipaddr="${RED2}Not found${END}"; fi printf '\n%-17s %-46s %-55s' " " "${GREY1}├── ${GREY1}BRIDGE" "${BLUE2}${cont_bridge_name}${END}" # printf '\n%-17s %-46s %-55s' " " "${GREY1}├── ${GREY1}DOCKER_NET" "${BLUE2}${cont_bridge_name}${END}" printf '\n%-17s %-46s %-55s' " " "${GREY1}├── ${GREY1}IP" "${BLUE2}${cont_ipaddr}${END}" if [ "${cfg_dev_enabled}" == "true" ]; then echo -e " ${GREY1}docker inspect -f \"{{with index .NetworkSettings.Networks \"${cont_network}\"}}{{.NetworkID}}{{end}}\" ${cont_id} | cut -c -12${END}" echo -e " ${GREY1}docker network inspect -f '{{\"'br-$cont_bridge'\" | or (index .Options \"com.docker.network.bridge.name\")}}' ${cont_bridge}${END}" echo -e " ${GREY1}docker inspect -f '{{with index .NetworkSettings.Networks \"${cont_network}\"}}{{.IPAddress}}{{end}}' ${cont_id}${END}" fi done <<< "$cont_network" fi # # # CHeck if containers IP is currently in CSF allow list /etc/csf/csf.allow # # if [[ -n "${cont_ipaddr}" ]] && [[ "$cont_ipaddr" != "${RED2}Not found${END}" ]]; then if sudo grep -q "\b${cont_ipaddr}\b" ${file_csf_allow}; then printf '\n%-17s %-46s %-55s' " " "${GREY1}└── ${GREY1}WHITELIST" "${YELLOW2}Already whitelisted in: ${END}${file_csf_allow}${END}" else # # # Found CSF binary, add container IP to allow list /etc/csf/csf.allow # # if [[ $csf_path ]]; then printf '\n%-17s %-46s %-55s' " " "${GREY1}└── ${GREY1}WHITELIST" "${GREEN2}Adding ${cont_ipaddr} to allow list ${file_csf_allow}${END}" # $csf_path -a ${cont_ipaddr} ${csf_comment} >/dev/null 2>&1 fi fi else printf '\n%-17s %-46s %-55s' " " "${GREY1}└── ${GREY1}WHITELIST" "${RED2}Found blank IP, cannot be added to ${file_csf_allow}${END}" fi # # # 22/tcp->0.0.0.0:22 # 22/tcp->[::]:22 # 80/tcp->0.0.0.0:80 # 80/tcp->[::]:80 # 443/tcp->0.0.0.0:443 # 443/tcp->[::]:443 # 2222/tcp->0.0.0.0:2222 # 2222/tcp->[::]:2222 # # rules=`docker port ${cont_id} | sed 's/ //g'` # # # manage ip:port rules # # if [ `echo ${rules} | wc -c` -gt "1" ]; then for rule in ${rules}; do # # # pull ip:port from each rule and format it appropriately # # src=`echo ${rule} | awk -F'->' '{ print $2 }'` dst=`echo ${rule} | awk -F'->' '{ print $1 }'` src_ip=`echo ${src} | sed 's|^\(.*\):.*$|\1|'` src_port=`echo ${src} | awk -F':' '{ print $2 }'` dst_port=`echo ${dst} | awk -F'/' '{ print $1 }'` dst_proto=`echo ${dst} | awk -F'/' '{ print $2 }'` # # # SOURCE 0.0.0.0:22 # DESTINATION 22/tcp # PORT 22 # PROTOTYPE tcp # # printf '\n%-17s %-46s' " " "${GREY1}│ ${END}" printf '\n%-17s %-46s %-55s' " " "${GREY1}├── ${GREY1}SOURCE" "${FUCHSIA2}${src}${END}" printf '\n%-17s %-46s %-55s' " " "${GREY1}└── ${GREY1}DESTINATION" "${FUCHSIA2}${dst}${END}" # printf '\n%-17s %-35s %-55s' " " "${GREY1}PORT" "${FUCHSIA2}${dst_port}${END}" # printf '\n%-17s %-35s %-55s' " " "${GREY1}PROTOTYPE" "${FUCHSIA2}${dst_proto}${END}" echo -e # # # IPTABLE RULE > Add container ip:port for each entry # # sudo ${path_iptables4} -A DOCKER -d ${cont_ipaddr}/32 ! -i ${cont_bridge_name} -o ${cont_bridge_name} -p ${dst_proto} -m ${dst_proto} --dport ${dst_port} -j ACCEPT sudo ${path_iptables4} -t nat -A POSTROUTING -s ${cont_ipaddr}/32 -d ${cont_ipaddr}/32 -p ${dst_proto} -m ${dst_proto} --dport ${dst_port} -j MASQUERADE echo -e " ${GREY1} ├── + RULE: ${GREY1}-A DOCKER -d ${cont_ipaddr}/32 ! -i ${cont_bridge_name} -o ${cont_bridge_name} -p ${dst_proto} -m ${dst_proto} --dport ${dst_port} -j ACCEPT${END}" echo -e " ${GREY1} ├── + RULE: ${GREY1}-t nat -A POSTROUTING -s ${cont_ipaddr}/32 -d ${cont_ipaddr}/32 -p ${dst_proto} -m ${dst_proto} --dport ${dst_port} -j MASQUERADE${END}" # # # Support for IPv4 # # iptables_opt_src="" if [ ${src_ip} != "0.0.0.0" ]; then iptables_opt_src="-d ${src_ip}/32 " fi if [[ ${src_ip} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then sudo ${path_iptables4} -t nat -A DOCKER ${iptables_opt_src}! -i ${cont_bridge_name} -p ${dst_proto} -m ${dst_proto} --dport ${src_port} -j DNAT --to-destination ${cont_ipaddr}:${dst_port} echo -e " ${GREY1} └── + RULE: ${GREY1}-t nat -A DOCKER ${iptables_opt_src}! -i ${cont_bridge_name} -p ${dst_proto} -m ${dst_proto} --dport ${src_port} -j DNAT --to-destination ${cont_ipaddr}:${dst_port}${END}" fi done fi echo -e echo -e done fi echo -e echo -e # # # DOCKER-ISOLATION-STAGE # # echo " ${GREY1} ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐${END}" echo -e " ${BOLD}${GREY1}+ RULES │ ${WHITE}Add DOCKER-ISOLATION-STAGE & DOCKER-USER rules${GREY1} │" echo " ${GREY1} └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘${END}" chain_docker_iso_stage_1_exiss=`sudo ${path_iptables4} -nvL DOCKER-ISOLATION-STAGE-1 2> /dev/null | grep "RETURN" | grep -c "0.0.0.0/0"` chain_docker_iso_stage_2_exiss=`sudo ${path_iptables4} -nvL DOCKER-ISOLATION-STAGE-2 2> /dev/null | grep "RETURN" | grep -c "0.0.0.0/0"` chain_docker_user_exiss=`sudo ${path_iptables4} -nvL DOCKER-USER 2> /dev/null | grep "RETURN" | grep -c "0.0.0.0/0"` if [[ "$chain_docker_iso_stage_1_exiss" == "0" ]]; then printf '\n%-17s %-29s %-55s' " " "${GREY1}+ RULE" "${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-1 -j RETURN${END}" sudo ${path_iptables4} -A DOCKER-ISOLATION-STAGE-1 -j RETURN else printf '\n%-17s %-29s %-55s' " " "${GREY1}! RULE" "${END}Already exists: ${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-1 -j RETURN${END} already exists ${END}" fi if [[ "$chain_docker_iso_stage_2_exiss" == "0" ]]; then printf '\n%-17s %-29s %-55s' " " "${GREY1}+ RULE" "${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-2 -j RETURN${END}" sudo ${path_iptables4} -A DOCKER-ISOLATION-STAGE-2 -j RETURN else printf '\n%-17s %-29s %-55s' " " "${GREY1}! RULE" "${END}Already exists: ${FUCHSIA2}-A DOCKER-ISOLATION-STAGE-2 -j RETURN${END} already exists ${END}" fi if [[ "$chain_docker_user_exiss" == "0" ]]; then printf '\n%-17s %-29s %-55s' " " "${GREY1}+ RULE" "${FUCHSIA2}-A DOCKER-USER -j RETURN${END}" sudo ${path_iptables4} -A DOCKER-USER -j RETURN else printf '\n%-17s %-29s %-55s' " " "${GREY1}! RULE" "${END}Already exists: ${FUCHSIA2}-A DOCKER-USER -j RETURN${END}" fi # # # Check if docker0 inside DOCKER chain # # printf '\n%-17s %-29s %-55s' " " "${GREY1}+ TASK" "${FUCHSIA2}Checking ${END}${docker0_eth}${FUCHSIA2} status${END}" if [ `sudo ${path_iptables4} -t nat -nvL DOCKER 2> /dev/null | grep ${docker0_eth} | wc -l` -eq 0 ]; then sudo ${path_iptables4} -t nat -I DOCKER -i ${docker0_eth} -j RETURN printf '\n%-17s %-29s %-55s' " " "${GREY1}+ RULE" "${FUCHSIA2}-t nat -I DOCKER -i ${docker0_eth} -j RETURN${END}" else printf '\n%-17s %-29s %-55s' " " "${GREY1}! RULE" "${END}Already exists: ${FUCHSIA2}-t nat -I DOCKER -i ${docker0_eth} -j RETURN${END}" fi echo -e echo -e