From 5d275f5e7299c3cc16a4cbca955e02e58d0e7e10 Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Thu, 6 Feb 2025 21:45:16 +0800 Subject: [PATCH] dockerd: refactoring uciadd and ucidel handling --- utils/dockerd/Makefile | 4 + utils/dockerd/files/dockerd.init | 2 +- utils/dockerd/files/dockerd.sh | 247 +++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+), 1 deletion(-) create mode 100755 utils/dockerd/files/dockerd.sh diff --git a/utils/dockerd/Makefile b/utils/dockerd/Makefile index 83987614..ecee250d 100644 --- a/utils/dockerd/Makefile +++ b/utils/dockerd/Makefile @@ -151,6 +151,10 @@ define Package/dockerd/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/dockerd.init $(1)/etc/init.d/dockerd + + if [ ! -f $(TOPDIR)/feeds/luci/package.json ]; then \ + $(INSTALL_BIN) ./files/dockerd.sh $(1)/etc/init.d/dockerd; \ + fi $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./files/etc/config/dockerd $(1)/etc/config/dockerd diff --git a/utils/dockerd/files/dockerd.init b/utils/dockerd/files/dockerd.init index 1ad853f6..111e2cd8 100755 --- a/utils/dockerd/files/dockerd.init +++ b/utils/dockerd/files/dockerd.init @@ -65,7 +65,7 @@ uciadd() { logger -t "dockerd-init" -p notice "Adding interface '${iface}' to network config" uci_quiet add network interface uci_quiet rename network.@interface[-1]="${iface}" - uci_quiet set network.@interface[-1].ifname="${device}" + uci_quiet set network.@interface[-1].device="${device}" uci_quiet set network.@interface[-1].proto="none" uci_quiet set network.@interface[-1].auto="0" uci_quiet commit network diff --git a/utils/dockerd/files/dockerd.sh b/utils/dockerd/files/dockerd.sh new file mode 100755 index 00000000..d3709f33 --- /dev/null +++ b/utils/dockerd/files/dockerd.sh @@ -0,0 +1,247 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=99 + +extra_command "uciadd" " Add docker bridge configuration to network and firewall uci config" +extra_command "ucidel" " Delete docker bridge configuration from network and firewall uci config" + +DOCKER_CONF_DIR="/tmp/dockerd" +DOCKERD_CONF="${DOCKER_CONF_DIR}/daemon.json" + +uci_quiet() { + uci -q "${@}" >/dev/null +} + +json_add_array_string() { + json_add_string "" "${1}" +} + +boot() { + uciadd + rc_procd start_service +} + +uciadd() { + local iface="${1}" + local device="${2}" + local zone="${3}" + + [ -z "${iface}" ] && { + iface="docker" + device="docker0" + zone="docker" + } + + /etc/init.d/dockerd running && { + echo "Please stop dockerd service first" + exit 0 + } + + # Add network interface + if ! uci_quiet get network.${iface}; then + logger -t "dockerd-init" -p notice "Adding docker default interface to network uci config (${iface})" + uci_quiet add network interface + uci_quiet rename network.@interface[-1]="${iface}" + uci_quiet set network.@interface[-1].ifname="${device}" + uci_quiet set network.@interface[-1].proto="none" + uci_quiet set network.@interface[-1].auto="0" + uci_quiet commit network + fi + + # Add docker bridge device + if ! uci_quiet get network.${device}; then + logger -t "dockerd-init" -p notice "Adding docker default bridge device to network uci config (${device})" + uci_quiet add network device + uci_quiet rename network.@device[-1]="${device}" + uci_quiet set network.@device[-1].type="bridge" + uci_quiet set network.@device[-1].name="${device}" + uci_quiet add_list network.@device[-1].ifname="${device}" + uci_quiet commit network + fi + + # Add firewall zone + if ! uci_quiet get firewall.${zone}; then + logger -t "dockerd-init" -p notice "Adding docker default firewall zone to firewall uci config (${zone})" + uci_quiet add firewall zone + uci_quiet rename firewall.@zone[-1]="${zone}" + uci_quiet set firewall.@zone[-1].network="${iface}" + uci_quiet set firewall.@zone[-1].input="ACCEPT" + uci_quiet set firewall.@zone[-1].output="ACCEPT" + uci_quiet set firewall.@zone[-1].forward="ACCEPT" + uci_quiet set firewall.@zone[-1].name="${zone}" + uci_quiet commit firewall + fi + + reload_config +} + +ucidel() { + local iface="${1}" + local device="${2}" + local zone="${3}" + + [ -z "${iface}" ] && { + iface="docker" + device="docker0" + zone="docker" + } + + /etc/init.d/dockerd running && { + echo "Please stop dockerd service first" + exit 0 + } + + if uci_quiet get network.${device}; then + logger -t "dockerd-init" -p notice "Deleting docker default bridge device from network uci config (${device})" + uci_quiet delete network.${device} + uci_quiet commit network + fi + + if uci_quiet get network.${iface}; then + logger -t "dockerd-init" -p notice "Deleting docker default interface from network uci config (${iface})" + uci_quiet delete network.${iface} + uci_quiet commit network + fi + + if uci_quiet get firewall.${zone}; then + logger -t "dockerd-init" -p notice "Deleting docker firewall zone from firewall uci config (${zone})" + uci_quiet delete firewall.${zone} + uci_quiet commit firewall + fi + + reload_config +} + +process_config() { + local alt_config_file data_root log_level iptables bip + + [ -f /etc/config/dockerd ] || { + # Use the daemon default configuration + DOCKERD_CONF="" + return 0 + } + + # reset configuration + rm -fr "${DOCKER_CONF_DIR}" + mkdir -p "${DOCKER_CONF_DIR}" + + config_load 'dockerd' + config_get alt_config_file globals alt_config_file + [ -n "${alt_config_file}" ] && [ -f "${alt_config_file}" ] && { + ln -s "${alt_config_file}" "${DOCKERD_CONF}" + return 0 + } + + config_get data_root globals data_root "/opt/docker/" + config_get log_level globals log_level "warn" + config_get_bool iptables globals iptables "1" + + # Don't add these options by default + # omission == docker defaults + config_get bip globals bip "" + config_get registry_mirrors globals registry_mirrors "" + config_get hosts globals hosts "" + config_get dns globals dns "" + config_get_bool ipv6 globals ipv6 "" + config_get ip globals ip "" + config_get fixed_cidr globals fixed_cidr "" + config_get fixed_cidr_v6 globals fixed_cidr_v6 "" + + . /usr/share/libubox/jshn.sh + json_init + json_add_string "data-root" "${data_root}" + json_add_string "log-level" "${log_level}" + json_add_boolean "iptables" "${iptables}" + [ -z "${bip}" ] || json_add_string "bip" "${bip}" + [ -z "${registry_mirrors}" ] || json_add_array "registry-mirrors" + [ -z "${registry_mirrors}" ] || config_list_foreach globals registry_mirrors json_add_array_string + [ -z "${registry_mirrors}" ] || json_close_array + [ -z "${hosts}" ] || json_add_array "hosts" + [ -z "${hosts}" ] || config_list_foreach globals hosts json_add_array_string + [ -z "${hosts}" ] || json_close_array + [ -z "${dns}" ] || json_add_array "dns" + [ -z "${dns}" ] || config_list_foreach globals dns json_add_array_string + [ -z "${dns}" ] || json_close_array + [ -z "${ipv6}" ] || json_add_boolean "ipv6" "${ipv6}" + [ -z "${ip}" ] || json_add_string "ip" "${ip}" + [ -z "${fixed_cidr}" ] || json_add_string "fixed-cidr" "${fixed_cidr}" + [ -z "${fixed_cidr_v6}" ] || json_add_string "fixed-cidr-v6" "${fixed_cidr_v6}" + json_dump > "${DOCKERD_CONF}" + + [ "${iptables}" -eq "1" ] && config_foreach iptables_add_blocking_rule firewall +} + +start_service() { + local nofile=$(cat /proc/sys/fs/nr_open) + + process_config + + procd_open_instance + procd_set_param stderr 1 + if [ -z "${DOCKERD_CONF}" ]; then + procd_set_param command /usr/bin/dockerd + else + procd_set_param command /usr/bin/dockerd --config-file="${DOCKERD_CONF}" + fi + procd_set_param limits nofile="${nofile} ${nofile}" + procd_close_instance +} + +reload_service() { + process_config + procd_send_signal dockerd +} + +service_triggers() { + procd_add_reload_trigger 'dockerd' +} + +iptables_add_blocking_rule() { + local cfg="${1}" + + local device="" + local extra_iptables_args="" + + handle_iptables_rule() { + local interface="${1}" + local outbound="${2}" + local extra_iptables_args="${3}" + + local inbound="" + + . /lib/functions/network.sh + network_get_physdev inbound "${interface}" + + [ -z "${inbound}" ] && { + logger -t "dockerd-init" -p notice "Unable to get physical device for interface ${interface}" + return + } + + # Wait for a maximum of 10 second per command, retrying every millisecond + local iptables_wait_args="--wait 10 --wait-interval 1000" + + # Ignore errors as it might already be present + iptables ${iptables_wait_args} --table filter --new DOCKER-USER 2>/dev/null + if ! iptables ${iptables_wait_args} --table filter --check DOCKER-USER --in-interface "${inbound}" --out-interface "${outbound}" ${extra_iptables_args} --jump REJECT 2>/dev/null; then + logger -t "dockerd-init" -p notice "Drop traffic from ${inbound} to ${outbound}" + iptables ${iptables_wait_args} --table filter --insert DOCKER-USER --in-interface "${inbound}" --out-interface "${outbound}" ${extra_iptables_args} --jump REJECT + fi + } + + config_get device "${cfg}" device + + [ -z "${device}" ] && { + logger -t "dockerd-init" -p notice "No device configured for ${cfg}" + return + } + + config_get extra_iptables_args "${cfg}" extra_iptables_args + config_list_foreach "${cfg}" blocked_interfaces handle_iptables_rule "${device}" "${extra_iptables_args}" +} + +stop_service() { + if /etc/init.d/dockerd running; then + service_stop "/usr/bin/dockerd" + fi +}