#!/bin/bash # DISCLAIMER: # This script is provided "AS IS" and is intended solely for illustrative or educational purposes. # Domotz makes no warranties, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, or non-infringement. Use of this script is at your own risk. # By using this script, you acknowledge and agree that Domotz shall not be liable for any direct, indirect, incidental, or consequential damages or losses arising from its use. # You further agree to indemnify, defend, and hold harmless Domotz and its affiliates from and against any claims, liabilities, damages, or expenses resulting from your use or misuse of this script. # # In the event of any conflict between this disclaimer and any other agreement between you and Domotz, this disclaimer shall prevail with respect to the use of this script. # # This script provides an example configuration for setting up Virtual LANs (VLANs) on a Linux system. # It demonstrates the creation of a VLAN interface with a specified VLAN ID on top of an existing network interface. # Prerequisites: # - the system should use the netplan file for network configuration. ver="1.0" # !!!Please changhe the path of the netplan file according to your system setup.!!! # Change this to your netplan file path NETPLAN_FILE="/etc/netplan/00-installer-config.yaml" # Check if the script is run as root if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" exit 1 fi # Function to check if the IP address is valid validate_ip() { local ip_with_mask=$1 local ip=${ip_with_mask%%/*} local mask=${ip_with_mask##*/} # Validate IP format if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then IFS='.' read -r -a octets <<< "$ip" for octet in "${octets[@]}"; do if ((octet < 0 || octet > 255)); then return 1 fi done else return 1 fi # Validate subnet mask if present if [[ $ip_with_mask == */* ]]; then if ! [[ $mask =~ ^[0-9]{1,2}$ ]] || ((mask < 16 || mask > 32)); then return 1 fi fi return 0 } # Function to add /24 subnet mask if not provided add_subnet_mask() { local ip=$1 if [[ ! $ip =~ /[0-9]{1,2}$ ]]; then ip="${ip}/24" fi echo "$ip" } # Function to check if the input is a number is_number() { local num=$1 [[ $num =~ ^[0-9]+$ ]] } # Show the interfaces currently configured echo "Current interfaces configuration:" echo "" ip -o link show | awk -F': ' '{print $2}' | grep -v lo echo "" echo "========================" # Function to check if an interface exists validate_interface() { local iface=$1 ip -o link show | awk -F': ' '{print $2}' | grep -v lo | grep -wq "$iface" } # Function to get ordinal number in uppercase get_ordinal() { local number=$1 case $number in 1) echo "FIRST";; 2) echo "SECOND";; 3) echo "THIRD";; 4) echo "FOURTH";; 5) echo "FIFTH";; 6) echo "SIXTH";; 7) echo "SEVENTH";; 8) echo "EIGHTH";; 9) echo "NINTH";; 10) echo "TENTH";; *) echo "${number}TH";; esac } # Ask on which interface to configure the VLANs while true; do read -p "Enter the interface name to configure VLANs: " IFACE if validate_interface "$IFACE"; then break else printf "Interface not found. Please enter a valid interface name.\n" >&2 fi done echo "========================" # Ask the number of VLANs to configure while true; do read -p "Enter the number of VLANs you want to configure: " VLAN_COUNT if is_number "$VLAN_COUNT"; then break else printf "Invalid input. Please enter a numeric value.\n" >&2 fi done echo "========================" # Define a function to make backup with incrementing names make_backup() { local file=$1 local backup_dir; backup_dir=$(dirname "$file") local backup_name; backup_name=$(basename "$file") local i=1 while [[ -f "$backup_dir/${backup_name}.bak$i" ]]; do let i++ done cp "$file" "$backup_dir/${backup_name}.bak$i" echo "Backup made as ${backup_name}.bak$i" } echo "========================" # Collect VLAN details declare -A vlans for (( i=1; i<=VLAN_COUNT; i++ )); do ordinal=$(get_ordinal $i) echo "Configuring the $ordinal VLAN of $VLAN_COUNT" while true; do read -p "Enter VLAN ID for the $ordinal VLAN: " vlan_id if is_number "$vlan_id"; then break else printf "Invalid input. Please enter a numeric value.\n" >&2 fi done # Validate and get the IP address with subnet mask while true; do read -p "Enter IP (e.g., 192.168.1.1 or 192.168.1.1/24) for the $ordinal VLAN: " ip ip=$(add_subnet_mask "$ip") if validate_ip "$ip"; then break else printf "Invalid IP address or subnet mask wider than /16. Please enter a valid IP address.\n" >&2 fi done vlans[$vlan_id]=$ip echo "VLAN ${IFACE}.${vlan_id} with IP $ip added" echo "========================" done # Recap echo "Here's the summary of what you're about to apply:" for id in "${!vlans[@]}"; do echo "Interface ${IFACE}.${id}, VLAN ID $id, IP ${vlans[$id]}" done echo "========================" # Preview the netplan file with new configurations echo "Preview of the netplan file with new configurations:" # Read the existing netplan file, excluding any existing VLAN sections if ! awk ' /^ vlans:/ {delete_block=1} /^[^ ]/ {delete_block=0} !delete_block' "$NETPLAN_FILE" > "${NETPLAN_FILE}.tmp"; then printf "Error reading netplan file.\n" >&2 exit 1 fi # Append the new VLAN configurations cat <> "${NETPLAN_FILE}.tmp" vlans: EOL for id in "${!vlans[@]}"; do cat <> "${NETPLAN_FILE}.tmp" ${IFACE}.${id}: id: ${id} link: ${IFACE} addresses: - ${vlans[$id]} EOL done cat "${NETPLAN_FILE}.tmp" echo "========================" # Confirmation read -p "Do you want to apply these settings? (yes/no): " confirm if [[ $confirm == "yes" ]]; then make_backup "$NETPLAN_FILE" mv "${NETPLAN_FILE}.tmp" "$NETPLAN_FILE" echo "Configurations have been written to $NETPLAN_FILE. Please review and apply with 'netplan apply'." else echo "Changes not applied." rm "${NETPLAN_FILE}.tmp" exit 0 fi echo "========================"