diff --git a/frontend/public/json/add-iptag.json b/frontend/public/json/add-iptag.json new file mode 100644 index 000000000..3b23d543c --- /dev/null +++ b/frontend/public/json/add-iptag.json @@ -0,0 +1,49 @@ + +{ + "name": "Proxmox VE LXC IP-Tag", + "slug": "add-iptag", + "categories": [ + 1 + ], + "date_created": "2025-06-15", + "type": "addon", + "updateable": false, + "privileged": false, + "interface_port": null, + "documentation": null, + "website": null, + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/proxmox.svg", + "config_path": "", + "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", + "script": "tools/pve/add-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": "Configuration: `nano /opt/iptag/iptag.conf`. iptag.service must be restarted after change.", + "type": "info" + }, + { + "text": "The Proxmox Node must contain ipcalc and net-tools. `apt-get install -y ipcalc net-tools`", + "type": "warning" + } + ] +} diff --git a/frontend/public/json/add-lxc-iptag.json b/frontend/public/json/add-lxc-iptag.json deleted file mode 100644 index 4f3b148b7..000000000 --- a/frontend/public/json/add-lxc-iptag.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "Proxmox VE LXC IP-Tag", - "slug": "add-lxc-iptag", - "categories": [ - 1 - ], - "date_created": "2024-12-16", - "type": "pve", - "updateable": false, - "privileged": false, - "interface_port": null, - "documentation": null, - "website": null, - "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/proxmox.webp", - "config_path": "/opt/lxc-iptag/iptag.conf", - "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", - "script": "tools/pve/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 Proxmox Node must contain ipcalc and net-tools. `apt-get install -y ipcalc net-tools`", - "type": "warning" - } - ] -} diff --git a/misc/add-iptag.sh b/tools/pve/add-iptag.sh similarity index 100% rename from misc/add-iptag.sh rename to tools/pve/add-iptag.sh diff --git a/tools/pve/add-lxc-iptag.sh b/tools/pve/add-lxc-iptag.sh deleted file mode 100644 index 88732be66..000000000 --- a/tools/pve/add-lxc-iptag.sh +++ /dev/null @@ -1,357 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (c) 2021-2025 community-scripts ORG -# Author: MickLesk (Canbiz) -# License: MIT -# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE -# Source: https://github.com/gitsang/lxc-iptag - -function header_info { - clear - cat <<"EOF" - __ _ ________ ________ ______ - / / | |/ / ____/ / _/ __ \ /_ __/___ _____ _ - / / | / / / // /_/ /_____/ / / __ `/ __ `/ - / /___/ / /___ _/ // ____/_____/ / / /_/ / /_/ / -/_____/_/|_\____/ /___/_/ /_/ \__,_/\__, / - /____/ -EOF -} - -clear -header_info -APP="LXC IP-Tag" -hostname=$(hostname) - -# Farbvariablen -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}" - -# 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 -} - -# 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" -} - -# This function displays a spinner. -spinner() { - local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') - local spin_i=0 - local interval=0.1 - printf "\e[?25l" - - local color="${YWB}" - - while true; do - printf "\r ${color}%s${CL}" "${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 "${TAB}${YW}${HOLD}${msg}${HOLD}" - 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]*) - msg_error "Installation cancelled." - exit - ;; - *) msg_error "Please answer yes or no." ;; - esac -done - -if ! pveversion | grep -Eq "pve-manager/8\.[0-4](\.[0-9]+)*"; then - 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: '$FILE_PATH'. Skipping installation." - exit 0 -fi - -msg_info "Installing Dependencies" -apt-get update &>/dev/null -apt-get install -y ipcalc net-tools &>/dev/null -msg_ok "Installed Dependencies" - -msg_info "Setting up IP-Tag Scripts" -mkdir -p /opt/lxc-iptag -msg_ok "Setup IP-Tag Scripts" - -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 - 172.16.0.0/12 - 10.0.0.0/8 - 100.64.0.0/10 -) - -# 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 - 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 Service" -systemctl daemon-reload &>/dev/null -systemctl enable -q --now iptag.service &>/dev/null -msg_ok "Started Service" -SPINNER_PID="" -echo -e "\n${APP} installation completed successfully! ${CL}\n"