From b8b6366e3f08a0be5bf73d69624f7620ad4a5a38 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:43:24 +0100 Subject: [PATCH 1/8] New Script: LXC IP-Tag --- json/add-lxc-iptag.json | 43 +++++++++ misc/add-lxc-iptag.sh | 107 +++++++++++++++++++++ misc/lxc-iptag/iptag.conf | 9 ++ misc/lxc-iptag/iptag.func | 176 +++++++++++++++++++++++++++++++++++ misc/lxc-iptag/iptag.service | 11 +++ 5 files changed, 346 insertions(+) create mode 100644 json/add-lxc-iptag.json create mode 100644 misc/add-lxc-iptag.sh create mode 100644 misc/lxc-iptag/iptag.conf create mode 100644 misc/lxc-iptag/iptag.func create mode 100644 misc/lxc-iptag/iptag.service diff --git a/json/add-lxc-iptag.json b/json/add-lxc-iptag.json new file mode 100644 index 00000000..149278e0 --- /dev/null +++ b/json/add-lxc-iptag.json @@ -0,0 +1,43 @@ +{ + "name": "Proxmox VE LXC IP-Tag", + "slug": "add-lxc-iptag", + "categories": [ + 1 + ], + "date_created": "2024-11-27", + "type": "misc", + "updateable": false, + "privileged": false, + "interface_port": null, + "documentation": null, + "website": null, + "logo": "https://raw.githubusercontent.com/home-assistant/brands/master/core_integrations/proxmoxve/icon.png", + "description": "This script automatically writes the IP address as a tag to each LXC container using a Systemd service. If the IP should be changed, this is also updated by the script.", + "install_methods": [ + { + "type": "default", + "script": "misc/add-lxc-iptag.sh", + "resources": { + "cpu": null, + "ram": null, + "hdd": null, + "os": null, + "version": null + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Execute within the Proxmox shell", + "type": "Info" + } + { + "text": "The CIDR list can modify here: `nano /usr/local/etc/iptag.conf`", + "type": "Info" + } + ] +} \ No newline at end of file diff --git a/misc/add-lxc-iptag.sh b/misc/add-lxc-iptag.sh new file mode 100644 index 00000000..bbdf1a9f --- /dev/null +++ b/misc/add-lxc-iptag.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2024 community-scripts ORG +# Author: MickLesk (Canbiz) +# Maker/Programmer: gitsang +# License: MIT +# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Original-Source: https://github.com/gitsang/lxc-iptag + +function header_info { + cat <<"EOF" + __ _ ________ ________ ______ + / / | |/ / ____/ / _/ __ \ /_ __/___ _____ _ + / / | / / / // /_/ /_____/ / / __ `/ __ `/ + / /___/ / /___ _/ // ____/_____/ / / /_/ / /_/ / +/_____/_/|_\____/ /___/_/ /_/ \__,_/\__, / + /____/ +EOF +} + +# Colors +YW=$(echo "\033[33m") +GN=$(echo "\033[1;92m") +RD=$(echo "\033[01;31m") +CL=$(echo "\033[m") +BFR="\\r\\033[K" +HOLD=" " +CM=" ✔️ ${CL}" +CROSS=" ✖️ ${CL}" + +set -o errexit +set -o errtrace +set -o nounset +set -o pipefail +shopt -s expand_aliases +alias die='EXIT=$? LINE=$LINENO error_exit' +trap die ERR + +function error_exit() { + trap - ERR + local reason="Unknown failure occurred." + local msg="${1:-$reason}" + local flag="${CROSS} ERROR ${CL}$EXIT@$LINE" + echo -e "$flag $msg" 1>&2 + exit $EXIT +} + +clear +header_info + +APP="LXC IP-Tag" +hostname=$(hostname) + +while true; do + read -p "This will install ${APP} on ${hostname}. Proceed? (y/n): " yn + case $yn in + [Yy]*) break ;; + [Nn]*) echo "Installation cancelled."; exit ;; + *) echo "Please answer yes or no." ;; + esac +done + +function msg_info() { + local msg="$1" + echo -ne " ${HOLD} ${YW}${msg}${CL}" +} + +function msg_ok() { + local msg="$1" + echo -e "${BFR} ${CM} ${GN}${msg}${CL}" +} + +msg_error() { + local msg="$1" + echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}" +} + +if ! pveversion | grep -Eq "pve-manager/8.[0-3]"; then + msg_error "This script can only be executed on the Proxmox main node." + exit 1 +fi + +FILE_PATH="/usr/local/bin/iptag" +if [[ -f "$FILE_PATH" ]]; then + msg_info "The file already exists in the path: '$FILE_PATH' . Skip Installation." + exit 0 +fi + +msg_info "Installing Prerequisites" +apt-get update &>/dev/null +apt-get install -y ipcalc net-tools &>/dev/null +msg_ok "Installed Prerequisites" + +msg_info "Setting up IP-Tag Scripts" +curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.func -o /usr/local/bin/iptag +chmod +x /usr/local/bin/iptag +curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.conf -o /usr/local/etc/iptag.conf +curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.service -o /lib/systemd/system/iptag.service +msg_ok "Setup IP-Tag Scripts" + +msg_info "Starting Systemd Service" +systemctl daemon-reload &>/dev/null +systemctl enable -q --now iptag.service &>/dev/null +msg_ok "Started Systemd Service" + +echo -e "\n${APP} installation completed successfully!" + diff --git a/misc/lxc-iptag/iptag.conf b/misc/lxc-iptag/iptag.conf new file mode 100644 index 00000000..8b1caf74 --- /dev/null +++ b/misc/lxc-iptag/iptag.conf @@ -0,0 +1,9 @@ +CIDR_LIST=( + 192.168.0.0/16 + 100.64.0.0/10 + 10.0.0.0/8 +) +LOOP_INTERVAL=60 +FW_NET_INTERFACE_CHECK_INTERVAL=60 +LXC_STATUS_CHECK_INTERVAL=-1 +FORCE_UPDATE_INTERVAL=1800 diff --git a/misc/lxc-iptag/iptag.func b/misc/lxc-iptag/iptag.func new file mode 100644 index 00000000..f81ac253 --- /dev/null +++ b/misc/lxc-iptag/iptag.func @@ -0,0 +1,176 @@ +#!/bin/bash + +# =============== CONFIGURATION =============== # + +CIDR_LIST=( + 192.168.0.0/16 + 100.64.0.0/10 + 10.0.0.0/8 +) +LOOP_INTERVAL=60 +FW_NET_INTERFACE_CHECK_INTERVAL=60 +LXC_STATUS_CHECK_INTERVAL=-1 +FORCE_UPDATE_INTERVAL=1800 + +if [ -f "/usr/local/etc/iptag.conf" ]; then + source /usr/local/etc/iptag.conf +fi + +# =============== UTIL_FUNCTION =============== # + +# Convert IP to integer for comparison +ip_to_int() { + local ip="${1}" + local a b c d + + IFS=. read -r a b c d <<< "${ip}" + echo "$((a << 24 | b << 16 | c << 8 | d))" +} + +# Check if IP is in CIDR +ip_in_cidr() { + local ip="${1}" + local cidr="${2}" + + ip_int=$(ip_to_int "${ip}") + netmask_int=$(ip_to_int "$(ipcalc -b "${cidr}" | grep Broadcast | awk '{print $2}')") + masked_ip_int=$(( "${ip_int}" & "${netmask_int}" )) + [[ ${ip_int} -eq ${masked_ip_int} ]] && return 0 || return 1 +} + +# Check if IP is in any CIDRs +ip_in_cidrs() { + local ip="${1}" + local cidrs=() + + mapfile -t cidrs < <(echo "${2}" | tr ' ' '\n') + for cidr in "${cidrs[@]}"; do + ip_in_cidr "${ip}" "${cidr}" && return 0 + done + + return 1 +} + +# Check if IP is valid +is_valid_ipv4() { + local ip=$1 + local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$" + + if [[ $ip =~ $regex ]]; then + IFS='.' read -r -a parts <<< "$ip" + for part in "${parts[@]}"; do + if ! [[ $part =~ ^[0-9]+$ ]] || ((part < 0 || part > 255)); then + return 1 + fi + done + return 0 + else + return 1 + fi +} + +lxc_status_changed() { + current_lxc_status=$(pct list 2>/dev/null) + if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then + return 1 + else + last_lxc_status="${current_lxc_status}" + return 0 + fi +} + +fw_net_interface_changed() { + current_net_interface=$(ifconfig | grep "^fw") + if [ "${last_net_interface}" == "${current_net_interface}" ]; then + return 1 + else + last_net_interface="${current_net_interface}" + return 0 + fi +} + +# =============== MAIN =============== # + +update_lxc_iptags() { + vmid_list=$(pct list 2>/dev/null | grep -v VMID | awk '{print $1}') + for vmid in ${vmid_list}; do + last_tagged_ips=() + current_valid_ips=() + next_tags=() + + # Parse current tags + mapfile -t current_tags < <(pct config "${vmid}" | grep tags | awk '{print $2}' | sed 's/;/\n/g') + for current_tag in "${current_tags[@]}"; do + if is_valid_ipv4 "${current_tag}"; then + last_tagged_ips+=("${current_tag}") + continue + fi + next_tags+=("${current_tag}") + done + + # Get current IPs + current_ips_full=$(lxc-info -n "${vmid}" -i | awk '{print $2}') + for ip in ${current_ips_full}; do + if is_valid_ipv4 "${ip}" && ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then + current_valid_ips+=("${ip}") + next_tags+=("${ip}") + fi + done + + # Skip if no ip change + if [[ "$(echo "${last_tagged_ips[@]}" | tr ' ' '\n' | sort -u)" == "$(echo "${current_valid_ips[@]}" | tr ' ' '\n' | sort -u)" ]]; then + echo "Skipping ${vmid} cause ip no changes" + continue + fi + + # Set tags + echo "Setting ${vmid} tags from ${current_tags[*]} to ${next_tags[*]}" + pct set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" + done +} + +check() { + current_time=$(date +%s) + + time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time)) + if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \ + && [[ "${time_since_last_lxc_status_check}" -ge "${STATUS_CHECK_INTERVAL}" ]]; then + echo "Checking lxc status..." + last_lxc_status_check_time=${current_time} + if lxc_status_changed; then + update_lxc_iptags + last_update_time=${current_time} + return + fi + fi + + time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time)) + if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \ + && [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then + echo "Checking fw net interface..." + last_fw_net_interface_check_time=${current_time} + if fw_net_interface_changed; then + update_lxc_iptags + last_update_time=${current_time} + return + fi + fi + + time_since_last_update=$((current_time - last_update_time)) + if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then + echo "Force updating lxc iptags..." + update_lxc_iptags + last_update_time=${current_time} + return + fi +} + +# main: Set the IP tags for all LXC containers +main() { + while true; do + check + sleep "${LOOP_INTERVAL}" + done +} + +main diff --git a/misc/lxc-iptag/iptag.service b/misc/lxc-iptag/iptag.service new file mode 100644 index 00000000..efab4dd5 --- /dev/null +++ b/misc/lxc-iptag/iptag.service @@ -0,0 +1,11 @@ +[Unit] +Description=LXC IP-Tag service +After=network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/iptag +Restart=always + +[Install] +WantedBy=multi-user.target From db5f9ffc0e8cfdbab2541323f74934e2e250f491 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 05:34:44 +0100 Subject: [PATCH 2/8] add comma in json --- json/add-lxc-iptag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/add-lxc-iptag.json b/json/add-lxc-iptag.json index 149278e0..45c85a38 100644 --- a/json/add-lxc-iptag.json +++ b/json/add-lxc-iptag.json @@ -34,7 +34,7 @@ { "text": "Execute within the Proxmox shell", "type": "Info" - } + }, { "text": "The CIDR list can modify here: `nano /usr/local/etc/iptag.conf`", "type": "Info" From a2fd2a0bc89c21f1de41666c0f3c3f955d317cfe Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:45:35 +0100 Subject: [PATCH 3/8] Update misc/add-lxc-iptag.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- misc/add-lxc-iptag.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/misc/add-lxc-iptag.sh b/misc/add-lxc-iptag.sh index bbdf1a9f..1040bc33 100644 --- a/misc/add-lxc-iptag.sh +++ b/misc/add-lxc-iptag.sh @@ -2,7 +2,6 @@ # Copyright (c) 2021-2024 community-scripts ORG # Author: MickLesk (Canbiz) -# Maker/Programmer: gitsang # License: MIT # https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Original-Source: https://github.com/gitsang/lxc-iptag From 0e202bdba192f67c93dea65f1c9f0c631afad2fd Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:43:10 +0100 Subject: [PATCH 4/8] Update json/add-lxc-iptag.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- json/add-lxc-iptag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/add-lxc-iptag.json b/json/add-lxc-iptag.json index 45c85a38..c3a8da8d 100644 --- a/json/add-lxc-iptag.json +++ b/json/add-lxc-iptag.json @@ -36,7 +36,7 @@ "type": "Info" }, { - "text": "The CIDR list can modify here: `nano /usr/local/etc/iptag.conf`", + "text": "Configuration: `nano /usr/local/etc/iptag.conf`. iptag.service must be restarted after change.", "type": "Info" } ] From 688158e6251225038a7626912095875eeae2a24a Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:43:18 +0100 Subject: [PATCH 5/8] Update json/add-lxc-iptag.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Håvard Gjøby Thom <34199185+havardthom@users.noreply.github.com> --- json/add-lxc-iptag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json/add-lxc-iptag.json b/json/add-lxc-iptag.json index c3a8da8d..c9f37e05 100644 --- a/json/add-lxc-iptag.json +++ b/json/add-lxc-iptag.json @@ -12,7 +12,7 @@ "documentation": null, "website": null, "logo": "https://raw.githubusercontent.com/home-assistant/brands/master/core_integrations/proxmoxve/icon.png", - "description": "This script automatically writes the IP address as a tag to each LXC container using a Systemd service. If the IP should be changed, this is also updated by the script.", + "description": "This script automatically adds IP address as tags to LXC containers using a Systemd service. The service also updates the tags if a LXC IP address is changed.", "install_methods": [ { "type": "default", From 44f1c7bd7ab12ed39552b5a5b536b1093b347004 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:44:31 +0100 Subject: [PATCH 6/8] remove files --- misc/lxc-iptag/iptag.conf | 9 -- misc/lxc-iptag/iptag.func | 176 ----------------------------------- misc/lxc-iptag/iptag.service | 11 --- 3 files changed, 196 deletions(-) delete mode 100644 misc/lxc-iptag/iptag.conf delete mode 100644 misc/lxc-iptag/iptag.func delete mode 100644 misc/lxc-iptag/iptag.service diff --git a/misc/lxc-iptag/iptag.conf b/misc/lxc-iptag/iptag.conf deleted file mode 100644 index 8b1caf74..00000000 --- a/misc/lxc-iptag/iptag.conf +++ /dev/null @@ -1,9 +0,0 @@ -CIDR_LIST=( - 192.168.0.0/16 - 100.64.0.0/10 - 10.0.0.0/8 -) -LOOP_INTERVAL=60 -FW_NET_INTERFACE_CHECK_INTERVAL=60 -LXC_STATUS_CHECK_INTERVAL=-1 -FORCE_UPDATE_INTERVAL=1800 diff --git a/misc/lxc-iptag/iptag.func b/misc/lxc-iptag/iptag.func deleted file mode 100644 index f81ac253..00000000 --- a/misc/lxc-iptag/iptag.func +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash - -# =============== CONFIGURATION =============== # - -CIDR_LIST=( - 192.168.0.0/16 - 100.64.0.0/10 - 10.0.0.0/8 -) -LOOP_INTERVAL=60 -FW_NET_INTERFACE_CHECK_INTERVAL=60 -LXC_STATUS_CHECK_INTERVAL=-1 -FORCE_UPDATE_INTERVAL=1800 - -if [ -f "/usr/local/etc/iptag.conf" ]; then - source /usr/local/etc/iptag.conf -fi - -# =============== UTIL_FUNCTION =============== # - -# Convert IP to integer for comparison -ip_to_int() { - local ip="${1}" - local a b c d - - IFS=. read -r a b c d <<< "${ip}" - echo "$((a << 24 | b << 16 | c << 8 | d))" -} - -# Check if IP is in CIDR -ip_in_cidr() { - local ip="${1}" - local cidr="${2}" - - ip_int=$(ip_to_int "${ip}") - netmask_int=$(ip_to_int "$(ipcalc -b "${cidr}" | grep Broadcast | awk '{print $2}')") - masked_ip_int=$(( "${ip_int}" & "${netmask_int}" )) - [[ ${ip_int} -eq ${masked_ip_int} ]] && return 0 || return 1 -} - -# Check if IP is in any CIDRs -ip_in_cidrs() { - local ip="${1}" - local cidrs=() - - mapfile -t cidrs < <(echo "${2}" | tr ' ' '\n') - for cidr in "${cidrs[@]}"; do - ip_in_cidr "${ip}" "${cidr}" && return 0 - done - - return 1 -} - -# Check if IP is valid -is_valid_ipv4() { - local ip=$1 - local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$" - - if [[ $ip =~ $regex ]]; then - IFS='.' read -r -a parts <<< "$ip" - for part in "${parts[@]}"; do - if ! [[ $part =~ ^[0-9]+$ ]] || ((part < 0 || part > 255)); then - return 1 - fi - done - return 0 - else - return 1 - fi -} - -lxc_status_changed() { - current_lxc_status=$(pct list 2>/dev/null) - if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then - return 1 - else - last_lxc_status="${current_lxc_status}" - return 0 - fi -} - -fw_net_interface_changed() { - current_net_interface=$(ifconfig | grep "^fw") - if [ "${last_net_interface}" == "${current_net_interface}" ]; then - return 1 - else - last_net_interface="${current_net_interface}" - return 0 - fi -} - -# =============== MAIN =============== # - -update_lxc_iptags() { - vmid_list=$(pct list 2>/dev/null | grep -v VMID | awk '{print $1}') - for vmid in ${vmid_list}; do - last_tagged_ips=() - current_valid_ips=() - next_tags=() - - # Parse current tags - mapfile -t current_tags < <(pct config "${vmid}" | grep tags | awk '{print $2}' | sed 's/;/\n/g') - for current_tag in "${current_tags[@]}"; do - if is_valid_ipv4 "${current_tag}"; then - last_tagged_ips+=("${current_tag}") - continue - fi - next_tags+=("${current_tag}") - done - - # Get current IPs - current_ips_full=$(lxc-info -n "${vmid}" -i | awk '{print $2}') - for ip in ${current_ips_full}; do - if is_valid_ipv4 "${ip}" && ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then - current_valid_ips+=("${ip}") - next_tags+=("${ip}") - fi - done - - # Skip if no ip change - if [[ "$(echo "${last_tagged_ips[@]}" | tr ' ' '\n' | sort -u)" == "$(echo "${current_valid_ips[@]}" | tr ' ' '\n' | sort -u)" ]]; then - echo "Skipping ${vmid} cause ip no changes" - continue - fi - - # Set tags - echo "Setting ${vmid} tags from ${current_tags[*]} to ${next_tags[*]}" - pct set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" - done -} - -check() { - current_time=$(date +%s) - - time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time)) - if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \ - && [[ "${time_since_last_lxc_status_check}" -ge "${STATUS_CHECK_INTERVAL}" ]]; then - echo "Checking lxc status..." - last_lxc_status_check_time=${current_time} - if lxc_status_changed; then - update_lxc_iptags - last_update_time=${current_time} - return - fi - fi - - time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time)) - if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \ - && [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then - echo "Checking fw net interface..." - last_fw_net_interface_check_time=${current_time} - if fw_net_interface_changed; then - update_lxc_iptags - last_update_time=${current_time} - return - fi - fi - - time_since_last_update=$((current_time - last_update_time)) - if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then - echo "Force updating lxc iptags..." - update_lxc_iptags - last_update_time=${current_time} - return - fi -} - -# main: Set the IP tags for all LXC containers -main() { - while true; do - check - sleep "${LOOP_INTERVAL}" - done -} - -main diff --git a/misc/lxc-iptag/iptag.service b/misc/lxc-iptag/iptag.service deleted file mode 100644 index efab4dd5..00000000 --- a/misc/lxc-iptag/iptag.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=LXC IP-Tag service -After=network.target - -[Service] -Type=simple -ExecStart=/usr/local/bin/iptag -Restart=always - -[Install] -WantedBy=multi-user.target From bbe3216faea7ac1e0b8639550493a94c536a9978 Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:49:26 +0100 Subject: [PATCH 7/8] Full-Update to Single-File --- misc/add-lxc-iptag.sh | 347 +++++++++++++++++++++++++++++++++++------- 1 file changed, 296 insertions(+), 51 deletions(-) diff --git a/misc/add-lxc-iptag.sh b/misc/add-lxc-iptag.sh index 1040bc33..3610f337 100644 --- a/misc/add-lxc-iptag.sh +++ b/misc/add-lxc-iptag.sh @@ -7,7 +7,8 @@ # Original-Source: https://github.com/gitsang/lxc-iptag function header_info { - cat <<"EOF" + clear + cat <<"EOF" __ _ ________ ________ ______ / / | |/ / ____/ / _/ __ \ /_ __/___ _____ _ / / | / / / // /_/ /_____/ / / __ `/ __ `/ @@ -17,7 +18,12 @@ function header_info { EOF } -# Colors +clear +header_info +APP="LXC IP-Tag" +hostname=$(hostname) + +# Farbvariablen YW=$(echo "\033[33m") GN=$(echo "\033[1;92m") RD=$(echo "\033[01;31m") @@ -27,80 +33,319 @@ HOLD=" " CM=" ✔️ ${CL}" CROSS=" ✖️ ${CL}" -set -o errexit -set -o errtrace -set -o nounset -set -o pipefail -shopt -s expand_aliases -alias die='EXIT=$? LINE=$LINENO error_exit' -trap die ERR - -function error_exit() { - trap - ERR - local reason="Unknown failure occurred." - local msg="${1:-$reason}" - local flag="${CROSS} ERROR ${CL}$EXIT@$LINE" - echo -e "$flag $msg" 1>&2 - exit $EXIT +# This function enables error handling in the script by setting options and defining a trap for the ERR signal. +catch_errors() { + set -Eeuo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR } -clear -header_info +# This function is called when an error occurs. It receives the exit code, line number, and command that caused the error, and displays an error message. +error_handler() { + if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi + printf "\e[?25h" + local exit_code="$?" + local line_number="$1" + local command="$2" + local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" + echo -e "\n$error_message\n" +} -APP="LXC IP-Tag" -hostname=$(hostname) +spinner() { + local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') + local spin_i=0 + local interval=0.1 + printf "\e[?25l" + local orange="\e[38;5;214m" + + while true; do + printf "\r ${orange}%s\e[0m " "${frames[spin_i]}" + spin_i=$(( (spin_i + 1) % ${#frames[@]} )) + sleep "$interval" + done +} + +# This function displays an informational message with a yellow color. +msg_info() { + local msg="$1" + echo -ne " ${HOLD} ${YW}${msg} " + spinner & + SPINNER_PID=$! +} + +# This function displays a success message with a green color. +msg_ok() { + if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi + printf "\e[?25h" + local msg="$1" + echo -e "${BFR}${CM} ${GN}${msg}${CL}" +} + +# This function displays a error message with a red color. +msg_error() { + if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then kill $SPINNER_PID > /dev/null; fi + printf "\e[?25h" + local msg="$1" + echo -e "${BFR}${CROSS} ${RD}${msg}${CL}" +} while true; do read -p "This will install ${APP} on ${hostname}. Proceed? (y/n): " yn case $yn in [Yy]*) break ;; - [Nn]*) echo "Installation cancelled."; exit ;; - *) echo "Please answer yes or no." ;; + [Nn]*) msg_info "Installation cancelled."; exit ;; + *) msg_info "Please answer yes or no." ;; esac done -function msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}${CL}" -} - -function msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -msg_error() { - local msg="$1" - echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}" -} - if ! pveversion | grep -Eq "pve-manager/8.[0-3]"; then - msg_error "This script can only be executed on the Proxmox main node." - exit 1 + msg_error "This version of Proxmox Virtual Environment is not supported" + msg_error "⚠️ Requires Proxmox Virtual Environment Version 8.0 or later." + msg_error "Exiting..." + sleep 2 + exit fi FILE_PATH="/usr/local/bin/iptag" if [[ -f "$FILE_PATH" ]]; then - msg_info "The file already exists in the path: '$FILE_PATH' . Skip Installation." + msg_info "The file already exists: '$FILE_PATH'. Skipping installation." exit 0 fi -msg_info "Installing Prerequisites" +msg_info "Installing Dependencies" apt-get update &>/dev/null apt-get install -y ipcalc net-tools &>/dev/null -msg_ok "Installed Prerequisites" +msg_ok "Installed Dependencies" msg_info "Setting up IP-Tag Scripts" -curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.func -o /usr/local/bin/iptag -chmod +x /usr/local/bin/iptag -curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.conf -o /usr/local/etc/iptag.conf -curl -sSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/lxc-iptag/iptag.service -o /lib/systemd/system/iptag.service +mkdir -p /opt/lxc-iptag + +msg_info "Setup Default Config" +if [[ ! -f /opt/lxc-iptag/iptag.conf ]]; then + cat < /opt/lxc-iptag/iptag.conf +# Configuration file for LXC IP tagging + +# List of allowed CIDRs +CIDR_LIST=( + 192.168.0.0/16 + 100.64.0.0/10 + 10.0.0.0/8 +) + +# Interval settings (in seconds) +LOOP_INTERVAL=60 +FW_NET_INTERFACE_CHECK_INTERVAL=60 +LXC_STATUS_CHECK_INTERVAL=-1 +FORCE_UPDATE_INTERVAL=1800 +EOF + msg_ok "Setup default config" +else + msg_ok "Default config already exists" +fi + +msg_info "Setup Main Function" +if [[ ! -f /opt/lxc-iptag/iptag ]]; then + cat <<'EOF' > /opt/lxc-iptag/iptag +#!/bin/bash + +# =============== CONFIGURATION =============== # + +CONFIG_FILE="/opt/lxc-iptag/iptag.conf" + +# Load the configuration file if it exists +if [ -f "$CONFIG_FILE" ]; then + # shellcheck source=./lxc-iptag.conf + source "$CONFIG_FILE" +fi + +# Convert IP to integer for comparison +ip_to_int() { + local ip="${1}" + local a b c d + + IFS=. read -r a b c d <<< "${ip}" + echo "$((a << 24 | b << 16 | c << 8 | d))" +} + +# Check if IP is in CIDR +ip_in_cidr() { + local ip="${1}" + local cidr="${2}" + + ip_int=$(ip_to_int "${ip}") + netmask_int=$(ip_to_int "$(ipcalc -b "${cidr}" | grep Broadcast | awk '{print $2}')") + masked_ip_int=$(( "${ip_int}" & "${netmask_int}" )) + [[ ${ip_int} -eq ${masked_ip_int} ]] && return 0 || return 1 +} + +# Check if IP is in any CIDRs +ip_in_cidrs() { + local ip="${1}" + local cidrs=() + + mapfile -t cidrs < <(echo "${2}" | tr ' ' '\n') + for cidr in "${cidrs[@]}"; do + ip_in_cidr "${ip}" "${cidr}" && return 0 + done + + return 1 +} + +# Check if IP is valid +is_valid_ipv4() { + local ip=$1 + local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$" + + if [[ $ip =~ $regex ]]; then + IFS='.' read -r -a parts <<< "$ip" + for part in "${parts[@]}"; do + if ! [[ $part =~ ^[0-9]+$ ]] || ((part < 0 || part > 255)); then + return 1 + fi + done + return 0 + else + return 1 + fi +} + +lxc_status_changed() { + current_lxc_status=$(pct list 2>/dev/null) + if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then + return 1 + else + last_lxc_status="${current_lxc_status}" + return 0 + fi +} + +fw_net_interface_changed() { + current_net_interface=$(ifconfig | grep "^fw") + if [ "${last_net_interface}" == "${current_net_interface}" ]; then + return 1 + else + last_net_interface="${current_net_interface}" + return 0 + fi +} + +# =============== MAIN =============== # + +update_lxc_iptags() { + vmid_list=$(pct list 2>/dev/null | grep -v VMID | awk '{print $1}') + for vmid in ${vmid_list}; do + last_tagged_ips=() + current_valid_ips=() + next_tags=() + + # Parse current tags + mapfile -t current_tags < <(pct config "${vmid}" | grep tags | awk '{print $2}' | sed 's/;/\n/g') + for current_tag in "${current_tags[@]}"; do + if is_valid_ipv4 "${current_tag}"; then + last_tagged_ips+=("${current_tag}") + continue + fi + next_tags+=("${current_tag}") + done + + # Get current IPs + current_ips_full=$(lxc-info -n "${vmid}" -i | awk '{print $2}') + for ip in ${current_ips_full}; do + if is_valid_ipv4 "${ip}" && ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then + current_valid_ips+=("${ip}") + next_tags+=("${ip}") + fi + done + + # Skip if no ip change + if [[ "$(echo "${last_tagged_ips[@]}" | tr ' ' '\n' | sort -u)" == "$(echo "${current_valid_ips[@]}" | tr ' ' '\n' | sort -u)" ]]; then + echo "Skipping ${vmid} cause ip no changes" + continue + fi + + # Set tags + echo "Setting ${vmid} tags from ${current_tags[*]} to ${next_tags[*]}" + pct set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" + done +} + +check() { + current_time=$(date +%s) + + time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time)) + if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \ + && [[ "${time_since_last_lxc_status_check}" -ge "${STATUS_CHECK_INTERVAL}" ]]; then + echo "Checking lxc status..." + last_lxc_status_check_time=${current_time} + if lxc_status_changed; then + update_lxc_iptags + last_update_time=${current_time} + return + fi + fi + + time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time)) + if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \ + && [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then + echo "Checking fw net interface..." + last_fw_net_interface_check_time=${current_time} + if fw_net_interface_changed; then + update_lxc_iptags + last_update_time=${current_time} + return + fi + fi + + time_since_last_update=$((current_time - last_update_time)) + if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then + echo "Force updating lxc iptags..." + update_lxc_iptags + last_update_time=${current_time} + return + fi +} + +# main: Set the IP tags for all LXC containers +main() { + while true; do + check + sleep "${LOOP_INTERVAL}" + done +} + +main +EOF + msg_ok "Setup Main Function" +else + msg_ok "Main Function already exists" +fi +chmod +x /opt/lxc-iptag/iptag + +msg_info "Creating Service" +if [[ ! -f /lib/systemd/system/iptag.service ]]; then + echo "Systemd service file not found. Creating it now..." + cat < /lib/systemd/system/iptag.service +[Unit] +Description=LXC IP-Tag service +After=network.target + +[Service] +Type=simple +ExecStart=/opt/lxc-iptag/iptag +Restart=always + +[Install] +WantedBy=multi-user.target +EOF + msg_ok "Created Service" +else + msg_ok "Service already exists." +fi + msg_ok "Setup IP-Tag Scripts" -msg_info "Starting Systemd Service" +msg_info "Starting Service" systemctl daemon-reload &>/dev/null systemctl enable -q --now iptag.service &>/dev/null -msg_ok "Started Systemd Service" - -echo -e "\n${APP} installation completed successfully!" +msg_ok "Started Service" +echo -e "\n${APP} installation completed successfully! ${CL}\n" From 30b5da27b2272c8e872ed0cefbc56616b3b934fa Mon Sep 17 00:00:00 2001 From: CanbiZ <47820557+MickLesk@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:52:04 +0100 Subject: [PATCH 8/8] Finalo --- misc/add-lxc-iptag.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/add-lxc-iptag.sh b/misc/add-lxc-iptag.sh index 3610f337..093faaa7 100644 --- a/misc/add-lxc-iptag.sh +++ b/misc/add-lxc-iptag.sh @@ -4,7 +4,7 @@ # Author: MickLesk (Canbiz) # License: MIT # https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Original-Source: https://github.com/gitsang/lxc-iptag +# Source: https://github.com/gitsang/lxc-iptag function header_info { clear