Compare commits

..

No commits in common. "master" and "210925" have entirely different histories.

6 changed files with 79 additions and 246 deletions

View file

@ -1,35 +0,0 @@
name: Build Images
on:
push:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Log into DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ github.actor }}/ufw-docker-agent
- name: Build and push
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64/v8
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View file

@ -1,18 +1,18 @@
FROM ubuntu:24.04 FROM ubuntu:20.04
ARG docker_version="27.3.1" ARG docker_version="19.03.12"
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y ca-certificates curl gnupg lsb-release \ && apt-get install -y --no-install-recommends apt-transport-https \
&& mkdir -p /etc/apt/keyrings \ ca-certificates curl software-properties-common gnupg dirmngr \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \ && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg]" \ && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
"https://download.docker.com/linux/ubuntu" "$(lsb_release -cs) stable" \ $(lsb_release -cs) stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends locales ufw \ && apt-get install -y --no-install-recommends locales ufw \
&& apt-get install -y --no-install-recommends "docker-ce=$(apt-cache madison docker-ce | grep -m1 -F "${docker_version}" | cut -d'|' -f2 | tr -d '[[:blank:]]')" \ && ( apt-get install -y --no-install-recommends "docker-ce=5:${docker_version}~*" || \
apt-get install -y --no-install-recommends "docker-ce=${docker_version}~*" ) \
&& locale-gen en_US.UTF-8 \ && locale-gen en_US.UTF-8 \
&& apt-get clean autoclean \ && apt-get clean autoclean \
&& apt-get autoremove --yes \ && apt-get autoremove --yes \

77
Vagrantfile vendored
View file

