diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000000..c1274a0514f650 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +文件路径:.gitattributes + +文件内容: +# 保持 ZeroTier init 脚本的可执行权限 +net/zerotier/files/etc/init.d/zerotier text eol=lf +net/zerotier/files/etc/init.d/zerotier -crlf + +# 所有 init.d 脚本保持可执行 +net/zerotier/files/etc/init.d/* text eol=lf +net/zerotier/files/etc/init.d/* -crlf + +# 所有脚本文件 +*.sh text eol=lf +*.sh -crlf diff --git a/net/zerotier/Makefile b/net/zerotier/Makefile index ffbab16379d7dd..5c1edc2c8f1490 100644 --- a/net/zerotier/Makefile +++ b/net/zerotier/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=zerotier PKG_VERSION:=1.16.0 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/zerotier/ZeroTierOne/tar.gz/$(PKG_VERSION)? @@ -67,6 +67,8 @@ TARGET_CFLAGS += -isystem $(STAGING_DIR)/usr/include define Package/zerotier/conffiles /etc/config/zerotier +/etc/zerotier.conf +/etc/zerotier endef define Package/zerotier/install @@ -79,7 +81,6 @@ define Package/zerotier/install ifeq ($(CONFIG_ZEROTIER_ENABLE_SELFTEST),y) $(INSTALL_BIN) $(PKG_BUILD_DIR)/zerotier-selftest $(1)/usr/bin/ endif - $(CP) ./files/* $(1)/ endef diff --git a/net/zerotier/files/etc/config/zerotier b/net/zerotier/files/etc/config/zerotier index 879fefe87996b3..086de29f4e2598 100644 --- a/net/zerotier/files/etc/config/zerotier +++ b/net/zerotier/files/etc/config/zerotier @@ -1,7 +1,7 @@ config zerotier 'global' # Sets whether ZeroTier is enabled or not - option enabled 0 + option enabled '0' # Sets the ZeroTier listening port (default 9993; set to 0 for random) #option port '9993' # Client secret (leave blank to generate a secret on first run) @@ -15,10 +15,14 @@ config zerotier 'global' # Copy the contents of the persistent configuration directory to memory # instead of linking it, this avoids writing to flash #option copy_config_path '1' + # Add firewall rules + option fw_allow_input '1' # Network configuration, you can have as many configurations as networks you # want to join (the network name is optional) config network 'earth' + # Sets whether this network is enabled or not + option enabled '0' # Identifier of the network you wish to join option id '8056c2e21c000001' # Network configuration parameters (all are optional, if not indicated the @@ -28,12 +32,24 @@ config network 'earth' option allow_global '0' option allow_default '0' option allow_dns '0' + # Add firewall rules + option fw_allow_input '0' + option fw_allow_forward '0' + # list fw_forward_ifaces '' + option fw_allow_masq '0' + # list fw_masq_ifaces '' # Example of a second network (unnamed as it is optional) #config network +# option enabled '1' # option id '1234567890123456' # option allow_managed '1' # option allow_global '0' # option allow_default '0' # option allow_dns '0' +# option fw_allow_input '1' +# option fw_allow_forward '1' +# list fw_forward_ifaces 'br-lan' +# option fw_allow_masq '1' +# list fw_masq_ifaces 'br-lan' diff --git a/net/zerotier/files/etc/hotplug.d/net/30-zerotier b/net/zerotier/files/etc/hotplug.d/net/30-zerotier new file mode 100644 index 00000000000000..b164e64ca24c76 --- /dev/null +++ b/net/zerotier/files/etc/hotplug.d/net/30-zerotier @@ -0,0 +1,7 @@ +#!/bin/sh + +[ "$ACTION" = "add" ] || exit 0 +echo "$DEVICENAME" | grep -Eq "^zt" || exit 0 + +[ "$(uci -q get zerotier.global.enabled)" = "1" ] || exit 0 +zerotier-fw4 -i "$DEVICENAME" diff --git a/net/zerotier/files/etc/init.d/zerotier b/net/zerotier/files/etc/init.d/zerotier index 01aff425f37cf2..26ea3d3a7469e2 100755 --- a/net/zerotier/files/etc/init.d/zerotier +++ b/net/zerotier/files/etc/init.d/zerotier @@ -1,15 +1,25 @@ #!/bin/sh /etc/rc.common - +# -*- mode: shell-script; sh-indentation: 2; sh-basic-offset: 2; -*- +# +# ZeroTier init script for OpenWrt +# License: GPL +# START=90 USE_PROCD=1 PROG=/usr/bin/zerotier-one CONFIG_PATH=/var/lib/zerotier-one +RUN_PATH=/var/run/zerotier-one + +network_ids="" join_network() { local section="${1}" - local id allow_managed allow_global allow_default allow_dns + local enabled id allow_managed allow_global allow_default allow_dns + + config_get_bool enabled "${section}" 'enabled' '1' + [ ${enabled} -eq 1 ] || return 1 config_get id "${section}" 'id' config_get_bool allow_managed "${section}" 'allow_managed' 1 @@ -24,6 +34,8 @@ join_network() { echo "allowGlobal=${allow_global}" >> "${CONFIG_PATH}"/networks.d/"${id}".local.conf echo "allowDefault=${allow_default}" >> "${CONFIG_PATH}"/networks.d/"${id}".local.conf echo "allowDNS=${allow_dns}" >> "${CONFIG_PATH}"/networks.d/"${id}".local.conf + + network_ids="${network_ids} ${id}" fi } @@ -39,7 +51,7 @@ start_service() { config_get config_path 'global' 'config_path' config_get_bool copy_config_path 'global' 'copy_config_path' 0 - if [ ${enabled} -eq 0 ]; then + if [ "${enabled}" -eq 0 ]; then echo "disabled in /etc/config/zerotier" return fi @@ -48,13 +60,10 @@ start_service() { rm -rf "${CONFIG_PATH}" # Create link or copy files from config_path to CONFIG_PATH - if [ -n "${config_path}" ]; then - if [ ! -d "${config_path}" ]; then - echo "ZeroTier config_path does not exist: ${config_path}" 1>&2 - return - fi + if [ -n "${config_path}" ] && [ "${config_path}" != "${CONFIG_PATH}" ]; then + [ -d "${config_path}" ] || mkdir -p "${config_path}" - if [ ${copy_config_path} -eq 1 ]; then + if [ "${copy_config_path}" -eq 1 ]; then cp -r "${config_path}" "${CONFIG_PATH}" else ln -s "${config_path}" "${CONFIG_PATH}" @@ -64,6 +73,11 @@ start_service() { mkdir -p "${CONFIG_PATH}"/networks.d config_foreach join_network network + # Remove deprecated networks + for conf in "${CONFIG_PATH}"/networks.d/*.conf; do + echo "$network_ids" | grep -q "$(echo "${conf}" | awk -F 'networks.d/|\\.' '{print $2}')" || rm -f "${conf}" + done + if [ -f "${local_conf_path}" ]; then ln -s "${local_conf_path}" "${CONFIG_PATH}"/local.conf fi @@ -74,8 +88,9 @@ start_service() { if [ -z "${secret}" ]; then echo -n "Generating secret - please wait... " - secret="$(zerotier-idtool generate)" - [ ${?} -ne 0 ] && return 1 + [ -e "${CONFIG_PATH}/identity.secret" ] && secret="$(cat "${CONFIG_PATH}/identity.secret")" + [ -n "$secret" ] || secret="$(zerotier-idtool generate)" + [ "${?}" -ne 0 ] && return 1 uci set zerotier.global.secret="${secret}" uci commit zerotier echo "done." @@ -90,12 +105,19 @@ start_service() { procd_open_instance procd_set_param command ${PROG} ${args} procd_set_param stderr 1 + procd_set_param limits core="unlimited" + procd_set_param limits nofile="1000000 1000000" procd_set_param respawn procd_close_instance } +service_started() { + zerotier-fw4 -s +} + stop_service() { - rm -rf "${CONFIG_PATH}" + rm -rf "${CONFIG_PATH}" "${RUN_PATH}" + fw4 reload >"/dev/null" 2>&1 } reload_service() { diff --git a/net/zerotier/files/etc/uci-defaults/80-zt-migration b/net/zerotier/files/etc/uci-defaults/80-zt-migration index 1cfedb58384c84..739e8450ad5459 100644 --- a/net/zerotier/files/etc/uci-defaults/80-zt-migration +++ b/net/zerotier/files/etc/uci-defaults/80-zt-migration @@ -1,19 +1,37 @@ +#!/bin/sh + # Convert the join list into networks nets=$(uci -q get zerotier.@zerotier[0].join) if [ -n "$nets" ]; then - for net in ${nets}; do - sid=$(uci add zerotier network) - uci set zerotier.${sid}.id=${net} - done - uci delete zerotier.@zerotier[0].join + nat="$(uci -q get zerotier.@zerotier[0].nat)" + + for net in ${nets}; do + sid="$(uci add zerotier network)" + uci set zerotier."${sid}".id="${net}" + uci set zerotier."${sid}".fw_allow_input="${nat}" + uci set zerotier."${sid}".fw_allow_forward="${nat}" + uci set zerotier."${sid}".fw_allow_masq="${nat}" + done + uci delete zerotier.@zerotier[0].join + + # Rename local conf (only if defined) + uci -q rename zerotier.@zerotier[0].local_conf='local_conf_path' - # Rename local conf (only if defined) - uci -q rename zerotier.@zerotier[0].local_conf='local_conf_path' || true + # Rename nat + uci -q rename zerotier.@zerotier[0].nat='fw_allow_input' - # Rename configuration to global - uci rename zerotier.@zerotier[0]='global' + # Rename configuration to global + uci rename zerotier.@zerotier[0]='global' - # Commit all changes - uci commit zerotier + # Set default config path + uci set zerotier.global.config_path='/etc/zerotier' + + # Commit all changes + uci commit zerotier + + # Move to new config path + [ -d "/etc/config/zero" ] && mv "/etc/config/zero" "/etc/zerotier" fi + +exit 0 diff --git a/net/zerotier/files/etc/uci-defaults/81-zt-firewall b/net/zerotier/files/etc/uci-defaults/81-zt-firewall new file mode 100644 index 00000000000000..3f22ee53e652e9 --- /dev/null +++ b/net/zerotier/files/etc/uci-defaults/81-zt-firewall @@ -0,0 +1,30 @@ +#!/bin/sh + +FW_PATH="/var/run/zerotier-one/_fw4" + +uci -q batch <<-EOF > "/dev/null" + delete firewall.zerotier_input + set firewall.zerotier_input="include" + set firewall.zerotier_input.type="nftables" + set firewall.zerotier_input.path="$FW_PATH/input.nft" + set firewall.zerotier_input.position="chain-pre" + set firewall.zerotier_input.chain="input" + + delete firewall.zerotier_srcnat + set firewall.zerotier_srcnat="include" + set firewall.zerotier_srcnat.type="nftables" + set firewall.zerotier_srcnat.path="$FW_PATH/srcnat.nft" + set firewall.zerotier_srcnat.position="chain-pre" + set firewall.zerotier_srcnat.chain="srcnat" + + delete firewall.zerotier_forward + set firewall.zerotier_forward="include" + set firewall.zerotier_forward.type="nftables" + set firewall.zerotier_forward.path="$FW_PATH/forward.nft" + set firewall.zerotier_forward.position="chain-pre" + set firewall.zerotier_forward.chain="forward" + + commit firewall +EOF + +exit 0 diff --git a/net/zerotier/files/usr/bin/zerotier-fw4 b/net/zerotier/files/usr/bin/zerotier-fw4 new file mode 100755 index 00000000000000..62027f0e666ee1 --- /dev/null +++ b/net/zerotier/files/usr/bin/zerotier-fw4 @@ -0,0 +1,77 @@ +#!/bin/sh + +FW_PATH="/var/run/zerotier-one/_fw4" +[ -d "$FW_PATH" ] || mkdir -p "$FW_PATH" + +while getopts "i:s" arg; do + case "$arg" in + i) + iface="$OPTARG" + [ -n "$iface" ] || continue + + network_id="$(zerotier-cli -j listnetworks | jsonfilter -qe "@[@.portDeviceName=\"$iface\"].nwid")" + [ -n "$network_id" ] || continue + + network_cfg="$(uci show "zerotier" | awk "/$network_id/ && !found {split(\$0, conf, /[.=]/); print conf[2]; found=1}")" + [ -n "$network_cfg" ] || continue + + if [ "$(uci -q get zerotier."$network_cfg".fw_allow_input)" = "1" ]; then + grep -q "$iface" "$FW_PATH/input.nft" 2>"/dev/null" && continue + rule="iifname $iface counter accept comment \"!fw4: Accept ZeroTier input $iface\"" + echo "$rule" >> "$FW_PATH/input.nft" + nft insert rule inet fw4 input "$rule" + fi + + if [ "$(uci -q get zerotier."$network_cfg".fw_allow_forward)" = "1" ]; then + grep -q "$iface" "$FW_PATH/forward.nft" 2>"/dev/null" && continue + fwd_ifaces="$(uci -q get zerotier."$network_cfg".fw_forward_ifaces)" + rule="iifname $iface counter accept comment \"!fw4: Accept ZeroTier input forward $iface\"" + [ -n "$fwd_ifaces" ] && rule="oifname { ${fwd_ifaces// /, } } $rule" + echo "$rule" >> "$FW_PATH/forward.nft" + nft insert rule inet fw4 forward "$rule" + + rule="oifname $iface counter accept comment \"!fw4: Accept ZeroTier output forward $iface\"" + [ -n "$fwd_ifaces" ] && rule="iifname { ${fwd_ifaces// /, } } $rule" + echo "$rule" >> "$FW_PATH/forward.nft" + nft insert rule inet fw4 forward "$rule" + fi + + if [ "$(uci -q get zerotier."$network_cfg".fw_allow_masq)" = "1" ]; then + grep -q "$iface" "$FW_PATH/srcnat.nft" 2>"/dev/null" && continue + masq_ifaces="$(uci -q get zerotier."$network_cfg".fw_masq_ifaces)" + rule="oifname $iface counter masquerade comment \"!fw4: Masquerade ZeroTier traffic $iface\"" + [ -n "$masq_ifaces" ] && rule="iifname { ${masq_ifaces// /, } } $rule" + echo "$rule" >> "$FW_PATH/srcnat.nft" + nft insert rule inet fw4 srcnat "$rule" + fi + ;; + s) + [ "$(uci -q get zerotier.global.fw_allow_input)" = "1" ] || continue + + wait=0 + until [ "$wait" -ge "10" ]; do + zerotier_info="$(zerotier-cli -j info | jsonfilter -qe "@.config.settings")" + [ -n "$zerotier_info" ] && break + sleep 2s + wait="$(( wait +2 ))" + done + [ -n "$zerotier_info" ] || continue + + for pp in "primaryPort" "secondaryPort"; do + pport="$(echo "$zerotier_info" | jsonfilter -qe "@.$pp")" + [ -z "$pport" ] && continue + grep -q "$pport" "$FW_PATH/input.nft" 2>"/dev/null" && continue + network="udp" + [ "$pp" = "primaryPort" ] && network="$network, tcp" + echo "meta l4proto { $network } th dport $pport counter accept comment \"!fw4: Accept ZeroTier input $pport ($pp)\"" >> "$FW_PATH/input.nft" + nft insert rule inet fw4 "input meta l4proto { $network } th dport $pport counter accept comment \"!fw4: Accept ZeroTier input $pport ($pp)\"" + done + ;; + *) + echo "Usage: $0 -i | -s" + echo " -i : Generate rules for the specified interface" + echo " -s : Generate rules for the zerotier service" + exit 1 + ;; + esac +done