@ -3,29 +3,16 @@
# -*- mode: ruby -*- # -*- mode: ruby -*-
# vi: set ft=ruby : # vi: set ft=ruby :
ENV['VAGRANT_NO_PARALLEL']="true"
Vagrant.configure('2') do |config| Vagrant.configure('2') do |config|
ubuntu_version = File.readlines("Dockerfile").filter { |line|
line.start_with?("FROM ")
}.first.match(/\d\d\.\d\d/)[0]
docker_version = File.readlines("Dockerfile").filter { |line| config.vm.box = "chaifeng/ubuntu-20.04-docker-19.03.13"
line.start_with?("ARG docker_version=") #config.vm.box = "chaifeng/ubuntu-16.04-docker-18.03"
}.first.match(/"([\d\.]+)"/)[1]
config.vm.box = "chaifeng/ubuntu-#{ubuntu_version}-docker-#{docker_version}"
config.vm.provider 'virtualbox' do |vb| config.vm.provider 'virtualbox' do |vb|
vb.memory = '1024' vb.memory = '1024'
vb.default_nic_type = "virtio" vb.default_nic_type = "virtio"
end end
config.vm.provider 'parallels' do |prl|
prl.memory = '1024'
prl.check_guest_tools = false
end
ip_prefix="192.168.56" ip_prefix="192.168.56"
config.vm.provision 'docker-daemon-config', type: 'shell', inline: <<-SHELL config.vm.provision 'docker-daemon-config', type: 'shell', inline: <<-SHELL
@ -70,16 +57,15 @@ Vagrant.configure('2') do |config|
private_registry="#{ip_prefix}.130:5000" private_registry="#{ip_prefix}.130:5000"
config.vm.define "master" do |master| config.vm.define "master" do |master|
master_ip_address = "#{ip_prefix}.130"
master.vm.hostname = "master" master.vm.hostname = "master"
master.vm.network "private_network", ip: "#{master_ip_address}" master.vm.network "private_network", ip: "#{ip_prefix}.130"
master.vm.provision "unit-testing", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "unit-testing", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
/vagrant/test.sh /vagrant/test.sh
SHELL SHELL
master.vm.provision "docker-registry", preserve_order: true, type: 'docker' do |d| master.vm.provision "docker-registry", type: 'docker' do |d|
d.run "registry", d.run "registry",
image: "registry:2", image: "registry:2",
args: "-p 5000:5000", args: "-p 5000:5000",
@ -87,38 +73,35 @@ Vagrant.configure('2') do |config|
daemonize: true daemonize: true
end end
ufw_docker_agent_image = "#{private_registry}/chaifeng/ufw-docker-agent:test-legacy" ufw_docker_agent_image = "#{private_registry}/chaifeng/ufw-docker-agent:test"
master.vm.provision "docker-build-ufw-docker-agent", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "docker-build-ufw-docker-agent", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
suffix="$(iptables --version | grep -o '\\(nf_tables\\|legacy\\)')" docker build -t #{ufw_docker_agent_image} /vagrant
docker build -t "#{ufw_docker_agent_image}-${suffix}" /vagrant docker push #{ufw_docker_agent_image}
docker push "#{ufw_docker_agent_image}-${suffix}"
echo "export UFW_DOCKER_AGENT_IMAGE=#{ufw_docker_agent_image}-${suffix}" > /etc/profile.d/ufw-docker.sh echo "export UFW_DOCKER_AGENT_IMAGE=#{ufw_docker_agent_image}" > /etc/profile.d/ufw-docker.sh
echo "export DEBUG=true" >> /etc/profile.d/ufw-docker.sh echo "export DEBUG=true" >> /etc/profile.d/ufw-docker.sh
echo "Defaults env_keep += UFW_DOCKER_AGENT_IMAGE" > /etc/sudoers.d/98_ufw-docker echo "Defaults env_keep += UFW_DOCKER_AGENT_IMAGE" > /etc/sudoers.d/98_ufw-docker
echo "Defaults env_keep += DEBUG" >> /etc/sudoers.d/98_ufw-docker echo "Defaults env_keep += DEBUG" >> /etc/sudoers.d/98_ufw-docker
SHELL SHELL
master.vm.provision "swarm-init", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "swarm-init", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
docker info | fgrep 'Swarm: active' && exit 0 docker info | fgrep 'Swarm: active' && exit 0
docker swarm init --advertise-addr "#{master_ip_address}" docker swarm init --advertise-addr eth1
docker swarm join-token worker --quiet > /vagrant/.vagrant/docker-join-token docker swarm join-token worker --quiet > /vagrant/.vagrant/docker-join-token
SHELL SHELL
master.vm.provision "build-webapp", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "build-webapp", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
docker build -t #{private_registry}/chaifeng/hostname-webapp - <<\\DOCKERFILE docker build -t #{private_registry}/chaifeng/hostname-webapp - <<\\DOCKERFILE
FROM httpd:alpine FROM httpd:alpine
RUN { echo '#!/bin/sh'; \\ RUN { echo '#!/bin/sh'; \\
echo 'set -e; (echo -n "${name:-Hi} "; hostname;) > /usr/local/apache2/htdocs/index.html'; \\ echo 'set -e; (echo -n "${name:-Hi} "; hostname;) > /usr/local/apache2/htdocs/index.html'; \\
echo 'grep "^Listen 7000" || echo Listen 7000 >> /usr/local/apache2/conf/httpd.conf'; \\
echo 'grep "^Listen 8080" || echo Listen 8080 >> /usr/local/apache2/conf/httpd.conf'; \\
echo 'exec "$@"'; \\ echo 'exec "$@"'; \\
} > /entrypoint.sh; chmod +x /entrypoint.sh } > /entrypoint.sh; chmod +x /entrypoint.sh
@ -128,7 +111,7 @@ DOCKERFILE
docker push #{private_registry}/chaifeng/hostname-webapp docker push #{private_registry}/chaifeng/hostname-webapp
SHELL SHELL
master.vm.provision "local-webapp", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "local-webapp", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
for name in public:18080 local:8000; do for name in public:18080 local:8000; do
webapp="${name%:*}_webapp" webapp="${name%:*}_webapp"
@ -142,7 +125,7 @@ DOCKERFILE
ufw-docker allow public_webapp ufw-docker allow public_webapp
SHELL SHELL
master.vm.provision "multiple-network", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "multiple-network", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
if ! docker network ls | grep -F foo-internal; then if ! docker network ls | grep -F foo-internal; then
docker network create --internal foo-internal docker network create --internal foo-internal
@ -165,7 +148,7 @@ DOCKERFILE
ufw-docker allow internal-multinet-app 80 foo-internal ufw-docker allow internal-multinet-app 80 foo-internal
SHELL SHELL
master.vm.provision "swarm-webapp", preserve_order: true, type: 'shell', inline: <<-SHELL master.vm.provision "swarm-webapp", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
for name in public:29090 local:9000; do for name in public:29090 local:9000; do
webapp="${name%:*}_service" webapp="${name%:*}_service"
@ -176,14 +159,6 @@ DOCKERFILE
done done
ufw-docker service allow public_service 80/tcp ufw-docker service allow public_service 80/tcp
docker service inspect "public_multiport" ||
docker service create --name "public_multiport" \
--publish "40080:80" --publish "47000:7000" --publish "48080:8080" \
--env name="public_multiport" --replicas 3 #{private_registry}/chaifeng/hostname-webapp
ufw-docker service allow public_multiport 80/tcp
ufw-docker service allow public_multiport 8080/tcp
SHELL SHELL
end end
@ -192,7 +167,7 @@ DOCKERFILE
node.vm.hostname = "node#{ip}" node.vm.hostname = "node#{ip}"
node.vm.network "private_network", ip: "#{ip_prefix}.#{ 130 + ip }" node.vm.network "private_network", ip: "#{ip_prefix}.#{ 130 + ip }"
node.vm.provision "swarm-join", preserve_order: true, type: 'shell', inline: <<-SHELL node.vm.provision "swarm-join", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
docker info | fgrep 'Swarm: active' && exit 0 docker info | fgrep 'Swarm: active' && exit 0
@ -202,25 +177,15 @@ DOCKERFILE
end end
end end
config.vm.define "node-internal" do |node|
node.vm.hostname = "node-internal"
node.vm.network "private_network", ip: "#{ip_prefix}.142"
end
config.vm.define "external" do |external| config.vm.define "external" do |external|
external.vm.hostname = "external" external.vm.hostname = "external"
external.vm.network "private_network", ip: "#{ip_prefix}.127" external.vm.network "private_network", ip: "#{ip_prefix}.127"
external.vm.provision "testing", preserve_order: true, type: 'shell', inline: <<-SHELL external.vm.provision "testing", type: 'shell', inline: <<-SHELL
set -euo pipefail set -euo pipefail
set -x set -x
server="http://#{ip_prefix}.130" server="http://#{ip_prefix}.130"
function test-webapp() { function test-webapp() { timeout 3 curl --silent "$@"; }
if timeout 3 curl --silent "$@"
then echo "Success: $*"
else echo "Cannot visit: $*"; return 1
fi
}
test-webapp "$server:18080" test-webapp "$server:18080"
! test-webapp "$server:8000" ! test-webapp "$server:8000"
@ -230,10 +195,6 @@ DOCKERFILE
test-webapp "$server:29090" test-webapp "$server:29090"
! test-webapp "$server:9000" ! test-webapp "$server:9000"
test-webapp "$server:40080"
test-webapp "$server:48080"
! test-webapp "$server:47000"
echo "=====================" echo "====================="
echo " TEST DONE " echo " TEST DONE "
echo "=====================" echo "====================="

@ -1 +1 @@
Subproject commit 27885eb79c11e4652dede994c886ae5f9e30994f Subproject commit 447edb60db232d3dbc2267f37c49bd7a070cc83d

View file

@ -12,20 +12,12 @@ source "$working_dir"/bach/bach.sh
@mocktrue ufw status @mocktrue ufw status
@mocktrue grep -Fq "Status: active" @mocktrue grep -Fq "Status: active"
@mock iptables --version @ignore remove_blank_lines
@mocktrue grep -F '(legacy)'
@mocktrue docker -v
@mock docker -v === @stdout Docker version 0.0.0, build dummy
@mockpipe remove_blank_lines
@ignore echo @ignore echo
@ignore err @ignore err
DEFAULT_PROTO=tcp DEFAULT_PROTO=tcp
GREP_REGEXP_INSTANCE_NAME="[-_.[:alnum:]]\\+" GREP_REGEXP_INSTANCE_NAME="[-_.[:alnum:]]\\+"
UFW_DOCKER_AGENT_IMAGE=chaifeng/ufw-docker-agent:090502-legacy
} }
function ufw-docker() { function ufw-docker() {
@ -38,41 +30,6 @@ function load-ufw-docker-function() {
@load_function "$working_dir/../ufw-docker" "$1" @load_function "$working_dir/../ufw-docker" "$1"
} }
test-ufw-docker-init-legacy() {
@mocktrue grep -F '(legacy)'
@source <(@sed '/PATH=/d' "$working_dir/../ufw-docker") help
}
test-ufw-docker-init-legacy-assert() {
iptables --version
test -n chaifeng/ufw-docker-agent:090502-legacy
trap on-exit EXIT INT TERM QUIT ABRT ERR
@dryrun cat
}
test-ufw-docker-init-nf_tables() {
@mockfalse grep -F '(legacy)'
@source <(@sed '/PATH=/d' "$working_dir/../ufw-docker") help
}
test-ufw-docker-init-nf_tables-assert() {
iptables --version
test -n chaifeng/ufw-docker-agent:090502-nf_tables
trap on-exit EXIT INT TERM QUIT ABRT ERR
@dryrun cat
}
test-ufw-docker-init() {
UFW_DOCKER_AGENT_IMAGE=chaifeng/ufw-docker-agent:100917
@source <(@sed '/PATH=/d' "$working_dir/../ufw-docker") help
}
test-ufw-docker-init-assert() {
test -n chaifeng/ufw-docker-agent:100917
trap on-exit EXIT INT TERM QUIT ABRT ERR
@dryrun cat
}
test-ufw-docker-help() { test-ufw-docker-help() {
ufw-docker help ufw-docker help
} }
@ -91,23 +48,11 @@ test-ufw-docker-without-parameters-assert() {
test-ufw-is-disabled() { test-ufw-is-disabled() {
@mockfalse grep -Fq "Status: active" @mockfalse grep -Fq "Status: active"
@mock iptables --version === @stdout 'iptables v1.8.4 (legacy)'
ufw-docker ufw-docker
} }
test-ufw-is-disabled-assert() { test-ufw-is-disabled-assert() {
die "UFW is disabled or you are not root user, or mismatched iptables legacy/nf_tables, current iptables v1.8.4 (legacy)" die "UFW is disabled or you are not root user."
ufw-docker--help
}
test-docker-is-installed() {
@mockfalse docker -v
ufw-docker
}
test-docker-is-installed-assert() {
die "Docker executable not found."
ufw-docker--help ufw-docker--help
} }
@ -465,7 +410,7 @@ test-ufw-docker--instance-name-found-a-name() {
} }
test-ufw-docker--instance-name-found-a-name-assert() { test-ufw-docker--instance-name-found-a-name-assert() {
docker inspect --format="{{.Name}}" foo docker inspect --format="{{.Name}}" foo
@dryrun echo -n foo echo -n foo
} }
@ -488,7 +433,7 @@ test-ufw-docker--list-name() {
ufw-docker--list foo ufw-docker--list foo
} }
test-ufw-docker--list-name-assert() { test-ufw-docker--list-name-assert() {
grep "# allow foo\\( [[:digit:]]\\+\\/\\(tcp\\|udp\\)\\)\\( [[:graph:]]*\\)\$" grep "# allow foo\\( [[:digit:]]\\+\\/\\(tcp\\|udp\\)\\)\\?\\( [[:graph:]]*\\)\\?\$"
} }
test-ufw-docker--list-name-udp() { test-ufw-docker--list-name-udp() {
@ -497,7 +442,7 @@ test-ufw-docker--list-name-udp() {
ufw-docker--list foo "" udp ufw-docker--list foo "" udp
} }
test-ufw-docker--list-name-udp-assert() { test-ufw-docker--list-name-udp-assert() {
grep "# allow foo\\( [[:digit:]]\\+\\/\\(tcp\\|udp\\)\\)\\( [[:graph:]]*\\)\$" grep "# allow foo\\( [[:digit:]]\\+\\/\\(tcp\\|udp\\)\\)\\?\\( [[:graph:]]*\\)\\?\$"
} }
@ -507,7 +452,7 @@ test-ufw-docker--list-name-80() {
ufw-docker--list foo 80 ufw-docker--list foo 80
} }
test-ufw-docker--list-name-80-assert() { test-ufw-docker--list-name-80-assert() {
grep "# allow foo\\( 80\\/tcp\\)\\( [[:graph:]]*\\)\$" grep "# allow foo\\( 80\\/tcp\\)\\?\\( [[:graph:]]*\\)\\?\$"
} }
@ -517,30 +462,7 @@ test-ufw-docker--list-name-80-udp() {
ufw-docker--list foo 80 udp ufw-docker--list foo 80 udp
} }
test-ufw-docker--list-name-80-udp-assert() { test-ufw-docker--list-name-80-udp-assert() {
grep "# allow foo\\( 80\\/udp\\)\\( [[:graph:]]*\\)\$" grep "# allow foo\\( 80\\/udp\\)\\?\\( [[:graph:]]*\\)\\?\$"
}
test-ufw-docker--list-grep-without-network() {
@mocktrue ufw status numbered
@mockfalse grep "# allow foo\\( 80\\/udp\\)\\( [[:graph:]]*\\)\$"
load-ufw-docker-function ufw-docker--list
ufw-docker--list foo 80 udp
}
test-ufw-docker--list-grep-without-network-assert() {
grep "# allow foo\\( 80\\/udp\\)\$"
}
test-ufw-docker--list-grep-without-network-and-port() {
@mocktrue ufw status numbered
@mockfalse grep "# allow foo\\( 80\\/udp\\)\\( [[:graph:]]*\\)\$"
@mockfalse grep "# allow foo\\( 80\\/udp\\)\$"
load-ufw-docker-function ufw-docker--list
ufw-docker--list foo 80 udp
}
test-ufw-docker--list-grep-without-network-and-port-assert() {
grep "# allow foo\$"
} }
@ -557,7 +479,7 @@ test-ufw-docker--list-number-assert() {
test-ufw-docker--delete-empty-result() { test-ufw-docker--delete-empty-result() {
@mock ufw-docker--list-number webapp 80 tcp === @stdout "" @mock ufw-docker--list-number webapp 80 tcp === @stdout ""
@mockpipe sort -rn @mock sort -rn
load-ufw-docker-function ufw-docker--delete load-ufw-docker-function ufw-docker--delete
ufw-docker--delete webapp 80 tcp ufw-docker--delete webapp 80 tcp
@ -569,7 +491,7 @@ test-ufw-docker--delete-empty-result-assert() {
test-ufw-docker--delete-all() { test-ufw-docker--delete-all() {
@mock ufw-docker--list-number webapp 80 tcp === @stdout 5 8 9 @mock ufw-docker--list-number webapp 80 tcp === @stdout 5 8 9
@mockpipe sort -rn @mock sort -rn
load-ufw-docker-function ufw-docker--delete load-ufw-docker-function ufw-docker--delete
ufw-docker--delete webapp 80 tcp ufw-docker--delete webapp 80 tcp

View file

@ -5,23 +5,13 @@ set -euo pipefail
LANG=en_US.UTF-8 LANG=en_US.UTF-8
LANGUAGE=en_US: LANGUAGE=en_US:
LC_ALL=en_US.UTF-8 LC_ALL=en_US.UTF-8
PATH="/bin:/usr/bin:/sbin:/usr/sbin:/snap/bin/" PATH="/bin:/usr/bin:/sbin:/usr/sbin"
GREP_REGEXP_INSTANCE_NAME="[-_.[:alnum:]]\\+" GREP_REGEXP_INSTANCE_NAME="[-_.[:alnum:]]\\+"
DEFAULT_PROTO=tcp DEFAULT_PROTO=tcp
ufw_docker_agent=ufw-docker-agent ufw_docker_agent=ufw-docker-agent
ufw_docker_agent_image="${UFW_DOCKER_AGENT_IMAGE:-chaifeng/${ufw_docker_agent}:221002-nf_tables}" ufw_docker_agent_image="${UFW_DOCKER_AGENT_IMAGE:-chaifeng/${ufw_docker_agent}:210925}"
if [[ "${ufw_docker_agent_image}" = *-@(legacy|nf_tables) ]]; then
if iptables --version | grep -F '(legacy)' &>/dev/null; then
ufw_docker_agent_image="${ufw_docker_agent_image%-*}-legacy"
else
ufw_docker_agent_image="${ufw_docker_agent_image%-*}-nf_tables"
fi
fi
test -n "$ufw_docker_agent_image"
function ufw-docker--status() { function ufw-docker--status() {
ufw-docker--list "$GREP_REGEXP_INSTANCE_NAME" ufw-docker--list "$GREP_REGEXP_INSTANCE_NAME"
@ -42,9 +32,7 @@ function ufw-docker--list() {
NETWORK="[[:graph:]]*" NETWORK="[[:graph:]]*"
fi fi
ufw status numbered | grep "# allow ${INSTANCE_NAME}\\( ${INSTANCE_PORT}\\/${PROTO}\\)\\( ${NETWORK}\\)\$" || \ ufw status numbered | grep "# allow ${INSTANCE_NAME}\\( ${INSTANCE_PORT}\\/${PROTO}\\)\\?\\( ${NETWORK}\\)\\?\$"
ufw status numbered | grep "# allow ${INSTANCE_NAME}\\( ${INSTANCE_PORT}\\/${PROTO}\\)\$" || \
ufw status numbered | grep "# allow ${INSTANCE_NAME}\$"
} }
function ufw-docker--list-number() { function ufw-docker--list-number() {
@ -84,11 +72,12 @@ function ufw-docker--allow() {
if [[ -z "$INSTANCE_PORT" || "$PORT_PROTO" = "${INSTANCE_PORT}/${PROTO}" ]]; then if [[ -z "$INSTANCE_PORT" || "$PORT_PROTO" = "${INSTANCE_PORT}/${PROTO}" ]]; then
ITER=0 ITER=0
for IP in "${INSTANCE_IP_ADDRESSES[@]}"; do for IP in "${INSTANCE_IP_ADDRESSES[@]}"; do
INSTANCE_NETWORK="${INSTANCE_NETWORK_NAMES[$ITER]}" INSTANCE_NETWORK="${INSTANCE_NETWORK_NAMES[$ITER]}"
ITER=$((ITER+1)) ITER=$((ITER+1))
if [[ -n "$NETWORK" ]] && [[ "$NETWORK" != "$INSTANCE_NETWORK" ]]; then if [[ -n "$NETWORK" ]] && [[ "$NETWORK" != "$INSTANCE_NETWORK" ]]; then
continue continue
fi fi
ufw-docker--add-rule "$INSTANCE_NAME" "$IP" "${PORT_PROTO%/*}" "${PORT_PROTO#*/}" "${INSTANCE_NETWORK}" ufw-docker--add-rule "$INSTANCE_NAME" "$IP" "${PORT_PROTO%/*}" "${PORT_PROTO#*/}" "${INSTANCE_NETWORK}"
RETVAL="$?" RETVAL="$?"
done done
@ -292,34 +281,34 @@ function ufw-docker--raw-command() {
after_rules="/etc/ufw/after.rules" after_rules="/etc/ufw/after.rules"
function ufw-docker--check() { function ufw-docker--check() {
err "\\n########## iptables -n -L DOCKER-USER ##########" err "\\n########## iptables -n -L DOCKER-USER ##########"
iptables -n -L DOCKER-USER iptables -n -L DOCKER-USER
err "\\n\\n########## diff $after_rules ##########" err "\\n\\n########## diff $after_rules ##########"
ufw-docker--check-install && err "\\nCheck done." ufw-docker--check-install && err "\\nCheck done."
} }
declare -a files_to_be_deleted declare -a files_to_be_deleted
function rm-on-exit() { function rm-on-exit() {
[[ $# -gt 0 ]] && files_to_be_deleted+=("$@") [[ $# -gt 0 ]] && files_to_be_deleted+=("$@")
} }
function on-exit() { function on-exit() {
for file in "${files_to_be_deleted[@]:-}"; do for file in "${files_to_be_deleted[@]:-}"; do
[[ -f "$file" ]] && rm -r "$file" [[ -f "$file" ]] && rm -r "$file"
done done
files_to_be_deleted=() files_to_be_deleted=()
} }
trap on-exit EXIT INT TERM QUIT ABRT ERR trap on-exit EXIT INT TERM QUIT ABRT ERR
function ufw-docker--check-install() { function ufw-docker--check-install() {
after_rules_tmp="${after_rules_tmp:-$(mktemp)}" after_rules_tmp="${after_rules_tmp:-$(mktemp)}"
rm-on-exit "$after_rules_tmp" rm-on-exit "$after_rules_tmp"
sed "/^# BEGIN UFW AND DOCKER/,/^# END UFW AND DOCKER/d" "$after_rules" > "$after_rules_tmp" sed "/^# BEGIN UFW AND DOCKER/,/^# END UFW AND DOCKER/d" "$after_rules" > "$after_rules_tmp"
>> "${after_rules_tmp}" cat <<-\EOF >> "${after_rules_tmp}" cat <<-\EOF
# BEGIN UFW AND DOCKER # BEGIN UFW AND DOCKER
*filter *filter
:ufw-user-forward - [0:0] :ufw-user-forward - [0:0]
@ -349,27 +338,27 @@ function ufw-docker--check-install() {
# END UFW AND DOCKER # END UFW AND DOCKER
EOF EOF
diff -u --color=auto "$after_rules" "$after_rules_tmp" diff -u --color=auto "$after_rules" "$after_rules_tmp"
} }
function ufw-docker--install() { function ufw-docker--install() {
if ! ufw-docker--check-install; then if ! ufw-docker--check-install; then
local after_rules_bak local after_rules_bak
after_rules_bak="${after_rules}-ufw-docker~$(date '+%Y-%m-%d-%H%M%S')~" after_rules_bak="${after_rules}-ufw-docker~$(date '+%Y-%m-%d-%H%M%S')~"
err "\\nBacking up $after_rules to $after_rules_bak" err "\\nBacking up $after_rules to $after_rules_bak"
cp "$after_rules" "$after_rules_bak" cp "$after_rules" "$after_rules_bak"
cat "$after_rules_tmp" > "$after_rules" cat "$after_rules_tmp" > "$after_rules"
err "Please restart UFW service manually by using the following command:" err "Please restart UFW service manually by using the following command:"
if type systemctl &>/dev/null; then if type systemctl &>/dev/null; then
err " sudo systemctl restart ufw" err " sudo systemctl restart ufw"
else else
err " sudo service ufw restart" err " sudo service ufw restart"
fi
fi fi
fi
} }
function ufw-docker--help() { function ufw-docker--help() {
cat <<-EOF >&2 cat <<-EOF >&2
Usage: Usage:
ufw-docker <list|allow> [docker-instance-id-or-name [port[/tcp|/udp]] [network]] ufw-docker <list|allow> [docker-instance-id-or-name [port[/tcp|/udp]] [network]]
ufw-docker delete allow [docker-instance-id-or-name [port[/tcp|/udp]] [network]] ufw-docker delete allow [docker-instance-id-or-name [port[/tcp|/udp]] [network]]
@ -421,11 +410,7 @@ function die() {
# __main__ # __main__
if ! ufw status 2>/dev/null | grep -Fq "Status: active" ; then if ! ufw status 2>/dev/null | grep -Fq "Status: active" ; then
die "UFW is disabled or you are not root user, or mismatched iptables legacy/nf_tables, current $(iptables --version)" die "UFW is disabled or you are not root user."
fi
if ! docker -v &> /dev/null; then
die "Docker executable not found."
fi fi
ufw_action="${1:-help}" ufw_action="${1:-help}"
@ -453,9 +438,9 @@ case "$ufw_action" in
if [[ "$INSTANCE_PORT" = */udp ]]; then if [[ "$INSTANCE_PORT" = */udp ]]; then
PROTO=udp PROTO=udp
fi fi
shift || true shift || true
NETWORK="${1:-}" NETWORK="${1:-}"
INSTANCE_PORT="${INSTANCE_PORT%/*}" INSTANCE_PORT="${INSTANCE_PORT%/*}"